PWN堆house of orange
- 总是感觉自己太焦虑了,是不是自己想太多了,还是喜欢独处,喜欢自己一个人。
- 参考文章:关于house of orange(unsorted bin attack &&FSOP)的学习总结 - ZikH26 - 博客园 (cnblogs.com)
相关知识
- house of orange该攻击手法是在没有
free
函数的情况下,来获得一个在unsorted bin中的堆块。 - 漏洞成因的源码位置在
malloc.c
和arena.c
中(glibc2.23) house of orange
这种堆利用手法就已经开始与IO
结合在一起了
实验
源码(英文)
源码
1 |
|
源码(中文)
- 老样子,翻译一遍源码
1 |
|
利用过程1(构造unsorted_bin)
-
house-of-orange这个打法是在没有
free
的情况下,要利用堆溢出或者其他对堆的正常操作,使得top_chunk空间不够,此时就会触发一个系统调用,该系统调用就会向操作系统申请一个新的top_chunk,这个时候我们就从无free的条件下,构造出了一个放在unsorted_bin中的堆块。 -
对于如上构造unsorted_bin的方法,目前我已知的有俩中方法:
- 利用house-of-force通过堆溢出,对top_chunk的size位直接修改(要满足top_chunk_size修改+前面申请的堆块size=0x1000对齐)。(利用漏洞的方式)
- 利用程序的运行逻辑,该程序单次申请能申请比较大的堆块,这样我们就有机会消耗完top_chunk的内存空间。(正常方法)
-
接下来我们进行调试,为了调试方便我们先关闭一下随机地址偏移。由于我使用的是Docker,所以直接在宿主机关掉随机地址偏移即可。
1 | sudo sysctl -w kernel.randomize_va_space=0 |
- 接下来开始正式的调试,所以我们就可以进行调试,我们这边先申请了一个
size=0x400
大小的堆块,先对堆块初始化。
- 接下来我们为了方便调试,我们就不多申请那么大的堆块了,就直接修改top_chunk的size位为0xc01。
- 接下来我们申请一个大于0xc00大小的堆块,这就使得我们top_chunk我们无法满足用户所申请的堆块大小,触发系统调用,使得旧top_chunk放入unsorted_bin,接下来我们申请了一个
0x1000
大小的堆块。接下来我们来调试这个过程。
此时我们就完成了攻击的第一步,即构造出了大堆块并且放入了unsortedbin
中里面去
利用过程2(了解IO)
- 接下来我们就进行一个目前PWN的主流方法,也就是伪造或劫持IOFILE
- 前提介绍:
- 当libc发现堆处于异常状态的时候会触发abort调用
- 无论何时abort被触发, 它都将通过调用**_IO_flush_all_lockp**刷新文件指针.
- 最终, 会遍历链表**_IO_list_all并且调用链表中的_IO_OVERFLOW**.
- 该方法是修改**_IO_list_all使其指向我们伪造的文件结构体**
- 在这个结构体中**_IO_OVERLOW**指向system函数并且这个结构体的前八字节要被设置为’/bin/sh’
- 以便于调用 _IO_OVERFLOW(fp, EOF)这个函数的时候会执行system(’/bin/sh’)
- 几点明确:
-
_IO_list_all是一个指向如下结构体的指针,该结构体如下,并且它就是单独一个指针。
-
vtable是指向**_IO_file_jumps的一个指针,而_IO_file_jumps本身是一个指针指向的是jumps结构体**
1 | struct _IO_FILE_plus { |
- _IO_FILE是一个结构体,里面存放着许多指针和其他类型的数据
- _IO_file_jumps是一个指针,它类似于**__IO_list_all**这个指针,指向的是一个结构体。jumps结构体如下(部分),具体查看
glibc-2.23\libio\fileops.c
1 | const struct _IO_jump_t _IO_file_jumps = |
- 所以这几个指针、变量、结构体的关系
- 在开始伪造操作之前,我们先来查看一下**_IO_list_all这个地址所在的位置,我们使用如下命令在
pwndbg
中输出的是_IO_list_all**这个指针的地址
1 | p &_IO_list_all |
- 此时我们发现这个**_IO_list_all这个存储在libc中,所以我们其实可以根据unsorted_bin**堆块的fd指针所指向的地址通过偏移得到。
- 接下来我们再使用如下命令查看**_IO_list_all这个指针指向的具体地址,我们会发现_IO_list_all**这个指针指向的是图中箭头这个位置
1 | x/20gx 0x7ffff7dd2520 |
- 接下来我们再使用如下命令查看一下**_IO_list_all**这个文件结构
1 | p *(struct _IO_FILE *) _IO_list_all |
- 输出之后我们会发现这样的数据
- 此时我们对比一下,发现IO_FILE这个结构体其实也在glibc这个位置,并且位置其实就在**_IO_list_all**下面一点。
struct _IO_FILE
这个结构体存储着就是**__IO_FILE**相关的东西,而我们
- 接下来我们查看一下
_IO_file_jumps
的地址
1 | p &_IO_file_jumps |
- 接下来我们再查看**_IO_file_jumps**指向的结构体
1 | p _IO_file_jumps |
- 进行对比:
利用过程3(伪造和劫持IO)
- 接下来我们回到程序中继续调试。接下来这边的这个代码,就是我们通过偏移获取的**__IO_list_all文件指针**的地址
- 目前该指针还是指向的是原始的IO_FILE
- 接下来我们需要通过堆溢出,劫持位于unsorted_bin中堆块的bk指针
- 劫持后就变成如下:
- 接下来我们向位于unsorted_bin中的堆块写入
/bin/sh\x00
- 之后我们修改了处于unsorted_bin中堆块的size
- 接下来就是非常关键的一步,在堆块上伪造IO_FILE和劫持__IO_list_all指针到堆块上,接下来我们先进行的操作是在堆块上伪造IO_FILE
1 | fp->_mode = 0; |
- 最后我们伪造跳表和vtable
1 | size_t *jump_table = &top[12]; // controlled memory |
- 接下来就是
malloc(10)
触发unsorted_bin_attack
的过程,根据unsorted_bin_attack
- 我们的**__IO_list_all就会跟新值,其值指向上图unsorted_bin**的位置中(位于libc中的main_arena)
- 而unsorte_bin这个指针又指向old_top这个堆块
- 这样我们的结构就如下:
- 最终走到这里调用
winner
house_of_orange_level_1
-
题目来源:hitcon_2016中的
house_of_orange
-
先来检查一下保护机制,发现该题目的附件保护全开
level_1分析1
全局变量(bss段)
- 全局变量通过解读程序代码,我们会发现该全局变量有如下四个:
house_ptr
:指向一个house
结构,这个结构之后会说明house_count
:统计house
的个数upgrade_count
:统计upgrade
的个数orange
:存放橘子的图案
- 接下来我们说明一下
house_ptr
的这个所指向的house
结构,该结构如下:
1 | struct house{ |
main函数和菜单
- main函数其实就实现的是一个菜单的功能,具体的菜单在
menu
这个函数中,先放在这里,更好理清楚main函数的逻辑
- 接下来放出
main
函数的逆向代码,发现main函数主要就是两个主要功能- 输入选项,执行对应选项的函数。
- 对无效选项进行处理
Build函数
- 接下来先看选项
1
,这个Build
函数,其实就是主要的三个部分:- 先判断创建
house
的数量是不是超过了3个 - 再申请一个
0x10
的堆块,作为house
- 然后申请指定大小的堆块,使得该堆块被作为
house_name
,这个堆块的大小申请没办法超过0x1000
- 之后使用
calloc
再创建一个堆块,用来存放price_orange
、orange_color
- 先判断创建
- 所以我们就可以画出大致的堆块
house
结构图
see函数
- 这个函数主要就是一个输出的作用,输出的就是
name
、price
- 输出的内容大致如下:
Upgrade函数
- 主要就是重新写入
house
中的一些相关信息。而这个函数中存在堆溢出漏洞。 - 此时我们就可以通过堆溢出利用
house_of_force
这个构造出Upgrade
这个函数
level_2分析2
- 接下来就是动态调试的过程了。先写好交互的相关代码,进行调试操作。
1 | from pwn import * |
- 本质上该程序就是构造一个实验中的那个结构,原原本本的构造即可
通过溢出得到free堆块
泄露libc和堆地址
伪造IO
exp
- exp如下:
1 | from pwn import * |
总结
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 iyheart的博客!