看雪CTF2019-apwn
题目
首先看保护,Full RELRO,所以没办法复写got表。所以泄露了libc过后的思路是Hook掉free函数
功能:
就是添加,编辑,拯救单身狗(free lucky dog然后替换)的一个功能。
漏洞
可以看到,这里的下标v1没有做好检查,我们如果用-6和-4就可以得到_IO_2_1_stdin_ 和_IO_2_1_stderr_的libc地址,但是不是单纯的访问这个地址,这里显示的是该地址的内容,而我们想要的是libc地址,但是_IO_2_1_stdin_往后8个字节的地址指向的内容便是_IO_2_1_stdin_+131,所以我们输入-6过后,再输入’a’*7+’\n’就能覆盖掉\x00从而获得8个字节后地址所指向的内容,也就是_IO_2_1_stdin_+131,然后就能得到_IO_2_1_stdin_的实际地址了。同理,如此可获得_IO_2_1_stderr_的实际地址。
然后使用https://www.jianshu.com/p/8d2552b8e1a2 或者https://libc.blukat.me网站或者LibcSearcher便能查询libc版本。LibcSearcher用法:
1 | from LibcSearcher import * |
利用
那么得到了libc的版本过后,我们可以使用编辑单身狗功能同样的漏洞,泄露得到堆基址。就是index输入80(前提是要lucky_dog那里生成过),利用这个,我们可以实现在luck_dog的partner那里写上任意地址,我们把free_hook_addr的实际地址写入(free_hook_addr的实际地址就是LibcSearcher示例里那样获得)。然后利用Lucky_dog的编辑功能,可以对这个任意地址实现写入,那么我们把system函数的实际地址写入free_hook_addr。这样一旦程序执行free函数,就会执行system。
最后一步就是把system的参数’/bin/sh’构造好,这个就是我们比如一开始生成lucky_dog时候,partner的名字就赋值’/bin/sh’就好,然后用同样的方法把他的地址写回堆里。然后生成一个single_dog(为了执行save_single_dog必备),然后选择5,就会free(‘/bin/sh’),其实就是system(‘/bin/sh’)。
坑:本地和一般的堆基址都是00,但是看雪的远程的堆基址是0x50。因为我们获得堆基址把最低字节覆盖掉了,所以这个0x00本地可以远程不行,远程的时候把00,10,20,30这样一直试下去,最后0x50的基址,也就是’/bin/sh’在0x90成功。
这里recv()没有限制好,在本地没有问题,但是远程会得到错误的libc地址,用recvuntil()或者slee(1)可解决,当时为了排坑把def create()这样的拆了,改成一个一个sendline和recv
exp
1 | from pwn import * |