Decrypting config.bin files for TP-Link WR841N, WA855RE, and probably more…

Notice - moved from medium.com, as their pricing model is just plain wrong... 
This is also hosted here, but updated below.

Tl;Dr — it’s basically the same as it always was, except they added a compression step. YOLO. These devices are still Amazon’s ‘Choice’ when you search for ‘router’ to buy, so they’re pretty popular.
If you want to read a config file from one of these (or similar) devices, just use the following script:
# First strip the header:
dd bs=1 skip=144 if=config.bin of=config1.bin 
# Now decrypt the file - same key as before!
openssl enc -d -des-ecb -nopad -K 478DA50BF9E3D2CF -in config1.bin >tmp.bin 
# However you also need to decompress it with zlib:
zlib-flate -uncompress <tmp.bin >config.json 
The contents of the config.json file is now the plaintext JSON config data for your router. Woo! :-D
What data can you get? WiFi Keys, MD5 of the admin password, WEP key, IP ranges in use, and a few other artefacts.

How did I get this?

Easy really — 10mins with Ghidra and you’re done, really…
So, quite a few people are aware of this post: http://teknoraver.net/software/hacks/tplink/ - This post by Matteo Croce (a senior developer at red hat) is a lovely example of ‘how not to do it’ against TP-Link — and clearly they were listening! This technique doesn’t work any more because of the extra decompression stage. But other than that, you’ll notice that my command in openssl is just the one from Matteo’s post with a dash of post-processing… So let’s dig into some details.
The structure of the file is as follows:


The red box is an MD5 hash that I won’t cover how it’s generated here (the code is pretty self explanatory, but you don’t need it to read the config).
The Orange box is just version data — some data about the firmware and then the hardware revision (“TL-WA855RE v3.0" is the hardware version of the repeater AND the routers… they are actually the same hardware… ) , and then the blue box is the encrypted data. This is what we are after, so use the dd command to extract the little pearl of encrypted glory.

DES decrypt and then uncompress — Ghidra decompliation

Now, the Ghidra decompiler is fairly nifty, and the above image is taken from its decompilation of the uclited binary found on these devices. This is the binary responsible for generating and reading the config.bin files after they have been uploaded, as well as a plethora of other functions.
This extract is taken from the function loadConfigToFlash() . This function is called after the file has been uploaded (it gets put in /tmp/httpUploadFile.bin for the curious) and is passed the file contents and length as parameters.
After some initial checks, we get to the above code path, whereupon we decrypt with des_min_do , and then use uncompress to recover the data. The keen eyed amongst you will notice that des_min_do is the same as in Matteo’s writeup! This is encouraging… and that memory reference for the key? Well, it’s this…

The DES Key in disassembly

…aaaaand yes, this is the same key, 0x478DA50BF9E3D2CF , as found before by Matteo. Awesome. So, we can use Matteo’s openssl command but we get garbled looking data — as we now know, this is just compressed.
So what compression is used? Well, running file on the output indicated it was zlib (easier to do that than RevEng the whole uncompress() function from scratch… I’m a laaaazzzyyy hacker X-P ), so using the zlib-flate as in the script above worked a charm.

So, wait… is it broken again?

Well, kinda. That starting MD5 is the challenge if you wanted to upload a malicious one. They go through a sequence of steps to generate that MD5, as it requires a config verification key… I mean, that key may or may not be 478da50bf9e3d2cf8819839d4c061445, but I really couldn’t tell you, tbh.
Suppose you get ahold of one of these config.bin files, you can get out the WiFi key, WEP code, as well as the MD5 of the admin password — so, I wouldn’t leave these files hanging around. All of the cryptographic artefacts in use are hard coded, and none of them are device specific — meaning that anyone with access to these files can get the data out.
Did they fix what Matteo found? Not a bit of it. They just added some compression and hoped that would be enough…
Spoiler alert — it wasn’t. ;)
Happy hacking!

Comments

Popular posts from this blog

Result about Aperiodic Tilings for Finite Sets of Prototiles - and MathJax test