教练,我还想用IO
IO的利用在现在的pwn题里越来越常见夜越来越多了,虽然house of orange已经是angelboy大神在hitcon 2016里提出的了,但是现在还是很常用,这里吐槽一下hitcon2019还是很变态2333,鉴于现在的使用越来越多,这里打算重新学习一下IO,鉴于水平问题,所不及之处或错误之处还望海涵并与我联系,因为之前已经写过一篇IO的,所有对IO不了解的可以先看一下我之前的文章
_IO_FILE结构体利用
这里贴两个链接,以表自己对angelboy师傅的膜拜1
2
3http://4ngelboy.blogspot.com/2016/10/hitcon-ctf-qual-2016-house-of-orange.html
http://blog.angelboy.tw/
house of orange再浅析
house of orange的使用条件
- 可以泄露heap和libc基址
- 可以触发unsorted bin attack
- 有空间让我们伪造FILE结构体
而条件一可以使用unsortedbin和small bin来泄露
原题的难点在于没有提供free函数,而在这种情况下我们该如何制造一个unsorted bin就是难以解决的问题了
解决方法
关于第一个其实有一个小trick,也是一个小机制
我们知道我们malloc块的时候,一般都是在top chunk处切一小块下来给我们,但是当我们申请的大小大于top chunk的size且不会使用mmap拓展(即仅仅是brk)的时候,就会把现在的top chunk变成unsorted bin chunk,此时我们就可以利用这个unsorted bin来泄露了
剩下的就是我们该如何伪造FILE结构体了
而我们知道通过unsorted bin attack 可以向任意地址写如main_arena结构体中的top对应地址值
struct main_arena:
1 |
|
这里就先到此为止,下面我们进入正题,IO的利用
IO来了
我们知道我们日常使用的一个代码比如:1
FILE *fd=fopen('');
此时系统并不会直接给fd分配一个_IO_FILE指针,其实他分配给FD的是_IO_FILE_plus结构体,
这里也贴一下方便查看1
2
3
4
5struct _IO_FILE_plus
{
_IO_FILE file;
IO_jump_t *vtable;
}
而我们的vtable虚表的结构是这样的1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24void * funcs[] = {
1 NULL, // "extra word"
2 NULL, // DUMMY
3 exit, // finish
4 NULL, // overflow
5 NULL, // underflow
6 NULL, // uflow
7 NULL, // pbackfail
8 NULL, // xsputn #printf
9 NULL, // xsgetn
10 NULL, // seekoff
11 NULL, // seekpos
12 NULL, // setbuf
13 NULL, // sync
14 NULL, // doallocate
15 NULL, // read
16 NULL, // write
17 NULL, // seek
18 pwn, // close
19 NULL, // stat
20 NULL, // showmanyc
21 NULL, // imbue
};
这里要特地提一下,house of orange这道题的环境还是libc2.23,也就意味着我们可以直接更改vtable来改变程序的执行流程hhh
而我们如何跳到vtable_IO_jump_t执行呢,这也很简单,只要构造一个错误就好,我们可以通过unsorted bin attack 来使得malloc出错,从而调用malloc_printerr,然后的调用链如下所示:1
malloc_printerr->__libc_message->abort->fflush(_IO_flush_all_lockp)->vtable->_IO_OVERFLOW(hijack->system)
此时就可以完成整个调用链来获得shell
而且此时有两种绕过check的构造方式1
2
3
4
5
61.fp->_mode <= 0
2.fp->_IO_write_ptr > fp->_IO_write_base
或
1._IO_vtable_offset (fp) == 0
2.fp->_mode > 0
3.fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base
libc>2.23
方法一
之前的文章也有提及,在libc>2.23之后,glibc就添加了一个新的check函数(_IO_vtable_check)
虽然我们不能随意伪造一个新的结构了,但是libc段上的__libc_IO_vtables还是可以用的,那么我们,而我们只需要更改_IO_str_jumps的虚表_IO_str_overflow即可,然后如下构造即可:1
2
3
4
5_flags = 0
_IO_write_ptr = 0x7fffffffffffffff
_IO_write_base = 0
_IO_buf_end = (binsh_addr-100)/2
_IO_buf_base = 0
方法二
这个方法来自V神的思考:即修改(_IO_str_finish)链接1
2
3
4
5
6
7
8
9void
_IO_str_finish (_IO_FILE *fp, int dummy)
{
if (fp->_IO_buf_base && !(fp->_flags & _IO_USER_BUF)) //唯一需要bypass的条件
(((_IO_strfile *) fp)->_s._free_buffer) (fp->_IO_buf_base);// getshell , [fp+0xe8]
fp->_IO_buf_base = NULL;
_IO_default_finish (fp, 0);
}
利用stdout泄露地址
在没有输出函数的情况下,我们该如何泄露地址呢?
我们只需要劫持stdout指针即可
一般来说是通过UAF,接着改FD的main_arena+88的末位
如果没有则利用攻击global_max_fast的方式去做,然后利用fastbin attack,变成stdout-xx的位置(得有0x7f或者0xff的size,0x7f在0x43的位置,0xff在0x51的位置),下一次申请时就可以从上往下写,改写flag标志位为0xfbad1800固定值,同时修改IO_Write_base末尾为’\x00’,在flag位和IO_Write_base位之间填写的东西可以为任意值,我们的目的是下溢改写IO_Write_base
写到这里就差的不多结束了,因为发现了一篇写的更优秀的文章,为了避免重复造轮子,这里贴出来https://www.anquanke.com/post/id/168802#h2-9
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!