gyctf_2020_signin
info
License
本文引用了部分来自 GNU C Library 的源码,源码取自 GNU C Library 基于 LGPLv2.1.
注:本题目的运行环境使用的 glibc 为 2.27-3ubuntu1_amd64,但本文中展示的所有 glibc 代码为 2.34.
WriteUp-gyctf_2020_signin
看到本文的各位师傅,请允许 Y7n05h 又翻出这段各位都熟悉无比的代码.能够发现从非空的 tcache 中取出 chunk 是在 __libc_malloc() 中完成的,而非在 _int_malloc_() 中.
1 | void * |
再看 __libc_calloc():
1 | void * |
相信各位都能发现 __libc_calloc() 和 __libc_malloc() 的差别是很小的,通常情况下将 __libc_calloc() 视为 __libc_malloc() + memset() 是合理的.但除此之外还有一点区别是 __libc_calloc() 中缺少从非空的 tcache 取出 chunk 的部分,因此 calloc() 将优先从 fastbin 中分配 chunk.
这也是本题目的利用的核心思路.
错误思路-tcache poisoning
Y7n05h 刚开始也是想采用 tcache poisoning 来完成本题,并寄希望与 free/malloc 的过程中能清除 cnt 实现第二次 edit.但很遗憾,此路并不通.通过此方式虽能将 chunk 分配在 ptr 上,但无法修改 ptr 的值.(至少 Y7n05h 没想到)
正确思路
此方式是从 Pwnki 师傅 的博客学来的.在这里感谢 Pwnki 师傅 师傅.
利用思路:
- 分配 8 个大小为 0x80 的 chunk 后全部 free,前 7 个塞满了 tcache,后一个进入 fastbin
- 在分配一个 chunk,这将从 tcache 中取出一个 chunk
- 修改在 1 中放入的 fastbin 中的 chunk 的 fd 的指针为
ptr - 0x10,注意这个行为使glibc认为ptr - 0x10是一个 chunk,则ptr则是这个chunk的fd - 通过执行
backdoor,调用calloc从fastbin取出chunk并将其fd指向的ptr - 0x10作为一个chunk插入tcache链表.插入过程中ptr将作为tcache_entry的next字段被修改.
这些过程的相关代码:
1 | typedef struct tcache_entry |
1 |
1 | /* While we're here, if we see other chunks of the same size, |
完整 exp:
1 | from pwn import * |
参考资料
1. Pwnki-gyctf_2020_signin. ↩
2. PYozo_free-gyctf_2020_signin. ↩