wdb_2018_1st_babyheap
总结
通过这道题的学习与总结有:
这道题考察的依然是利用UAF打unlink。unlink攻击的核心是可以伪造fake_chunk以及控制fake_chunk下面的堆块的chunk头。虽然无法直接溢出,但是我们可以做一个double free,然后打fastbin attack将chunk头申请出来(在低地址堆块中写入size,保证chunk头可以从fastbin上出来),接着就可以打unlink了。
保护策略:
程序分析
程序中就存在一个UAF漏洞(如下图)
同时限制了我们使用edit函数的次数为3次,限制了add函数的次数10次。最关键的是我们无法控制malloc出来堆块的大小,定死的size就是0x30。(如下图)
然后下面自定义的输入函数也不存在off by one以及溢出。
利用思路:
因为我们malloc申请的堆块大小是固定的0x30字节的,这样我们就没法得到libc地址,我们必须想办法让堆块进入unsorted bin中,这样执行show函数才能获取libc地址。所以我们肯定是要利用double free+fastbin attack将chunk头申请出来去修改堆块的size。
在这之前我们需要获取堆地址,然后多垫几个堆块,保证修改之后,堆块地址加上自身size后依然可以找到下一个正确的堆块地址。因为我们要将chunk头申请出来,就意味着我们需要伪造一个size,去通过fastbin的检查。(edit函数用的时候要慎重,最后我们打unlink写入地址时就需要用掉两个edit函数的机会,所以我们前面的各种布局只能用一次edit函数,而且这次肯定还是要在fastin attack的时候用)
然后我们下面放三种堆块布局,分别是正常的堆块A和堆块B,伪造size,申请chunk B head的布局,unlink时的堆块A和堆块B布局
正常的堆块A和堆块B布局如下:
因为我们想把chunk B head申请出来,因此我们需要伪造size,如下:
我解释一下这个图,首先我们是要控制chunk B head,因此我们先打一个double free+fastbin attack,将fake chunk(也就是黑色框中的部分)申请出来,这样我们往fake chunk中写入数据,就可以控制chunk B head了(将chunk B的size改成0xa0),而在这之前我们需要在chunk A中的用户区写入0x31这个size(否则无法通过从fastbin中申请chunk的检查)
上一步可以控制chunk B head后,我们把chunk B释放掉后,它就进入了unsorted bin中。同时别忘记unlink的条件,我们需要一个大于fastbin 范围的堆块作为引线堆块,所以释放这个chunk B的时候,我们还需要顺便打一个unlink。另外我们还需要布局一个fake chunk,这个fake chunk的size肯定要是0x20,因此我们需要修改下chunk A中的user data,但是我们不能再用edit函数了,所以这里采用的方法是释放掉chunk A,然后再申请回来,写入0x21这个size,同时还要写入ptr-0x18和ptr-0x10。
最终的unlink时布局如下:
emmm,只要是熟悉unlink的师傅,应该都能看懂上面这个布局,最后提一下这个fake chunk是打fastbin attack强行错位申请出来的。而为什么这个fake chunk的头必须要从0x603010开始,不能从0x603020开始?这是因为chunk B的地址是定死的,而它上面的内存单元必须是ptr-0x18和ptr-0x10,如果0x603020这个地址当做fake chunk head的话,那么0x603020这里应该是fake chunk的prev size,这样就不是ptr-0x18了,所以fake chunk必须在0x603010的地址开始。
然后打一个unlink,此时我们就可以控制bss段存放堆块的地址了,而此时我们还有两次执行edit函数的机会。由于我们在chunk B释放后执行show函数也得到了libc地址,因此我们直接用edit函数写一个free_hook的地址在bss段上,再edit函数往里写一个system的地址。最后free掉一个存有/bin/sh\x00字符串的堆块即可获取shell。
EXP:
from tools import * |