先把知识点刷完,然后做题练习,加油orz
参考
原理
House of Force的使用,主要是跟top chunk相关。通过修改top chunk的size为一个很大的值(-1),然后通过malloc修改top chunk指针的位置,从而实现任意地址任意写。
在glibc中,会对用户请求的大小和top chunk的size进行验证
1 | // 获取当前的top chunk,并计算其对应的大小 |
如果能把size改成一个很大的值,这样就能轻松通过验证。一般来说会把top chunk的size改成-1,因为比较是无符号数的比较,因此-1就是最大的unsigned long的值。
1 | remainder = chunk_at_offset(victim, nb); |
通过验证以后,top chunk的指针就会更新,这样接下来申请的堆块就会分配到这个位置。即用户如果控制了av->top
这个指针,就能实现任意地址任意写。
同时,top chunk的size也会更新
1 | victim = av->top; |
所以在进行分配的时候,需要计算号remainder_size的值,要确保其大于下次分配的大小+MINSIZE。
在修改好top chunk的size之后,接下来的malloc就是为了修改top chunk的指针指向想要改写的位置。
对于用户分配大小的计算
1 | /* |
首先要先通过REQUEST_OUT_OF_RANGE(req)
这个检测,即我们传给malloc的值在负数范围内,不得大于-2*MINSIEZ
,这个一般都是可以满足的。
同时,我们需要使得request2size正好转换为对应的大小,也就是使得((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK
正好我们想要的大小。
还有就是,在top chunk被修改的同时,其目标位置附近的内容也会被修改。
1 | set_head(victim, nb | PREV_INUSE | |
总结
House of Force的利用条件还是很苛刻的。
- 需要存在一些漏洞来控制top chunk的size域
- 需要用户能够自定义malloc分配的大小
- 分配的次数不能够限制
一般来说,程序都会控制malloc分配的上下限。所以条件还是很麻烦滴。
栗子
一个例子
1 |
|
这个程序目标是修改malloc@got.plt,已知malloc@got.plt在0x601028处,在分配完第一个chunk之后,内存如下
1 | 0x602000: 0x0000000000000000 0x0000000000000021 |
修改后
1 | 0x602000: 0x0000000000000000 0x0000000000000021 |
可以看到top chunk的位置在0x602020处,这样我们计算偏移的时候为(0x601028-0x10) - 0x602020 - 0x10。然后进行malloc。在这次malloc之前,可以看到top chunk的位置还是正常的
1 | 0x7ffff7dd1b20 <main_arena>: 0x0000000100000000 0x0000000000000000 |
在malloc之后,top chunk的位置已经修改了
1 | 0x7ffff7dd1b20 <main_arena>: 0x0000000100000000 0x0000000000000000 |
这样,下一次分配出来的地址,就是目标地址了(可能有一点出入,因为对齐的缘故)。
1 | RAX 0x601020 (_GLOBAL_OFFSET_TABLE_+32) —▸ 0x7ffff7a91130 (malloc) ◂— push rbp |
可以看到分配出来的chunk已经是0x601020了,这样就能修改malloc@got.plt了。
利用House of Force,不仅可以放低top chunk,也可以太抬高,只是计算的偏移有所不同而已。
题目
[咕咕咕]