Unsorted Bin Attack:非常常用,用来绕过aslr
首先,Unsorted bin是FIFO的。后放入的会插在队头(离main arena最近的一端,一定要区分这个),取chunk的时候会从尾部(离main arena较远的一端)取出;但unsorted bin是一个双向循环链表,严格来说没有头尾之分,这里按下面这张图的格式方便记忆。
!(unsorted_bin)[/images/unsorted_bin.jpg]
所谓的main arena指的其实是struct malloc_state main_arena.bins[0,1]
(见How2Heap-3),64位系统下应该是指向main_arena+96。通过这个攻击我们能将这个数写在我们想要的地址,常用来篡改某些关键字段的数据(如top chunk的size)。而且这个数和libc基址的偏移是固定的,泄露这个数可以用来绕过aslr,因此这个手法很常用。
Unsorted Bin Leak
这里没有什么特定的技巧,用UAF将已经放在Unsorted Bin中的chunk内容打印泄露其fd即可,同时如果unsorted bin中只有一个chunk,fd和bk都会指向main_arena+96。
打出这个值之后获取和libc基址的偏移,参考ctf wiki有两种获取libc基址的方法,一是通过IDA分析libc文件,找到malloc_trim
函数,里面会有访问main_arena的位置,可以直接获取。
二是借助__malloc_hook()
函数进行计算,这种方法比较方便。malloc_state和__malloc_hook的地址差是0x10,然后直接在libc中进行查找就行:
1 | main_arena_offset = ELF("libc.so.6").symbols["__malloc_hook"] + 0x10 |
Unsorted Bin Attack 原理
这个漏洞得以实现是因为_int_malloc
中有这样一段:
1 | /* remove from unsorted list */ |
unsorted_chunks(av)
是宏bin_at(M,1)
。也就是说,控制victim的bk,在将victim从chunk中取出的时候,bk地址就会被写入malloc_state.bin[1]
这样的大地址。
在直接从Unsorted Bin中取处chunk的时候,malloc并不使用victim的fd,所以随便改没有检查。但是要注意的是,进行一次攻击后unsorted bin的链表头会被破坏,后续我们就无法再从unsorted bin中取chunk了。
1 | while ((victim = unsorted_chunks(av)->bk) != unsorted_chunks(av)) { |
POC
1 |
|
流程很简单,只要一个UAF就能实现任意地址写大数。注意劫持bk要写入target_addr-0x10,即target_addr在一个假chunk(甚至都没有伪造,某种意义上是一个“幻象”chunk/“影子”chunk)的fd处。
House of Lore:针对small bin的任意地址分配chunk攻击
思想很简单,想办法绕过源码中对于smallbin的检查即可。即控制一个smallbin大小chunk的bk指向我们的目标地址,然后让这个fake_chunk的fd指向这个small chunk(也就是malloc只检查 bck -> fd =? victim,如果不等就报错退出)。接着把我们的small chunk取出来,下一次malloc堆块就会分配在我们想要的位置了。smallbin是FIFO结构,新加入的chunk会插在bin数组索引紧邻的位置。
how2heap给我们的代码是将chunk分配在了栈上,而且最后shellcode执行告诉我们会破坏canary。在看到没有开canary的堆题的时候可以考虑这个攻击。
poc
1 | void jackpot(){ puts("Nice jump d00d"); exit(0); } |