HITCON CTF 2019 pwn 题解
TOC
权重 98 的国际赛。
文件链接:hitcon_ctf_2019.zip。
Trick or Treat
一道 misc pwn,考验答题者的脑洞。
void __fastcall __noreturn main(__int64 a1, char **a2, char **a3) |
思路:
- 申请的size足够大,使得其使用 mmap 进行内存申请,从而用其偏移计算 libc 地址
- 把 free_hook 指向 system
- ed 绕过滤
- !/bin/sh 执行shell
#!/usr/bin/python2 |
dadadb
来自 Angel boy
的题目,质量当然毋庸置疑。
其链表并没有什么问题,成链和解链都很正常。
漏洞比较简单,在 add 的时候,当对应的 链表 如果有 指针的话,则会把原先的 free 掉后再申请新的,但是其并没有更新其size,也就意味着使用的仍然是原先的size,如果原先的size本身就很大的话,无疑直接导致了 heap overflow。
int add() |
思路
- 控制其指针结构进行任意读。
由于我的Windows的dll是和靶机一样的,所以直接用 windbg 读 symbols 就行,假如靶机用的是一个比较冷门的dll,那么获取其对应的 symbols 应该也比较麻烦。
伪造假的 chunk 放入 FreeList,从而控制 data 段的 fp 指针。
利用 FILE - fread 进行任意写
这里和 Linux 的 fread 任意读类似。
- 劫持返回地址,进行 ROP 使得内存有可执行权限,然后跑 shellcode 读 flag。
在Windows 下进行 ROP 来读 flag 很麻烦,不如直接写 shellcode 来的快,这里我提醒一下,要注意 栈下溢,否则 ReadFile 时可能会出错。
脚本
#!/usr/bin/python2 |
Crypto in the Shell
这题比较简单,没有设置很多障碍,漏洞点也很明显,就是明显的数组溢出。
int __cdecl main(int argc, const char **argv, const char **envp) |
思路
- 修改 key, iv 并泄露出来。
- 利用 key, iv 泄露出 libc、镜像、栈 地址。
- 修改 局部变量i ,使得我们有很多次机会
- 任意写
任意写的原理就是爆破一个字节,利用加密函数进行爆破使得其等于我们需要的那个字节,否则就继续爆破,知道出现预期结果为止。多个字节的话,单字节爆破叠加即可。
脚本
概率 1/2
,成功的主要因数取决于 修改的局部变量i
是否为负数。
#!/usr/bin/python2 |
另一种思路
由于有可以任意地址读,那么可以直接劫持 stdin 进行任意地址写。
one punch man
靶机环境是 glibc-2.29 ,需要用到一些新特性来进行利用以达到任意代码执行。
void delete() |
漏洞点在于 delete 时没有清理指针导致的 UAF ,程序使用的是 calloc 函数来获取 堆内存,这使得 tcache 就不能使用了,但是后门函数使用的仍然是malloc函数,不过我们需要满足其 tcache->counts 大于 6 才行。这就是该题的难点。
思路
- 用 UAF 构造 chunk overlap
- 用 tcache->counts 来伪造 size, 用 tcache->entries 伪造 fake_chunk 的 fd 和 bk,提前布置好 堆布局,以便绕过 unlink 检查。
- unlink 控制 tcache->entries,劫持hook控制程序流,然后SROP再执行shellcode读取flag。
脚本
#!/usr/bin/python2 |
另一种思路
利用 large bin attack 攻击 tcache->counts ,那么可以绕过限制直接调用后门。
LazyHouse
乘法溢出漏洞,重要输入的值满足下面的判断就能导致溢出。
unsigned long input; |
其原理是利用乘法的进位使得恰好溢出,并且得到的值小于116630
,可以利用除法来进行反向计算获得其溢出的输出。
unsigned long input = -1; |
思路
- 乘法溢出,解除 内存申请的限制
- chunk overlap,使得 heap 布局可以自由控制
- 泄露 heap 地址,和 libc 地址
- large bin attack 修改 global_max_fast ,使得可以继续使用fastbin
- fastbin attack 劫持 tcache
- 修改 hook ,利用 calloc 的特性进行栈转移。
- ROP 读 flag
通过调试靶机的 libc 可以发现 calloc 函数使用 rbp 当做寄存器变量来存储 传入的 size,所以我们可以控制其 size 进行栈转移。
脚本
#!/usr/bin/python2 |
其他思路
利用 small bin 来劫持 tcache (balsn战队)
利用 SROP 代替栈转移
POE luna
借用作者的原话,直接分析二进制代码就足够了。
#!/usr/bin/python2 |