Recently I got my hands on both “smart” routers from Vodafone PT, the Huawei HG8247Q and the Huawei HS8247W. Once I had access to the file system, either by making a flash dump of the router or exploiting the web application, I started browsing through the files and quickly found encrypted configuration files of the router.
The Huawei HG8247Q router used by Vodafone PT
Fortunately, someone has already reversed the encryption method and the key utilized in it[1]. But in case you are too lazy to check it out for yourself, it essentially compresses the data and encrypts it with the key “13395537D2730554A176799F6D56A239”. This was likely discovered by reversing the tool Huawei provides in it’s router named “aescrypt2”.
Encrypted passwords
During the first couple ONTs and routers of Huawei, the passwords in the configuration file were stored in cleartext, they obviously realised this was not enough and started hashing some of them. The problem with this approach is that some services still required the cleartext version of the password, this was “mitigated” in their latest routers by encrypting password fields like so:
1
2
3
4
5
6
<WEPKey NumberOfInstances="4">
<WEPKeyInstance InstanceID="1" WEPKey="$2E{]>L8HXOKCG(I1m313#pLsF"D[NI=\hxIWS0+nG$" />
<WEPKeyInstance InstanceID="2" WEPKey="$2y"zK$H"#x+MacLV>=9iU"%7KB0tv"954@;T&I2Y/$" />
<WEPKeyInstance InstanceID="3" WEPKey="$2P+=+Z#qe12zNXhV1daK(R=`>@|UsAJ"JtYAld6|,$" />
<WEPKeyInstance InstanceID="4" WEPKey="$2`GbQ!8LcrRO]NcXU>)iA0UdK<i^&hE{JkJ~f.id0$" />
</WEPKey>
The hunt
Know that these strings must be encrypted somewhere within the dumped firmware the for this code began. We started by trying to find a password field that did not look “too vulgar” to reduce the potential number of false positives in our initial search, which resulted in the us choosing the field “FtpPassword”. Search for this string in firmware resulted in a couple of files.
1
2
3
4
5
6
7
8
9
$ grep -r / -e "FtpPassword"
Binary file /etc/app/usb_ftp_app/cfg/CommView_tr098.bin matches
Binary file /etc/app/usb_ftp_app/cfg/hw_ttree.bin matches
/etc/wap/customize/recover_comteco.sh: cfgtool add $var_default_ctree_var $var_node_app_srvmng FtpPassword C1o3m6t6e7c3o
/etc/wap/dm.cfg/DataView_tr181_oi2.xml:
/etc/wap/hw_aes_tree.xml:
Binary file /etc/wap/tr181_view/DataView_tr181_telmex.bin matches
Binary file /lib/libhw_base_ssmp_appm_intf.so matches
/var/UnzipedC.xml:
Out of these files hw_aes_tree.xml proved to be the most interesting, it looked like an XML file indicating all the fields that were meant to be encrypted. To find where this file was used we performed a similar search to the previous one, this yielded in a couple of binaries, that all linked to /lib/libhw_ssp_basic.so, which is the binary that provides almost all functionalities to the remaining binaries. From the binaries that used the .xml file we discovered that the function HW_XML_DBEncryptInitProc is the entry point for decrypting the parameters we want, at this point we can just throw the library into any disassembler and and we can the function that decrypts each node:
1
2
3
4
5
6
7
8
9
10
11
12
13
//HW_XML_DBEncryptInitProc
j_HW_XML_DBEncryptNodeForEach(xml, v8, memType, HW_XML_DBEncryptInitForEach);
//HW_XML_DBEncryptInitForEach
if (sEncryptedStr[1] == '2'){
sDecryptionKey = "Df7!ui%s9(lmV1L8"
r4 = HW_OS_AESCBCDecrypt(sEncryptedStr, HW_OS_StrLen(sEncryptedStr), pOutputBuffer, u32OutputBufferLength, sDecryptionKey, HW_OS_StrLen(sDecryptionKey));
} else {
fd = HW_OS_Open("/var/aes_encrypt_1");
if(fd >= 0)
HW_OS_Close(fd);
r4 = HW_OS_AESDecrypt(sEncryptedStr, HW_OS_StrLen(sEncryptedStr), pOutputBuffer, u32OutputBufferLength)
}
We can see that there are two variants for encrypt the node depending on the second character of the encoded node, in our case all the nodes had a ‘2’ in their string so obviously that’s the path we followed. If you are curious about the second path, it utilizes AES in ECB mode rather than CBC and derives a key from a byte array in the binary.
As the name implies, the function HW_OS_AESCBCDecrypt, decodes and decrypts the provided string, and can be summarized in 8 steps:
- Remove the prefix “$2” and suffix “$” from the string
- Decode the data to binary through the function HW_AES_AscUnvisible
- Grab the last 0x14 bytes, reduce it to 0x10 through the function HW_AES_PlainToBin and use the result as the IV for the decryption
- Derive key K from a byte array in the application and the input “Df7!ui%s9(lmV1L8” which is the result of sha256(“9jK0lk5kLmxn8sjojW962llHY76xAc2zDf7!ui%s9(lmV1L8”)
- Grab 0x14 bytes from the beginning of the buffer and reduce it to 0x10
- Decrypt the data
- Set the IV to the current cyphertext
- Go to 5 while there is data remaining
Password modes
Besides password encryption, Huawei routers also feature multiple ways of storing the password. The first two modes are already well known by the community[3] but in more recent routers a new mode emerged, which appears to be unknown to most.
Like before we started our search by searching for “PassMode” in the file system and we see can the binary /bin/ssmp
with the function HW_SSP_IsMatchUser which contains the following code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
switch ( ctx->m_pEncryptMode)
{
case 0:
return HW_OS_StrCmp(raw_input, ctx->m_pPassword) != 0;
case 1:
result = HW_OS_MD5(raw_input, &intermediate_step);
if ( !result )
result = HW_OS_StrCmp(&intermediate_step, v5 + 32) != 0;
return result;
case 2:
result = HW_OS_MD5(raw_input, &intermediate_step);
if ( result )
return result;
HW_SHA256_CAL(&intermediate_step, &output);
break;
case 3:
HW_XML_GetOrSetSaltValue(v3, &salt, saltLen, 0, 0);
HW_OS_PBKDF2_SHA256(raw_input, HW_OS_StrLen(raw_input), &salt, saltLen - 1, 5000, &output, 64);
break;
}
In summary we have these three modes, in addition to no hashing at all:
Existing modes:
- MD5(password)
- SHA256(MD5(password))
- PBKDF2(password, 256 key size, 5000 iterations, salt) the salt is ascii string of length 24
Tools
I have created a simple website where you can hash, cipher and decipher your passwords generated by an Huawei router. The source code can be found here