Delay3
1 | ➜ [/home/ywhkkx/桌面] ./Delay3 |
1 | Delay3: 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]=edcd74af07248bb015dfdb61762ab93dce45667f, stripped |
64位,dynamically,全开
1 | GNU C Library (Ubuntu GLIBC 2.23-0ubuntu11) stable release versio |
漏洞分析
1 | void delete() |
1 | unsigned __int64 __fastcall read_r(__int64 chunk, int size) |
入侵思路
- 对“size”的限制导致 chunk 无法进入 unsortedbin
- read_r 对末尾字节的置空限制了打印模块(同时也带来了 off-by-one)
- 程序每5秒钟置空一次 chunk_list
因为多线程会导致GDB打印不了数据,所以先把“pthread_create”改为了“menu”,把chunk的数量限制也改了:(再源文件中可以通过 sleep 获得原本的效果)
1 | .text:0000000000000ED5 lea rdx, start_routine ; start_routine |
先泄露“heap_addr”:
1 | add(0x48,'0'*0x10) |
限制了 unsortedbin 怎么泄露“libc_base”呢?
- tcache perthread corruption 劫持 count(直接排除)
- house of orange 中的思想:当 top chunk->size 不足时会把整个 top chunk 放入 unsortedbin,所以通过覆盖 top chunk->size 的方式进行入侵(行不通,因为页对齐的原因“size”最小为“0xf41”)
- 因为本程序每5秒钟都会清空一次 chunk_list ,所以理论上来说,可以无限申请 chunk,这时就需要利用这个机制把 top chunk 申请完,剩下的 top chunk 进入unsortedbin时乘机泄露(也失败了,因为程序会在半分钟后自动关闭)
- 利用 Double free 实现 overlap ,覆盖某个chunk的size来使该chunk可以进入 unsortedbin(好像可行)
1 | Allocated chunk |
1 | add(0x48,p64(leak_addr-0x10)) |
接下来就是利用了,我第一个想到 malloc_hook:
1 | pwndbg> x/20xg 0x7f7b59291b05 |
又是因为“size”的限制,hook 打不了
1 | pwndbg> telescope 0x7f362e950b78 |
最后利用 Double free 通过top chunk的首位“\x55”申请到 main_arena 中,却始终劫持不了 hook,在被堆风水和段错误折磨了6个多小时后,我蚌埠住了(其实最恶心的一点是:在多线程中,GDB打印不了数据了,如果 nop 掉多线程操作,有些步骤又没法完成,吐了)
1 | pwndbg> bins /* 一边红的GDB */ |
还是学习大佬的wp吧:
1 | import sys |
先看 leak 过程:(leak 过程没有太大差别)
1 | #chunk arrange |
利用 Double free 在 free chunk 的 FD 中写入“0x61”
1 | #Fastbin->A<->B |
1 | pwndbg> heap |
前两个chunk用于“暴露0x61”,后两个chunk继续打 Double free
1 | #forge size in main_arena 2 |
1 | pwndbg> bins |
刚开始我很疑惑,为什么要在 fastbin-0x50 这里写上 0x61 呢,后来想到当我自己劫持 main_arena 时的经历,fastbin 中的地址存储在 main_arena 靠前的偏移中,于是我打印了下 main_arena:
1 | pwndbg> telescope 0x7f59fc5f0b78-88 |
发现“0x61”真的在 main_arena 中,这下可以 Double free 劫持了(刚开始我采用了 top chunk 地址的“0x55”来劫持 main_arena ,结果只能劫持 unsortedbin ,最后发生了严重的段错误)
Double free 劫持 top chunk:(top chunk 比 fastbin,unsortedbin 都要好劫持)
1 | #fastbin alloc to main_arena |
1 | pwndbg> telescope 0x7f409e371ba8-136 |
1 | pwndbg> heap // GDB不能正常显示了,但是看'main_arena+88'的位置,应该是写上了 |
成功劫持 top chunk,在我劫持 unsortedbin 的时候,末尾置空这一点始终困扰着我(末尾置空破坏了 main_arena 结构导致了段错误,后来避免段错误后,发现根本通不过检查)
大佬的这种写法可以少去1字节,使“\x00”不会覆盖后面的数据
1 | OGG = libc.address+0x4527a |
1 | pwndbg> telescope 0x7fe67e7edae8 |
top chunk 的申请没有“size”的要求,对 __realloc_hook
和 __malloc_hook
的操作是为了重置栈帧
小结:
这6个多小时的解题有点折磨,最后看了wp回头看本题目时,发现思路也挺清晰
反正我是把可能技术都尝试了一遍:
- 首先是 leak 那里就出来问题,泄露出了“heap_addr”但是泄露不出“libc_base”(“size”的限制)
- 在此基础上,因为有 off-by-one 所以我选择打 unlink,结果当然失败了,先不管实现了 overlap 有什么用,覆盖“size->P位”的过程会把整个“size”给覆盖掉
- 使用 Double free 修改了“chunk->size”把它释放到了 unsortedbin 中,泄露了“libc_base”
- 接下来我当然想到了利用 Double free 劫持 hook,还是因为“size”的原因劫持不了(hook前面也没有“\x55”等可以劫持的地址)
- 又想到可以控制 top chunk 来打 House Of Force(size限制,排除)和 House Of Einherjar(只能控制 top chunk 前面的区域,控制不了 hook,排除)
- House Of Orange 肯定也不行
- FSOP 中 unsortedbin attack 勉强可以执行,但是 FSOP 需要伪造很长的IO_FILE结构体,size明显不符合条件
- 然后选择 main_arena 劫持,因为 top chunk 那里有“0x55”(main_arena+88),但是接下来只能劫持后面的 unsortedbin 了,末尾置空又会导致严重的段错误
最后止步于此…………
看了大佬的wp,发现其核心在于把“0x61”放入 fastbin 中,而后对应的 main_arena 条目就变为了“0x61”,可以利用 Double free 申请到这里,从而可以控制 top chunk(top chunk的检查比fastbin,unsortedbin少很多)
- 本题目使我的堆风水提高了不少(我前前后后改了不知道多少遍堆风水,最后才避免了报错)
- 另外学习到了 main_arena 劫持这门技术(限制“size”时必选)
我觉得我还是缺少历练,需要多多打比赛(挨打),做题(坐牢)