[pwn.college] Dynamic Allocator Misuse
pwn.college 中的 Dynamic Allocator Misuse 堆漏洞利用思路小结
level 1
UAF
level 2
UAF
read_flag 申请的堆块大小做了一个 rand 处理,但是并未设置随机种子,所以每次运行还是固定的值
level 3
UAF
read_flag 申请 2 次堆块,但我们同时也能访问多个堆块
level 4
Double Free
思考 tcache 在 free 时会做什么检查
level 5
read_flag 会将申请的堆块首字节置 0,puts_flag 检查其是否为 0
可以利用 free 设置 next 指针将其修改
level 6
未开启 PIE,.bss 段上存放了 8 字节 secret,需要读出来作为 send_flag 的输入
可以修改 next 指针从而 malloc 得到目标地址堆块
level 7
和 level 6 相似,只是 8 字节 secret 变成了 16 字节
注意 malloc 会将 key 清 0 即可
level 8
secret 地址最低字节为 \x0A,即 \n,通过 scanf 发送给程序会被截断
所以不断修改最低字节分部分泄露即可,善用 malloc 将 key 清 0
level 9
和上面的题目类似
无法访问分配到目标地址的堆块,但是 malloc 确实执行了
level 10
泄露了栈地址和 main 函数地址,提供了 win 函数
只需分配一个栈上的 chunk 然后覆盖返回地址为 win 函数地址即可
level 11
如何获取栈地址和程序加载地址,关键在 echo 执行了 malloc,而我们有 UAF
1 | unsigned __int64 __fastcall echo(__int64 a1, __int64 a2) |
level 12
House of Spirit
提供了 stack_scanf 写栈,stack_free 尝试 free 栈上一个地址,stack_malloc_win 尝试 malloc 然后对比拿到的地址和 stack_free 地址,相同则输出 flag
所以利用 stack_scanf 伪造一个待 free 的堆块即可
level 13
House of Spirit
栈上存放了 16 字节的 secret,拿到 secret 就可以拿到 flag
同 level 12 利用 stack_scanf 伪造一个待 free 的堆块,再 malloc 得到栈上的堆块,即可控制 secret
level 14
和 level 11 类似,但是 echo 不一样了,主要区别在于栈地址的获取不太一样
不过我们依然可以获取,因为我们能够 malloc 拿到栈上的堆块
1 | __pid_t __fastcall echo(__int64 a1, __int64 a2) |
level 15
UAF 被 ban,但是 echo 是可以跨 chunk 访问的,所以我们依然能够利用 echo 拿到栈地址和程序加载地址
并且提供的 read 也是不限长度,我们只需要最开始分配一个块,将其作为我们访问后续空间的跳板
level 16
从这一题开始,glibc 版本升到 2.35,主要的变化是 safe-linking 机制,以及堆块地址 0x10 对齐
safe-linking 会对 next 指针进行保护,需要了解在 malloc / free 时 next 指针发生了什么变化



这道题就是 level 9 的 safe-linking 版,需要额外弄清楚下面 2 件事:
- 要分配到目标地址,next 应该填入什么
- malloc 目标地址后,我们无法访问该 chunk,思考其 next 指针的值会改变什么
level 17
level 10 的 safe-linking 版
直接分配到返回地址附近变得不可行,原因如下:
- chunk 地址 0x10 对齐,不能分配到 saved rip 地址
- 分配到 saved rbp 地址,chunk size 是 canary,会导致 malloc_usable_size 访问非法地址,从而发生段错误
- 再往栈上更低地址分配,需要泄露 canary
幸运的是题目泄露的栈地址不仅仅是栈地址,而是确切的我们可访问的堆块指针列表的地址
level 18
level 13 的 safe-linking 版
但是好像不用管 safe-linking
level 19
Chunk Overlapping
House of Spirit 是直接伪造,这个就是修改现成的
level 20
这道题是前面内容的综合
初看无从下手,基本目标是要泄露 libc 地址和栈地址,但是仅以前面所学知识我们不知道仅靠 tcache 能获取什么,之前的题目或多或少都提供了栈地址 / binary 地址 / 获取 flag 的便捷方式
根据 level 19,我们能想到可以构造重叠堆块,但是接下来呢?堆内存会存放 libc 的位置吗?
经过摸索可以发现以下事实:
- malloc 一个较大的重叠堆块并用 safe_write 输出其中内容,会发现疑似 libc 地址的东西
- 几次 malloc 之间调用一次 safe_write 会导致这几次 malloc 得到的地址不连续
关键:safe_write 第一次被调用时会调用 fdopen 打开 FD 1,并调用 malloc 申请堆块存储相应的 locked_FILE 结构体
level 20 部分源码:
1 | if ( strcmp(s1, "safe_write") ) |
fdopen 部分源码:
1 | new_f = (struct locked_FILE *)malloc(sizeof(struct locked_FILE)); |
也就是说,我们可以通过重叠堆块访问到一个 _IO_FILE_plus 结构体,该结构体中的 vtable 指向一个全局的跳转表 _IO_file_jumps,得到它就获得了 libc 地址
下面展示 stdout 结构:
1 | pwndbg> p *(struct _IO_FILE_plus *) stdout |
至于如何拿到栈地址,可以问问 environ