深入浅出FSOP

2018-10-23 14:58:1424417人阅读

【Backer Talk】BSRC白客说第二期




概述


通常情况下,文件指针的利用有这几种方式:

  • 覆盖vtable

  • 覆盖fp

  • _IO_acquire_lock等溢出

  • FSOP

本议题将以一道比较简单的ctf题为例, _IO_acquire_lock中溢出的方式来缕清执行流程、熟悉结构体,进而分析FSOP的利用思路

seethefile


 > 题目来源:pwnable.tw

1.对照运行结果查看相应代码

1.jpg

文件打开读取关闭功能,打开的文件名不能带flag

2.jpg

发现写入全局变量name是可溢出覆盖到相邻的fp指针


2.触发崩溃

3.jpg

    fclose+23 处提示有段错误,此时esi = aaaa,即我们覆盖的值

!!所以,我们覆盖的 fd 应为一个地址而不是一个字符串


3.分析原因

下载 glibc 2.23 源码搜索 _IO_new_fclose 可在 iofclose.c中看到定义:

5.jpg

同时发现覆盖的aaaa为结构体 IO_FILE,查看定义:

注意图中的chain

6.jpg

 当 fp指针为正常指针时

7.jpg

 来看看它的结构:

8.jpg

就是下边这么个链表:

9.jpg

每一个节点的开头为 _flags ,正常的 _flags 前两个字节为 0xfbad

exploit


直接结合程序来一步步绕过对结构体的检测

把溢出到fp 的内容换成地址 0x0804B260 即全局变量量 name 的地址

10.jpg

崩溃信息如下:

11.jpg

可以看到箭头指向的前 面 用 DWORD PTR [esi+0x48] 给 edx 为 0 ,导致箭头处访问0x8 处的内存导致出错。

不妨把 edx 设置为 一个地址:

12.jpg

仍存在段错误:

13.jpg

溢出的地方为edx寄存器,分析发现对应结构体中: _lock 成员的值

14.jpg

查看崩溃之前执行的指令

15.jpg

修正payload:

16.jpg

17.jpg

查看崩溃前指令 

OK,已经很接近了,即:

eax = ebx + eax* 1 + 0x94 = bss_name + 0 + 0x94

那么我们可以通过设置 bss_name + 0x94 处的值从 而设置 eax ,进 而控制 call 的参数

如下步骤可以控制eip: 

1.找出要调 用的函数地址记为func_addr,写 入某个可控区域记为func_ptr

2.将func_ptr - 0x44写入bss_name + 0x94

修正payload,下 面的payload将eip设置为0xcafebabe

18.jpg

另一种方法


上面介绍结构体的时候有个_chain ,这个是做什么的呢?

还有_IO_list_all 这个东东,看起来里边的东西都可以伪造,能不能利用呢?

在glibc源码中搜索_IO_list_all可以在genops.c中找到主要的几个使用了该结构体的函数:

void _IO_link_in (struct_IO_FILE_plus*fp)

void _IO_un_link (struct_IO_FILE_plus*fp)

int _IO_flush_all_lockp (intdo_lock) 

重点来看第三个函数。

精简后的代码如下:

20.jpg

如果巧妙地控制判断的条件,伪造 _IO_list_all 结构体,则可以设置 fp 为任意地址。

全局搜索可以看到_IO_flush_all_lockp 在 abort.c 中是 fflush预处理后真实的样子,被函 abort()调用。

往上继续跟踪,最后被assert()调用。

调用链为:

assert() __assert_fail()__assert_fail_base()abort() _IO_flush_all_lockp()

此时我们发现_IO_flush_all_lockp 出现的场景非常多,包括

  • glibc abort

  • exit()

  • main return

所有包含断言的地方都有。

由此,我们又多了个利用思路:

Ⅰ.伪造_IO_list_all 

Ⅱ.通过某种 方式触发assert()从而调用_IO_flush_all_lockp使得fp为我们预期的地址

Ⅲ.利利 用_IO_flush_all_lockp对条件的判断时的一个预处理函数_IO_OVERFLOW达到利用效

ps:有点像windows 下伪造异常处理理句句柄并通过触发异常来实现利用的过程。

 文件结构体创建时涉及堆的操作,由此可以通过触发堆块检测异常来达到利用效果。

20.jpg

(from:angelboy’s topicon HITB SG2018)

//相关定义

//libioP.h

#define JUMP_FIELD(TYPE, NAME) TYPE NAME

//JUMP_FIELD(_IO_overflow_t, __overflow)

//_IO_overflow_t __overflow()

(*(struct _IO_jump_t **)

((void*) &_IO_JUMPS_FILE_plus (fp) + (fp)->_vtable_offset))

//genops.c

int __overflow (_IO_FILE*f,int ch)

{

/* This is a single-byte stream.          */

if (f->_mode==0)

_IO_fwide (f,-1);

return _IO_OVERFLOW (f, ch);

}

libc_hidden_def (__overflow)


参考资料

Pwning My Life:HITCON CTF Qual 2016 - House of Orange Write up


本文来自百度安全,如需转载,请注明出处及本文链接

【Backer Talk】将以两周一期的频率为大家带来技术分享,欢迎自荐成为BSRC白客说讲师,BSRC白客说征稿活动也在持续进行中,欢迎向我们惠赐作品。



0
现金券
0
兑换券
立即领取
领取成功