Field Value Seed: 000000000000 Last MAC Octet: 00



In my case the magic command was "ATEN1,508fad63" and this is what "ATHE" produced afterwards: In my case the magic command was "ATEN1,508fad63" and this is what "ATHE" produced afterwards:

======= Debug Command Listing ======= AT just answer OK ATHE print help ATBAx change baudrate. 1:38.4k, 2:19.2k, 3:9.6k 4:57.6k 5:115.2k ATENx,(y) set BootExtension Debug Flag (y=password) ATSE show the seed of password generator ATTI(h,m,s) change system time to hour:min:sec or show current time ATDA(y,m,d) change system date to year/month/day or show current date ATDS dump RAS stack ATDT dump Boot Module Common Area ATDUx,y dump memory contents from address x for length y ATWBx,y write address x with 8-bit value y ATWWx,y write address x with 16-bit value y ATWLx,y write address x with 32-bit value y ATRBx display the 8-bit value of address x ATRWx display the 16-bit value of address x ATRLx display the 32-bit value of address x ATGO(x) run program at addr x or boot router ATGR boot router ATGT run Hardware Test Program AT%Tx Enable Hardware Test Program at boot up ATBTx block0 write enable (1=enable, other=disable) ATRTw,x,y(,z) RAM test level w, from address x to y (z iterations) ATWEa(,b,c,d) write MAC addr, Country code, EngDbgFlag, FeatureBit to flash ROM ATCUx write Country code to flash ROM ATCB copy from FLASH ROM to working buffer ATCL clear working buffer ATSB save working buffer to FLASH ROM ATBU dump manufacturer related data in working buffer ATSH dump manufacturer related data in ROM ATWMx set low 6 digits MAC address in working buffer ATMHx set hight 6 digits MAC address in working buffer ATBS show the bootbase seed of password generator ATLBx xmodem upload bootbase,x is password ATSMx set 6 digits MAC address in working buffer ATCOx set country code in working buffer ATFLx set EngDebugFlag in working buffer ATSTx set ROMRAS address in working buffer ATSYx set system type in working buffer ATVDx set vendor name in working buffer ATPNx set product name in working buffer ATFEx,y,... set feature bits in working buffer ATMP check & dump memMapTab ATDOx,y download from address x for length y to PC via XMODEM ATTD download router configuration to PC via XMODEM ATUPx,y upload to RAM address x for length y from PC via XMODEM ATUR upload router firmware to flash ROM ATDC hardware version check disable during uploading firmware ATLC upload router configuration file to flash ROM ATUXx(,y) xmodem upload from flash block x to y ATERx,y erase flash rom from block x to y ATWFx,y,z copy data from addr x to flash addr y, length z ATXSx xmodem select: x=0: CRC mode(default); x=1: checksum mode ATLD Upload Configuration File and Default ROM File to Flash ATBR Reset to default Romfile ATCD Convert Running ROM File to Default ROM File into Flash

Now we have access to few other interesting commands. Remember the objective is to patch the ROM-0 download vulnerability.

Patching the vulnerability (virtually)

In order to patch the vulnerability we need to patch the stage2 firmware (we are still on the stage1 level - minimal boot firmware). You can go to the stage2 firmware by typing ATGR (boot router) command. The bad thing about that is after this step we will have no access to stage 1 commands. So we can't really patch :(

(Compressed) Version: ADSL ATU-R, start: bfc5d430 Length: 390890, Checksum: 08F1 Compressed Length: D7150, Checksum: DBE7 Copyright (c) 2001 - 2006 TP-LINK TECHNOLOGIES CO., LTD initialize ch = 0, IP175C, ethernet address: 00:XX:XX:XX:XX:41 initialize ch = 1, ethernet address: 00:XX:XX:XX:XX:41 Wan Channel init ........ done Initializing ADSL F/W ........ done ANNEXAL set try multimode number to 3 (dropmode try num 3) Syncookie switch On! Press ENTER to continue... Valid commands are: sys exit ether wan ip bridge dot1q pktqos show set lan tc>

So what happened? The compressed stage 2 firmware got decompressed and executed. Knowing the ATGR command boots up the router let's find the instruction that passes the execution to the stage 2 firmware. This seems to be the best option because the firmware at that point is already unpacked.

ROM:80011E8C loc_80011E8C: # CODE XREF: LoadAndRunImage+D8j ROM:80011E8C jal sub_80009B24 ROM:80011E90 li $a0, 0x1F4 ROM:80011E94 ROM:80011E94 execute_image: # execute image ROM:80011E94 jalr $s0 # jump and link to address in $s0 ROM:80011E98 nop

Now the question is what is the address stored in $s0? Obviously we still can't set a breakpoint, we can't view the registers so we need to leak it using some trick. But wait we can read and write memory so take a look on the following command:

ATWL 80011E94, ae30001c ATGR

This command patches the instruction at 0x80011E94 with ae30001c (the byte representation of MIPS "sw $s0, 0x1C($s1)" instruction). By overwriting the original jalr $s0 with sw $s0, 0x1C($s1) we have forced the program to store the contents of $s0 register to 0x8001FF1C memory address. So now stage 2 firmware will not be executed instead the "ERROR" message will be presented and we will still have the access to the stage1 console! So let's take a look what was stored at 0x8001FF1C.

ATRL 8001FF1C 8001FF1C: 80020000

So now when we have leaked stage 2 address (0x80020000) we can dump it and analyse it properly).



So keeping in mind that we want to block ROM-0 from being downloadable I have found (using trail and error and xrefs) following code fragment that was a great candidate for patching:

ROM:80248C98 la $a1, aRom0_8 # "/rom-0" ROM:80248CA0 jal sub_802D0F2C ROM:80248CA4 move $a0, $s2 ROM:80248CA8 beqz $v0, loc_80248CB8 # NOP THIS SIR ROM:80248CAC li $v1, 0xE ROM:80248CB0 j loc_exit ROM:80248CB4 sw $v1, 0x64($s3) ROM:80248DEC loc_exit: # CODE XREF: sub_80248AA8+208j ROM:80248DEC # sub_80248AA8+21Cj ... ROM:80248DEC lw $ra, 0x28+var_4($sp) ROM:80248DF0 lw $s0, 0x28+var_28($sp) ROM:80248DF4 lw $s1, 0x28+var_24($sp) ROM:80248DF8 lw $s2, 0x28+var_20($sp) ROM:80248DFC lw $s3, 0x28+var_1C($sp) ROM:80248E00 lw $s4, 0x28+var_18($sp) ROM:80248E04 lw $s5, 0x28+var_14($sp) ROM:80248E08 lw $s6, 0x28+var_10($sp) ROM:80248E0C lw $fp, 0x28+var_8($sp) ROM:80248E10 nop ROM:80248E14 jr $ra ROM:80248E18 addiu $sp, 0x28

So the beqz $v0, loc_80248CB8 instruction jumps to loc_80248CB8 and we simply don't want that. So instead when the condition is not met this procedure jumps to loc_exit which is basically saying "goodbye". So let's patch the beqz with NOP:

ATEN 1,508fad63 ATWL 80011E94, 00000000 ATGR ATWL 80248CA8, 00000000 ATGO 80020000











SUCCESS! So now when the stage 2 firmware is patched in memory and booted it is time to test it (for the record: 192.168.2.1 - is my router addr)!

Conclusion

This simple patch was done in virtual memory only meaning everything will come back to the state it was before applying it after your router reboots. This is convenient from one side and inconvenient from the other. It is certainly possible to flash the device with modified firmware but I will not provide such methods here. One way or another I hope you have enjoyed the journey as I did. There are probably a plenty more vulnerabilities like this one somewhere inside every router so sometimes such ghetto hacks may become necessary :-) (let's hope not!). Obviously this was just one simply patch and it wasn't heavily tested in action. Please use this method as a way of learning something NOT as an actual remedy (probably there are plenty of other bugs that need to be patched as well). - PIOTR 31.01.2014 / EOF.







Bonus Binwalk

Some additional material from binwalk:





root@ubuntu:/home/die/binwalk/firmware# binwalk firmware.bin DECIMAL HEX DESCRIPTION ------------------------------------------------------------------------------------------------------------------- 84992 0x14C00 ZynOS header, header size: 48 bytes, rom image type: ROMBIN, uncompressed size: 66696, compressed size: 16845, uncompressed checksum: 0xC92E, compressed checksum: 0xC9CE, flags: 0xE0, uncompressed checksum is valid, the binary is compressed, compressed checksum is valid, memory map table address: 0x0 85043 0x14C33 LZMA compressed data, properties: 0x5D, dictionary size: 8388608 bytes, uncompressed size: 66696 bytes 128002 0x1F402 GIF image data, version "89a", 200 x 50 136194 0x21402 GIF image data, version "89a", 560 x 50 349184 0x55400 ZynOS header, header size: 48 bytes, rom image type: ROMBIN, uncompressed size: 3737744, compressed size: 880976, uncompressed checksum: 0x8F1, compressed checksum: 0xDBE7, flags: 0xE0, uncompressed checksum is valid, the binary is compressed, compressed checksum is valid, memory map table address: 0x0 349235 0x55433 LZMA compressed data, properties: 0x5D, dictionary size: 8388608 bytes, uncompressed size: 3737744 bytes dd if=firmware.bin bs=1 skip=85043 of=image1.lzma dd if=firmware.bin bs=1 skip=349235 of=image2.lzma root@ubuntu:/home/die/binwalk/firmware# lzma -d image1.lzma root@ubuntu:/home/die/binwalk/firmware# lzma -d image2.lzma die@ubuntu:~/binwalk/firmware$ binwalk image2 DECIMAL HEX DESCRIPTION ------------------------------------------------------------------------------------------------------------------- 2840932 0x2B5964 Copyright string: " (c) 1994 - 2004 ZyXEL Communications Corp." 2840988 0x2B599C Copyright string: " (c) 2001 - 2006 TrendChip Technologies Corp." 2841044 0x2B59D4 Copyright string: " (c) 2001 - 2006 " 2865263 0x2BB86F LZMA compressed data, properties: 0x48, dictionary size: 33554432 bytes, uncompressed size: 16777216 bytes 3037283 0x2E5863 LZMA compressed data, properties: 0x5C, dictionary size: 33554432 bytes, uncompressed size: 16777216 bytes 3037543 0x2E5967 LZMA compressed data, properties: 0xB4, dictionary size: 33554432 bytes, uncompressed size: 16777216 bytes 3209377 0x30F8A1 LZMA compressed data, properties: 0x40, dictionary size: 2097152 bytes, uncompressed size: 2097216 bytes 3350495 0x331FDF LZMA compressed data, properties: 0xB8, dictionary size: 16777216 bytes, uncompressed size: 538981760 bytes 3445523 0x349313 LZMA compressed data, properties: 0x40, dictionary size: 16777216 bytes, uncompressed size: 949368448 bytes 3563851 0x36614B LZMA compressed data, properties: 0x90, dictionary size: 16777216 bytes, uncompressed size: 33554432 bytes 3652626 0x37BC12 GIF image data, version "89a", 16 x 16 3653238 0x37BE76 GIF image data, version "89a", 16 x 16 3654302 0x37C29E GIF image data, version "89a", 16 x 16 3655370 0x37C6CA GIF image data, version "89a", 16 x 16 3734691 0x38FCA3 LZMA compressed data, properties: 0x88, dictionary size: 33554432 bytes, uncompressed size: 167772160 bytes 3737404 0x39073C Copyright string: " (c) 1996-2000 Express Logic Inc. * ThreadX R3900/Green Hills "