Image of Modern Operating Systems (3rd Edition)
Image of Beginning Google Maps API 3
Image of Advanced Programming in the UNIX Environment, Second Edition (Addison-Wesley Professional Computing Series)
Image of Android Wireless Application Development

Decrypt PROLiNK ADSL Modem Configuration File To Reveal Backdoor

I was recently asked by a friend to examine the settings on a PROLiNK ADSL2 router modem, model PRS1241B, to see if the performance of the modem could be improved as he was having trouble using it for video conferencing. PROLiNK is a brand of Fida International (S) Pte Ltd, a Singapore-based company founded in 1991, that produces a wide range of consumer technology products including a range of ADSL modems and routers.

As usual, I wished to make a backup of the current user-configurable settings before modifying any user configurable settings. PROLiNK makes this an easy task to accomplish via their simple and cleanly implemented web interface shown below.

The downloaded configuration file was saved as MAC.cfg with MAC being the fixed 48-bit Media Access Control address. For the purposes of this blog post, in order to protect the owner of this modem, I am using a dummy MAC address; henceforth the configuration file is named 93610D31D283.cfg

Once I realized that the configuration file was encrypted or obfuscated in some manner, my curiosity was aroused. Why did the vendor not simply produce a plaintext configuration file? The only reasonable answer was that the vendor wanted to hide some information from users, so naturally I decided to decrypt the file!

I opened the file in my 010 hex editor and looked for patterns in the encrypted bytes. None were immediately visible other than the fact that the file mostly contained extended ASCII values. I then used the builtin unsigned byte histogram tool as shown below:

Frequency analysis is a useful way to detect the weak encryption such as a substitution cipher. The histogram simply shows the frequency of all the bytes found in the encrypted file. From looking at the generated histogram it was readily apparent that more than likely some sort of XOR cipher scheme was being used.

The next step was to confirm that an XOR cipher was actually being used. To do that, I changed (perturbed) the password of the admin user. There is a trick to doing this – ensure that the length of the password is not changed and, if possible, change the password to all the same digits or letters, e.g. “111111” or “aaaaaa”.

I then saved another copy of the configuration file and, using the 010 Hex Editor, compared the two binaries using it’s builtin file comparison tool:

A few minutes with a programmers calculator confirmed that an XOR cipher was indeed being used but with a key length greater than the password string I had entered.

To find out more about the configuration file format and possibly uncover the full cipher key, I changed the admin password from “1111111” to “11111111111111111111111111” which was the longest password accepted by the change password webpage and saved a new configuration file which I then compared with the last saved configuration file as shown below:

Again a few minutes with a pen, paper and programmers calculator confirmed that the cipher key did not repeat and this meant that the XOR cipher key was longer than 28 bytes. Interestingly, one of the XOR cipher key values was a NULL. This means that the corresponding bytes in the ciphertext and the plaintext have the same values.

Looking at the large number of differences in the two configuration files as a result of simply changing the length of the admin password strongly suggested to me that the configuration file was in some sort of structured text format such as XML or JSON and that a very long XOR cipher key was used.

It was now time to try and guess the XOR cipher key. I knew 28 values of the key from perturbing the admin password. I did not known the actual length of the key but assumed that is was shorter than the plaintext, i.e. basically a form of a Vigenère cipher, and thus any of the standard techniques to break Vigenère should break the encryption.

There are a number of tools out there than can be used to try and brute force discover an XOR cipher. The best tool I have come across to date is Alexey Hellman’s xortool which is written for Python 2.

Why the SHELL=none syntax? Unfortunately the xortool tool produces colorized output – which I dislike – and there is no command line option to disable colorized output. However, looking at the source code, I noticed that colorization is dependent on detecting that the SHELL environmental variable is set to bash. By temporarily setting this variable to none, colorization is disabled and I get the output I desire.

By trial and error, I varied the key size (-l option) and the most common byte (-c option), examining the generated output each time, until I ran the following command and got a seriously large number of reasonable plaintext outputs.

$ xortool 90610C31D6B0.cfg  -l 256  -c 22

In fact, 32767 output files were generated. Here is the first few lines of the output file named 32767.outs.

<v N="CO\FIG_COMPANK" V=""></v>
HV N="CONF=G_C]\TACT" V=""/>
<V N= CONTIU_^OQATION" V=""></v>
<v N="CONFI+_PA'SWORD" V=""></v>
<v N="DOS_STATUS" V="0x0"/,
<v \="SRCIP_F8OOD_FIN_T<REH]^D" V="0x64"></v>
<v N="ARCIP_FLOOD_UDP_THREH]LD" V="0g64"></v>
<v N="SRCIP]FLO;D_ICMP]THRWH]LV"2V="0x64"></v>
<v N="IP_B8OCK_TIME""V=""x1 c"></v>~PV N="WLAN_MAC_ADDR" V="000b2b000001"/>
<v N="WLAN_RT_TYPE" V=""xa"></v>
<v :="WLAN_AN _DIDWRSITY" V="0x0"></v>
<v \="WLAN_TX_ANT" V="0x""></v>
<v N""WLAN_LED_TYPE" V?"0xC"></v>
< " N="WLAN_AHANMNU_" V=V\x0"/>

Here is a copy of the cipher key that generated the above plaintext:


I have broken it down into a number of lines for legibility.

Thanks to xortool, I now had some reasonable plaintext and a 256 byte XOR cipher to work with. I could be reasonably certain that the plaintext configuration file is in quasi-XML format and that the XOR cipher key is 256 bytes in length.

Not perfect but with sufficient correct plaintext that it was possible to deduce the correct characters for the first 256 bytes of plaintext and hence the corresponding byte in the cipher key. Yes, I had some hours of work ahead of me using paper, pen and programmers calculator but the problem was no longer intractable.

The task ahead of me was to convert the 256 byte cipher key string generated by xortool into a binary key file, and write a short Python script to use the key file to decrypt the encrypted configuration file. By comparing the plaintext generated by the Python script with the expected plaintext for the first 256 bytes of the configuration file, and adjusting the key file byte by byte to generate the expected plaintext, I was able to deduce the correct 256 byte XOR cipher key in about 4 hours.

Here is the Bash script I used to convert the raw cipher key shown above in a binary keyfile:


if [ -f keyfile ]
   rm -f keyfile

cat infile | tr "\\\x" " " | tr -s " " | cut -c 2- | tr " " "\n" |
while read key
    echo -n "${key} "
    echo -ne \\x${key} >> keyfile

exit 0

Here is my simple Python script:


Simple Python 2 script to test the accuracy of the 256-byte XOR key

def xor(input, key):
    l = len(key)
    j = len(input)
    return bytearray((
        (input[i] ^ key[i % l]) for i in range(0, j)

input = bytearray(open("93610D31D283.cfg", "r").read())

key = bytearray(open("keyfile","rb").read())

output = xor(input, key)

open("outfile.txt", "wb").write(output)

Here is the 256-byte XOR cipher key that generated perfect plaintext:

$  xxd key
0000000: 818c 8d80 9b9d 909c a5a9 ada0 b8a9 f5b8  ................
0000010: b5b8 b8d0 c0c5 c4a2 cdcc c5ca d4db e9dc  ................
0000020: d3de acd8 ebe7 9daa e9ff fbfa e0ef 9e94  ................
0000030: e1e1 8da9 fdfe f58a 8587 be8c 008e 8af8  ................
0000040: 008a e4c9 8885 c780 8484 8784 9af6 f0a8  ................
0000050: 9598 9380 a1bc f9a4 af96 a9a3 ad81 efe7  ................
0000060: ddb9 f6d2 d6d1 8bd8 c6f0 c8c4 c9b6 c188  ................
0000070: b5b4 b1be baf9 abb8 b3b0 d5b0 00a8 c5a1  ................
0000080: d2ec ceff e5e8 c990 e3ae a5ea 8b8a d5a8  ................
0000090: bfda c8a2 a2f9 e4fc b4b5 b7b5 a1ad abaf  ................
00000a0: e5d4 e1e5 e0aa eb93 e3c6 cda0 84a3 df94  ................
00000b0: aaae e3e0 a58e dc8b 99f4 90cf 90a6 b4b8  ................
00000c0: c4d6 97f6 c4cc c4b1 cec2 f287 d6d2 ca9c  ................
00000d0: d186 80de 00d1 fdb4 b0be d8b2 b0c9 c9c2  ................
00000e0: 00f0 acfe ea8f 8ebd d191 85c0 a2bd f1fc  ................
00000f0: ac85 9fd8 fce3 c8a8 8c94 94b6 98cd 95a6  ................

You will see that there are 3 nulls in the key as predicted by me earlier in this post upon examination of the histogram for the encrypted configuration file.

Here is the plaintext corresponding to the example xortool output shown earlier in this post.

<v N="CONFIG_COMPANY" V=""></v>
<v N="CONFIG_CONTACT" V=""></v>
<v N="CONFIG_WELCOME" V=""></v>
<v N="CONFIG_LOCATION" V=""></v>
<v N="CONFIG_NAME" V="ADSL"></v>
<v N="CONFIG_STATION" V=""></v>
<v N="CONFIG_PASSWORD" V=""></v>
<v N="DOS_STATUS" V="0x0"></v>
<v N="IP_BLOCK_TIME" V="0x12c"></v>
<v N="WLAN_MAC_ADDR" V="000b2b000001"></v>
<v N="WLAN_REG_DOMAIN" V="0x1"></v>
<v N="WLAN_RF_TYPE" V="0xa"></v>
<v N="WLAN_ANT_DIVERSITY" V="0x0"></v>
<v N="WLAN_TX_ANT" V="0x0"></v>
<v N="WLAN_LED_TYPE" V="0x7"></v>
<v N="WLAN_CHAN_NUM" V="0x0"></v>

Not particularly elegant or efficient XML but it works!

There are a number of interesting user accounts visible in the plaintext configuration file. For example, this special password for the admin account gives you God-mode if you telnet or ssh to the modem.

   <V N="FLAG" V="0x0"/>
   <V N="USERNAME" V="admin"/>
   <V N="PASSWORD" V="0010airocon"/>
   <V N="BACKDOOR" V="0x1"/>
   <V N="PRIORITY" V="0x1"/>

This is the menu you see if you telnet or ssh to the modem using Putty or a similar utility:

If you are logged in as admin, you are just a regular user. If you are logged in with a root account, you still do not get elevated privileges. See the error message displayed above, when a root account tried to run the config option.

Only when you are logged in with an account with the backdoor flagged as 1 do you get elevated (full) privileges as shown below:

Note that different passwords can be used with the same username, e.g. admin, to enter different privilege levels, i.e. normal or elevated.

Once you get elevated privileges, a plethora of additional options and commands become available to you as shown in the following screenshots.

I am not sure what the underlying operating system is as I do not have the time at present to explore all the options fully. However I am fairly certain it is not based on a Linux kernel. It does however vaguely remind me of very early versions of Cisco IOS. For example,no is used to negate a command or option. I will point out that command line editing is minimal and it is easy to lock up the OS requiring a reboot of the modem. Command history is supported; command completion is not.

Interesting the prompt for the top level debug option is [doic]$. I am not sure of the meaning of doic.

Some commands worth exploring from the ADSL shell include show command, show web, and configuration. The xfile command allows you to manipulate files as shown below:

Have a look at the system processes to get an idea of the range of servers which are enabled by default:

I am not going to provide a full printout of the unencrypted configuration file that I generated as this would reveal a lot of other interesting default features, accounts and passwords. Put in the work yourself if you want this information; I have demonstrated to you how to generate the plaintext. I will tell you that there are 1530 lines in the plaintext OOTB (out of the box) configuration file.

By the way, there are a lot of options that cannot be configured via the web interface and can only be configured via a uploaded configuration file.


1 comment to Decrypt PROLiNK ADSL2 Modem Configuration File To Reveal Backdoor

Leave a Reply