House Of Force
本文最后更新于 2025年12月30日 凌晨
参考
前置知识
malloc请求大小与实际大小
- 请求大小我们用
req来标识 - 实际大小我们用
nb来标识 - malloc(req)后req会转为无符号型整数
- void *__libc_malloc(size_t bytes)
- 请求大小与实际大小的转换
- REQUEST_OUT_OF_RANGE(req)越界检查
- request2size(req)实现转换
1 | |
REQUEST_OUT_OF_RANGE(req)越界检查
越界检查很好理解,就是我们
req的大小不能大于(unsigned long) (INTERNAL_SIZE_T)(-2 * MINSIZE)(unsigned long) (INTERNAL_SIZE_T)(-2 * MINSIZE)
- x86_32:MINSIZE = 0x10 所以边界为 0xffffffe0
- x86_64:MINSIZE = 0x20 所以边界为 0xffffffffffffffc0
也就是说我们的req要小于边界大小即可
request2size(req)实现转换
核心
- MINSIZE:最小堆的大小
- prev_size
- size
- fd
- bk
- MALLOC_ALIGN_MASK:用来对齐的
x86_64下对齐0x10x86_32下对齐0x8,也可以称为对齐冗余 - SIZE_SZ:size字段的大小
- 为什么没有prev_size呢,因为在实际chunk中prev_size是归属于物理相邻的低地址chunk的
1 | |
转换流程
- malloc(req)
- nb = MINSIZE : ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)
举个例子[x86_64]
正数
req = 0x10
(req) + SIZE_SZ + MALLOC_ALIGN_MASK = 0x27 > MINSIZE
那么nb = 0x20 [((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)]
负数
req = -0x10
-0x10 > -0x40[-2 * MINSIZE] –> 拒绝申请
req = -0x60 == 0xffffffffffffffa0
-0x60 < -0x40[-2 * MINSIZE]
(req) + SIZE_SZ + MALLOC_ALIGN_MASK = 0xffffffffffffffb7 > MINSIZE
nb = 0xffffffffffffffb0 [((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)]
可以看到req和nb之间的差别在于SIZE_SZ + 对齐
那么我们要求req == nb呢(这个很重要,关乎于我们控制top_chunk)
只要提前 - (SIZE_SZ + MALLOC_ALIGN_MASK),并保证对齐即可
malloc(req)与top_chunk
给出场景top_chunk = 0x3955020

req = 0x10[Add(0x10)];nb = 0x20
top_chunk = 0x3955040
0x3955040 - 0x3955020 = 0x20 == nb

那么也就是说当我们malloc(req)的时候top_chunk -= nb
Exploit条件
- 能够以溢出等方式控制到 top chunk 的 size 域
- 能够自由地控制堆分配尺寸的大小
top_chunk的地址存放在main_arena+0x58(88)上,也就是我们Unsorted bin leak出来的地址
无Top chunk
通过req来控制我们Top chunk的位置
- malloc(req)
- nb = request2size(req):依据需求对req进行手动转换nb,避免更新Top chunk地址错误
- Top chunk -= nb
局限
- Top chunk的地址不可控
知晓Top chunk
通过计算Top chunk与目标地址(Tag_Address), 实现在目的地址附近创建堆块
offset = Tag_Address - Top chunk - (SIZE_SZ * 2)
- (SIZE_SZ * 2) : 预留
prev_sizesizemalloc(offset):依据需求对offset进行手动转换nb,避免更新Top chunk地址错误
- 注意
size域会被更新malloc(req):获取Tag_Address堆块