题目介绍
程序只有两个功能:
1 | 1.create string |
1、create 功能
先申请一个0x20大小的堆空间,接着输入字符串,如果字符长度<0xf那么直接放入ptr里,如果 >0xf 则再申请适合长度的堆空间存字符,然后将指针存到ptr中,最后会将堆的free函数存储在堆存储结构的后8字节处,如下图
2、delete 函数
调用存储在结构体里的free_func指针来释放堆
由于free时没有将指针置空,出现了释放后仍可利用的现象,即uaf
利用思路
查看保护机制
可以看到保护全开,所以在解题过程中要先绕过PIE。
思路:首先利用uaf,利用堆块之间申请与释放的步骤,形成对free_func指针的覆盖。从而达到劫持程序流的目的。具体来说,先申请三个字符长度小于0xf 的堆块,并将其释放。此时fastbin中空堆块的单链表结构如下图:
那么此时再创建一个字符长度为0x20的字符串,则申请出来的堆结构会是如下图
此时就可以将1号堆块的free_func指针覆盖为任意内容,指向我们需要执行的函数,随后再调用1号块的free_func函数,实现劫持函数流的目的。
利用过程
1、绕过PIE
在能劫持函数流之后 ,首先是泄露出程序的地址以绕过PIE,具体方法是:将free_func的低位覆盖为0x2d,去执行puts函数,打印出free_func的地址从而得到程度基地址。
2、泄露真实地址
得到基地址后,下一步要做的就是泄露真实地址了,puts函数执行完后程序回到了0xc71处,此时fastbin中只有2号堆块,所以要先释放0号堆块,释放完后3个堆块都处理空闲状态了,此时查看栈中的情况会发现,在delete中输入的yes其实是存储在栈中的,而且,可读入0x100个字节。
这样,我们就可以在栈上布局rop链达到劫持程序流的目的, 我们可以找到pop_pop_pop_pop这样的gadget将栈顶的4个元素弹出,’yes’之后便是返回地址。再调用puts函数打印出puts_got得到puts的真实地址。再利用同样的方式调用system(‘/bin/sh’)
EXP
1 | #coding:utf-8 |