gkctf2020 domo 复现
1 | Welcome to GKCTF |
1 | domo: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=b8ef84fe110e5098832857f8a42e28fb72b4ff26, stripped |
64位,dynamically,全开
程序是给了 libc.so ,可以查看版本:
1 | ➜ [/home/ywhkkx/tool/LibcSearcher/libc-database] git:(master) ./find __libc_start_main 740 |
漏洞分析
1 | if ( size >= 0 && size <= 288 ) |
经典 off-by-one
入侵思路
程序ban了 hook,开了 Full RELRO,修改模块又没法正常使用(其实到这里的时候,我唯一想到的制胜手段就是 leak Environ 获取栈地址,然后WAA返回地址进行 ret 劫持)
我自己尝试完成本题目时遇到了不小的麻烦,利用 unsortedbin 泄露了 libc_base,构造 fastbin 泄露了 head_addr ,但是我的构造方式很紊乱,导致之后的 unlink 完全没办法进行,所以我还是学习一下大佬的 exp 把:
1 | # -*- coding: utf-8 -*- |
这时大佬泄露 libc_base 的过程(和我的想法一致,但堆风水比我好了不少)
1 | # leak libc_base |
堆布局如下:
1 | pwndbg> heap |
释放 chunk2 后,chunk2进入 unsortedbin ,重新申请回来使其在保留 leak 数据的前提下可以被 show 出来
1 | pwndbg> telescope 0x5616421500d0 |
“0x7ff69bf5cb0a”被 leak 出来,直接计算 libc_base
1 | # leak heap_addr |
堆布局如下:
1 | Allocated chunk | PREV_INUSE |
1 | pwndbg> telescope 0x5622703621f0 |
“0x56227036210a”会被 leak 出来,可以计算 heap_addr(heap首地址)
1 | # unlink for overlapping |
因为本程序的修改模块失效,所以大佬用了这种方式进行修改(fastbin的性质)
free第三块chunk前堆的情况:
1 | 0x5559a9d3f010: 0x0000000000000000 0x0000000000000051 // chunk0(index0) |
free第三块chunk后,堆成功重叠:
1 | 0x5559a9d3f010: 0x0000000000000000 0x0000000000000051 // chunk0(index0) |
1 | unsortedbin |
unlink 成功了(其实我以前学习 wiki 上的案例时,遇到的都是要在 chunk_list 中打 unlink 的,今天遇到这个才发现 unlink 其实很灵活)
1 | # fastbins attack |
接下来的 chunk 申请,都应该在 fake chunk 中分割:
1 | pwndbg> x/20xg 0x55efe9805010 |
1 | pwndbg> telescope 0x00007f39e554a97d |
新申请的 chunk 中被装满了 one_gadget ,方便后续劫持:
1 | pwndbg> x/20xg 0x55efe9805210 |
1 | # overwrite vtable |
先看看“fake_vtable”是什么:
1 | [+] fake_vtable >> 0x55d3aa3da220 |
1 | pwndbg> x/20xg 0x55d3aa3da210 |
为了方便演示,先把“fake_vtable”换为无用地址(劫持之后GDB就无法正常显示了)
payload覆盖前:
1 | pwndbg> telescope 0x7f754337997d+3 |
payload覆盖后:
1 | pwndbg> telescope 0x7f754337997d+3 |
vtable
变量的值为 _IO_file_jumps
的指针,_IO_file_jumps
中保存了一些函数指针,一系列标准IO函数中会调用这些函数指针,但 _IO_file_jumps
里的内容是无法修改的,但可以修改 vtable
指向伪造的 _IO_file_jumps
从而getshell
小结:
这个题目我先自己做了做,成功 leak 了 heap_addr 和 libc_base,想到了打 fastbin attack,利用 unlink 实现 overlapping 来突破本程序严格的 size 检查,但是最后卡 unlink 那里了,复盘时发现自己的堆排布很乱,导致 unlink 总是出现未知状况(触发莫名其妙的合并等等)
学习大佬的 exp 时也踩了大坑,用 LibcSearcher 查找出来的 libc 版本有误,凑巧的是,在线查询网站上也是这个结果,导致我的 _IO_2_1_stdin_
排列的和其他师傅的博客大相径庭,最后,我在一篇博客中看到:在IDA中可以直接查看 libc.so.6 的 libc 版本
这些坑现在踩了,以后就注意了