Exploring Linksys WRT120N Firmware Obfuscation

Original author: Craig
  • Transfer
Recently, my attention was drawn to the fact that in the firmware updates for Linksys WRT120N they use some kind of obfuscation. It seemed to me that it would be interesting to rummage through it, and I decided to take a look.

The latest firmware version does not look like firmware that you can work with right away.
image

As you can see, there is a small block of data compressed by LZMA - these are just HTML files for the router’s web interface. Most of the firmware consists of some strange, random data. Because I can’t do anything else with her, and my curiosity was trying to overcome me more and more, I bought this model of a router for myself (how they inflated the Amazon Prime cost!).

Iron analysis

At the first glance at the hardware, it became clear that the WRT120N runs on the Atheros AR7240 SoC, has 2MB SPI flash, 32MB RAM and something similar to Serial and JTAG wiring: In order to take a deeper look at the boot process, I decided to start with serial port. I have already talked about serial ports, so I will not focus on the methods of finding pins and speed in this article. It was easy to find the port pins using a multimeter and a visual inspection of the board:
image


image


    Pin 2 – RX
    Pin 3 – TX
    Pin 5 – Ground

The port runs at 115200 baud and provides interesting boot information:
$ sudo miniterm.py /dev/ttyUSB0 115200
--- Miniterm on /dev/ttyUSB0: 115200,8,N,1 ---
--- Quit: Ctrl+]  |  Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
=======================================================================
Wireless Router WG7005G11-LF-88 Loader v0.03 build Feb  5 2009 15:59:08
                    Arcadyan Technology Corporation
=======================================================================
flash MX25L1605D found.
Copying boot params.....DONE
Press Space Bar 3 times to enter command mode ...
Flash Checking  Passed.
Unzipping firmware at 0x80002000 ... [ZIP 3] [ZIP 1]  done
In c_entry() function ...
install_exception 
install exception handler ...
install interrupt handler ...
ulVal: 0x484fb
Set GPIO #11 to OUTPUT
Set GPIO #1 to OUTPUT
Set GPIO #0 to OUTPUT
Set GPIO #6 to INPUT
Set GPIO #12 to INPUT
Timer 0 is requested
##### _ftext      = 0x80002000
##### _fdata      = 0x80447420
##### __bss_start = 0x804D5B04
##### end         = 0x81869518
##### Backup Data from 0x80447420 to 0x81871518~0x818FFBFC len 583396
##### Backup Data completed
##### Backup Data verified
[INIT] HardwareStartup ..
[INIT] System Log Pool startup ...
[INIT] MTinitialize ..
CPU Clock 350000000 Hz
init_US_counter : time1 = 270713 , time2 = 40272580, diff 40001867
US_counter = 70
 cnt1 41254774 cnt2 41256561, diff 1787
Runtime code version: v1.0.04
System startup...
[INIT] Memory COLOR 0, 1600000 bytes ..
[INIT] Memory COLOR 1, 1048576 bytes ..
[INIT] Memory COLOR 2, 2089200 bytes ..
[INIT] tcpip_startup ..
Data size: 1248266
e89754967e337d9f35e8290e231c9f92
Set flash memory layout to Boot Parameters found !!!
Bootcode version: v0.03
Serial number: JUT00L602233
Hardware version: 01A
...


It seems that the firmware was made by Arcadyan , the message 'Unzipping firmware ...' was especially interesting, a quick google led me to a post about de-flashing firmware from Arcadyan, but it seems that a slightly different method is used.

Through the serial port, you can only use the bootloader menu. During loading, you can climb into it by pressing the space bar three times and perform some actions, such as clearing the flash and setting the board settings:
Press Space Bar 3 times to enter command mode ...123
Yes, Enter command mode ...
[WG7005G11-LF-88 Boot]:?
======================
 [U] Upload to Flash  
 [E] Erase Flash      
 [G] Run Runtime Code 
 [A] Set MAC Address 
 [#] Set Serial Number 
 [V] Set Board Version 
 [H] Set Options 
 [P] Print Boot Params 
 [I] Load ART From TFTP 
 [1] Set SKU Number 
 [2] Set PIN Number  
======================


Unfortunately, the bootloader did not allow dumping the contents of RAM or flash. Although there is a JTAG wiring on the board, I decided to dump the flash directly, because The JTAG dump process is usually not fast, and the SPI connection is very simple.

Probably any device that supports the SPI protocol can read flash. I used the FTDI C232HM cable and the spiflash.py program from libmpsse
$ sudo spiflash --read=flash.bin --size=$((0x200000)) --verify
FT232H Future Technology Devices International, Ltd initialized at 15000000 hertz
Reading 2097152 bytes starting at address 0x0...saved to flash.bin.
Verifying...success.

A flash consists of three LZMA blocks and a small amount of MIPS code, but the firmware itself is still not good:
image

The first two LZMA blocks are part of the recovery image, and the MIPS code is the bootloader itself. The rest of the space is occupied by the obfuscated firmware file, except for zeros and some data at the end.

Bootloader analysis

The bootloader, in addition to decrypting the firmware and loading it at an address in memory, contains some interesting things. I will miss boring things, like I was looking for the boot address of the bootloader, manually determined the functions of the standard C library, found the offset table of JUMPs, etc., and right away I will turn to interesting.

First, in the early boot phase, the bootloader checks to see if the reset button is pressed. If it is clicked, it downloads the “Tiny_ETCPIP_Kernel” image - a small recovery image with a web interface.
image

It's a good news. Now we know that if something goes wrong during the firmware update process, we can press reset and revive the device.
And there is also a hidden admin mode in the bootloader menu:
image

Pressing "!" will lead to the inclusion of administrator mode, which unlocks some options, including reading and writing to memory.

[WG7005G11-LF-88 Boot]:!
Enter Administrator Mode !
======================
 [U] Upload to Flash  
 [E] Erase Flash      
 [G] Run Runtime Code 
 [M] Upload to Memory 
 [R] Read from Memory 
 [W] Write to Memory  
 [Y] Go to Memory     
 [A] Set MAC Address 
 [#] Set Serial Number 
 [V] Set Board Version 
 [H] Set Options 
 [P] Print Boot Params 
 [I] Load ART From TFTP 
 [1] Set SKU Number 
 [2] Set PIN Number  
======================
[WG7005G11-LF-88 Boot]:

The most interesting part of the bootloader, of course, is the one that loads the obfuscated firmware into memory.

Obfuscation Analysis


Deobfuscation is performed in the load_os function, which passes a pointer to the obfuscated image and the address where the unpacked image should be placed:
image
Unpacking itself is not very complicated: In general, if the firmware starts from 04 01 09 20 (and ours starts with these bytes), then the decryption algorithm is executed, which:
image


  • Rearranges two 32-byte data blocks at 0 × 04 and 0 × 68 addresses
  • Swaps 4 bits for the first 32 bytes, starting at 0 × 04
  • Rearrange byte bytes 32 bytes starting at 0 × 04

After all this, the data at 0 × 04 contains the correct LZMA header, which is then expanded.

It was easy to implement the deobfuscation utility, and the WRT120N firmware can now be unpacked and unzipped.
$ ./wrt120n ./firmware/FW_WRT120N_1.0.07.002_US.bin ./deobfuscated.bin
Doing block swap...
Doing nibble-swap...
Doing byte-swap...
Saving data to ./deobfuscated.bin...
Done!

image
Analysis of unpacked, but not uncompressed firmware

If anyone is interested, you can download the utility for unpacking .

Also popular now: