BUUCTF-Secret Holder
[BUUCTF] Secret Holder
题目链接:https://buuoj.cn/challenges#secretHolder_hitcon_2016
通过这道题来学习一下堆unlink相关操作
在开始讲这道题之前首先需要了解堆的一种漏洞利用: unlink, 通过unlink和向堆指向空间写入数据,我们能够实现任意地址写
unlink
在堆中,bins(非fast bin)是以双向链表形式存在,而我们从这个链表中获取一个chunk时,会触发链表节点的删除操作
如果我们想往一个地址(target_addr)写入任意值(my_value), 那么我们可以修改chunk的fd和bk分别为target_addr - 0x18, my_value,此时unlink操作就变成了
如果没有node节点的校验,并且我们拥有(my_value + 0x10)地区的写权限的话(一般都有target_addr的写权限),我们就能实现任意地址写。
然而,现实很骨干,开发者们早就注意到了这个漏洞,并在unlink时加入了如下的校验:检查下一个节点的presize和当前节点的size是否相同,且FD->bk == P && BK->fd == P
加入了这样一个校验机制之后,我们就不能直接达成任意地址写这个目标了。然而,道高一尺魔高一丈,前辈们想出了一种间接任意写的办法。让我们仔细看下这段校验的代码, 令FD = &P - 0x18, BK = &P - 0x10, 此时
- FD->bk = P
- *(FD + 0x18) = P
- *(&P - 0x18 + 0x18) = *(&P) = P
- BK->fd = P
- *(BK + 0x10) = P
- *(&P - 0x10 + 0x10) = *(&P) = P
校验通过,继续执行赋值语句
- FD->bk = BK
- *(&P - 0x18 + 0x18) = &P - 0x10
- P = &P - 0x10;
- BK->fd = FD
- *(&P - 0x10 + 0x10) = &P - 0x18
- P = &P - 0X18;
最终效果为P = &P - 0x18, 让我们来个图直观感受一下unlink前后的内存布局变化
通过unlink,我们成功让原本指向堆的指针指向了指针上方的一块区域。又由于题目中一般允许让用户对堆的内容重新输入,此时(第一次输入)我们只需要写入p64(0) * 3 + p64(target_addr)
,覆盖掉P的指针, 即可让P指向我们想要写入内容的地址,然后(第二次输入)写入p64(my_value)
,就能实现任意地址写。
还有一个关键的问题!怎样触发unlink? 当我们free掉一个chunk,叫chunk1,如果chunk1与top chunk相邻,chunk1就会与top chunk合并,同时还会去检查前面一个chunk,叫chunk0,如果chunk0处于free状态,则会触发链表的unlink。
glibc环境配置
接下来我们看下Secret Holder这道题,首先设置一下运行环境
IDA 代码分析
这个文件是动态加载的,题目中有三个堆buf_small
, buf_big
, buf_huge
,用三个变量init_small
, init_big
, init_huge
来标识是否被使用,在keep方法中,直接用read读取size个字符,并且没有用\0
结束读入的字符串,可能存在信息泄露。在wipe中,没有判断flag就直接free掉了buf,这里是一个double free漏洞。renew方法则是重新给三个堆赋值。
总体思路
- 构造fake chunk
- 执行unlink
- 泄露libc基址
- 执行one_gadget
编写exp
基本框架
构造fake chunk
图的出处见参考文献2, 这位老哥讲解的特别好,直接copy过来...
执行unlink
unlink之前需要做一些准备,buf_huge的大小是400000字节,最初的top chunk无法满足,我们需要先alloc一次,(这次会通过mmap分配,并扩大mmap分配的内存阈值),再free掉,再alloc第二次,第二次获取的堆地址才是我们想要的buf_huge地址(和buf_small, buf_big)相邻
alloc完buf_huge后的内存布局如图所示,之后我们就可以删除buf_huge来触发buf_small的unlink
unlink完后small_ptr就指向了small_ptr-0x18的位置,而big_ptr=small_ptr-0x10, 也就是说如果往small_ptr里写数据的话还会把big_ptr的内容给覆盖。现在让我们来修改got表
泄露libc基址
执行one_gadget
参考文献
[1]https://ctf-wiki.org/pwn/linux/user-mode/heap/ptmalloc2/unlink/
[2]https://poning.me/2016/10/29/secret-holder/
[3]CTF竞赛权威指南Pwn篇 p295.堆利用-HITCON CTF 2016: Secret Holder
__EOF__

本文链接:https://www.cnblogs.com/wudiiv11/p/buuctf-secret-holder.html
关于博主:励志成为世界一流的安全专家
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现