martedì 31 marzo 2020

TP-Link RE200 config.bin decryption and manipulation

A very quick article to share with you how to decrypt the TP-Link RE200 config.bin


In this article we take up the concepts seen in the previous one jumping straight into Ghidra to take a look at the _tddp_UploadFlashData routine in httpd ELF.


The way the config is being uploaded is pretty clear, basically the uploaded file is entirely decrypted, after which the md5 hashing is performed starting from the 0x10 offset until the end of the file. Finally, it verifies whether the first byte 0x10 coincide in this md5.
The encryption has been performed with a DES symmetric-key algorithm (ECB)

Demonstration:

Openssl can reach the goal by using this command:
# openssl enc -d -des-ecb -nopad -K 478DA50BF9E3D2CF -in config.bin > decrypted.bin

alternatively you can use any other application, demonslay335's CryptoTester for example:

 copy and paste the decrypted data into an hxd

Do a manually md5 check by selecting all the bytes from 0x10 to the end of the file.

You can now modify by a text editor the decrypted confing, retrive and or change the admin password, recalculate the new md5, encrypt the whole file back and upload it by the web interface. That's all. :)


Follow me on Twitter


Cheers,
RE-Solver







sabato 28 marzo 2020

TP-Link RE200 aka AC750: Unpack, repack, validate image by md5 hashing and upload YOUR OWN version!

This article demonstrates how "easy" may be build a potentially malicious firmware. 
This way should be valid for EVERY TP-Link firmware header version 1 (identified by the very first 4 bytes in the header, in little endian!)

A TP-Link RE200 is a widespread cheap Range Extender.
I love having root shell on my devices, so long story short:
I've started to decrypt RE200 config.bin (which I'll publish soon Edit: here!), to find a vector to inject code and get a root shell.
Unfortunatelly, for this time, the firmware is (not really, but enough) well written so I couldn't see any code injection possibilities from the browser and/or from the nvram config file and (almost) every stack smash chance are avoided by reimplemented TP-Link functions.

Ok, excluding a phisical attack, a custom firmware is the common route (among the same family devices) to get the shell.

Index:
0 - rcS script
1 - firmware header structure - httpd Analysis with Ghidra
2 - firmware customization and squashfs recompression
3 - firmware file reconstruction
  3.1 - Uncompress the image
  3.2 - Modify
  3.3 - Re-Compress the image
  3.4 - Put the things togheter
4 - Firmware mod new hash
5 - Upload and verify

0 - rcS script

Once unpacked the firmware by using binwalk ($ binwalk  -e firmware.bin ) the first thing to take a look at RunControlSingle user script (rcS).





Pretty clear,  TP-Link has commented the telnet row command, disabling the daemon.
In the end we'll see the httpd start command.

1 - firmware header structure - httpd Analysis with Ghidra

Let's start to examinate the firmware header in Ghidra. Our focus lands on upgradeFirmware(void *param_1,uint param_2)

I will try to be as brief as possible. Additional explainations requests in comments are welcome
1- In a similar way we seen in the config.bin [here], the file offset 0x4c contanins the md5 hash signature
2- int variable in 0x94 indicates if our firmware conains bootloader. If yes, the md5 signature uses a different salt.
3- md5_veryfy_digest. No explaination, this works in the same way as in the config.bin. Getting the md5  from the file in a variable, it replaces the same file address readen 0x4c with the 0x10 bytes with the right salt on point 2. It calculates the md5, and compare with the one originally readen.
4- Country code check @ 0x98 len=3chars: in case we'll change the firmware from a different country, we need to restore the same country code the device is factured with.

 md5key_withoutbootloader = DC D7 3A A5 C3 95 98 FB DD F9 E7 F4 0E AE 47 38
 md5key_withbootloader =      8C EF 33 5B D5 C5 CE FA A7 9C 28 DA B2 E9 0F 42

2 - firmware customization and squashfs recompression
We have now enough informations about the firmware header which allows us to grant writing on the device flash.
On the official TP-Link firmware, we have 2 headers, the first at 0x0 and a second one at 0x20200 (in this case). The first section contains the uboot, after the second header kernel + rootfs.

The second header contains the signature made from 0x20200 to EOF with the md5key_withoutbootloader salt
The first md5 signature is made with  md5key_withbootloader from 0x0 to EOF, (thus also including the second image)

As seen in httpd, we have 2 allowed kind of images: the first, is the whole image uboot+kernel+rootfs and the second way is to write just the kernel+rootfs which leaves the uboot uneffected (read: if I fail I can still de-brick by using a serial TTL :) )
That's why I've splitted the firmware.

3 - Firmware file reconstruction
 3.1 Uncompress the image
First of all, from the firmware, we're going to extract the squasfs file and uncompress by using unsquashfs:

Note: binwalk is an amazing swiss-knife, keep in mind the compression xz (LZMA2) and the inodes




By dd tool, squashfs has been extracted skipping, from the firmware file, the first 0x100000 (1048576 in decimal) bytes.
Next step was to uncompress the image with simply with # unsquashfs filename

 3.2 Modify
I've used nano to modify the rcS row number 33
from:
#telnetd -l /bin/login &
to
telnetd -l /bin/login &
Forgot to say: /etc/shadow file contains a different password then the one we use on the web.
Create your new /etc/shadow file!
The TP-Link credential hardcoded are root:shoadmin
(Thank you 6c2e6e2e ) <-wrong password here

(Thank you Openwrt)


3.3 Re-Compress the image
now recompress time with: mksquashfs squashfsdir/ fileout.squashfs -comp xz -no-duplicates
Those last two options are vital. The first indicates to mksquashfs to use LZMA2 algo(the same algo we know the stock firmware is using, showed by binwalk), the second one prevents mksquashfs to delete duplicates, guaranteeing the correct restoration of inodes and file number.

3.4 Put the things togheter 
Anyway the file size is reasonably different different. Anyway we can have a bigger (or smaller) image, anyway not bigger than 0x6C0000 calculated from my reduced (kernel+squashfs) stock firmware (EOF) 0x7C0000 - 0x100000 (initial squashfs magic number).
In the re200_imagecut.bin (
obtained in paragraph 2, see image) we overwrite into the file starting from 0x100000 our new squashfs image by keeping the SAME original file size, if needed padding the file adding or removing 0xFF up to 0x7C0000-1




4 - Firmware mod new hash
We have now recreated the right file structure. The last step is to rewrite the new md5 at 0x4c-0x5c.
In my case, bootloaderless, my key will be md5key_withoutbootloader:


By keeping in mind what we read at the paragraph n.2, once replaced the md5 you'll have the new md5 (see the picture at the bottom) wich we will use to replace the salt (in red) from 0x4c to 0x5c.

5 - Upload and verify

Let's upload and try to login with Putty.....
BOOM .... it worked like a charm on the first try!!! 😎


Modified firmware image here.
(no uboot, telnet enabled: default telnet credentials root:sohoadmin)

Cheers,
RE-Solver


giovedì 26 marzo 2020

Tp-Link CPE-510/520 "new" Config.bin structure: Decryption, modify, re-encryption



So far, seems nobody has yet relased a tool to decrypt such kind of config structure.
By doing only static analysis we'll take a look how to figure out the new TP-Link CPE-510/520  (probably also TP-Link CPE-210/2200 and others) config.bin structure by using Ghidra.
I neither have the CPE :)



Index:
0 - Hardware overview and firmware extracting
1 - uclited ELF static analysis with Ghidra
  1.1 - config.bin file structure
  1.2 - Extracting decryption key
  1.3 - TP-Link MD5 config signature tricky calculation
2 - config.bin decryption script
3 - Re-creation of a new modified config.bin
4 - Login md5 trick



0 - Hardware overview and firmware extracting

OpenWrt wiki provide us many hardware details:
CPE-510 is based on tipically mips_24kc instruction set, the bootloader is not the well known Uboot, because TP-Link has used their SafeLoader. This will be important later.

Let's download the TP-Link CPE-510 rev 3.0 firmware and examine it with binwalk:


We're interested in the squashfs partition, so let's quickly extract the image by using -e paramenter on binwalk and take a look on what the router once turned on by looking at the rcS script:
Before the httpd, a lower software surface, uclited , is executed.

1 - uclited ELF static analysis with Ghidra

I'm not a Ghidra big fan, but sometimes it's powerfull, expecially when I have a missing decompiler on IDA Pro. lol.
So, load the ELF on Ghidra and start having fun!


1.1 - config.bin file structure
Before proceeding and examining in ghidra we have to take a look on how the encrypted config.bin looks like:
In the file header there are just a few words in plaintext and at 0x94 (keep it in mind) we have undeadable informations. From my experience, this may be where the encrypted stuff starts.

1.2 - Extracting decryption key

There are several approaches to finding the routine we are interested in.
I'll skip how to find the routine (it's too long to write here), so go straight at the routine labled as
usrconf_load @ 0x004272d0 which is the decryption config.bin routine.




The routine is almost self explanatory, anyway let's go over the highlights copared to the config.bin hex:

In the image above:
From 0x0 to 0x3 bytes are the file size. (4 bytes)
Next 0x10 bytes are the MD5 file hash. (0x10 bytes)
From 0x4 to 0x94 are the file header (device info, rev info, and other things). (0x90 bytes)
From 0x94 to EOF is the DES Encrypted data




The DES - ECB  routine  des_min_do(__src + 0x90,size - 0x90,__ptr,0x20000,(const_DES_cblock *)desConfigKey,0); act an encrytion with last paramenter as int 1 or decryption if set 0.

desConfigKey is the pointer to the key: 47 8d a5 0b f9 e3 d2 cf 
We can assume "__src + 0x90"  as our file pointer which is moved 4 bytes forward (the bytes of the file size at the beginning of the file)

We have now all the informations we need to decrypt the file.

1.3 - TP-Link MD5 config signature tricky calculation 
 





In the previous paragraph I deliberately highlighted the MD5 in blue for a specific reason, I do not understand why, but TP-Link do a particular thing in the calculation of the MD5 which will be:
Understanding those steps are esential to recreate the modified file:
1 step: the routine saves the 0x10 bytes readen from file offset 0x4 to 0x14. This is the final md5 that will be compared
2 step: the routine replaces 0x10 bytes with "47 8d a5 0b f9 e3 d2 cf 88 19 83 9d 4c 06 14 45"
3rd step: the routine calculates the md5 from 0x4 to EOF with the first 0x10 bytes shortly before replaced
4 step: the md5 result is compared to the one readen in the original file (saved during the step 1)

2 - config.bin decryption script



dd bs=1 skip=148 if=config.bin of=config_cut.bin 
openssl enc -d -des-ecb -nopad -K 478DA50BF9E3D2CF -in config_cut.bin >compressed.bin 
zlib-flate -uncompress  config.json
 
where 148=0x94 do you remember?... 
the config.json contains all the router informations including the login ones.


3 - Re-creation of a new modified config.bin

You can do it by yourself. Having all the informations you need, you can just recompress the modified .json, encrypt it again with openss, calculate back the new md5 as seen in the 1.3 paragraph and add the current file size + 0x4 and replace the first 4 bytes with the calculated value.

4 - Login md5 trick 
 If you forgot your router login password, in the config you'll have no plaintext password but the md5(password).
Do you need to brute the plaintext password which generates the corresponding MD5?

Considering that the browser, in local javascript, calculates and send the MD5 to the router, you dont need to waste your time.
A firefox Web console is enough to inject the md5 and get the login.



Cheers,

RE-Solver