[heap] House of Orange 堆利用技巧
参考来源: https://wiki.x10sec.org/pwn/heap/house_of_orange/
(这里总结一下做个笔记)
0x00 背景
少数情况下不能直接控制free函数释放掉想要的堆块获得unsorted_chunk,需要用一种其它的方式获得一个unsorted_chunk,House Of Orange正是一种不用控制free从而获得释放堆块的堆利用技巧
使用条件
- 需要能够通过堆溢出或者其它什么方式,间接或直接控制Top Chunk的size域,改变其大小。
- 可以使用malloc请求分配自定义大小的堆块。
0x01 原理
触发条件
在分配新堆块时,_int_malloc依次检查 fastbin、small bins、unsorted bin、large bins是否可以满足分配要求,如果都不符合,将尝试从现有Top Chunk中分配。如果还不符合,那么ptmalloc就不再继续作用,而是使用sysmalloc向系统申请内存到用户区域。此时2原有的Top Chunk将会被置入unsorted_bin。
限制条件
该方法对修改Top Chunk的size域的值有一定的限制
源码:
if ((unsigned long)(nb) >= (unsigned long)(mp_.mmap_threshold) && (mp_.n_mmaps < mp_.n_mmaps_max))
assert((old_top == initial_top(av) && old_size == 0) ||
((unsigned long) (old_size) >= MINSIZE &&
prev_inuse(old_top) &&
((unsigned long)old_end & pagemask) == 0));
将这些限制总结起来就是:
分配大小限制:
- 分配的chunk大小小于128K(此时将使用brk拓展堆,否则将使用mmap)
- 分配的chunk大小应大于被修改后的Top Chunk大小减去 fencepost的大小
Top Chunk的size大小限制:
- 伪造的size必须要对齐到内存页 (堆块末尾地址16进制表示时后三位为0)
- size要大于MINSIZE(0x10)
- size要小于之后申请的chunk size + MINSIZE(0x10)
- size的prev inuse位必须为1
0x02 示例分析
示例
//example.cpp
//gcc example.cpp -g -o example;chmod +x example
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#define fake_size 0x1fe1
int main(void)
{
void *ptr;
ptr=malloc(0x10);
ptr=(void *)((long long int)ptr+0x18);
*((long long*)ptr)=fake_size;
malloc(0x2000); //into unsorted_bin
malloc(0x60);
}
相对于ctfwiki上的原文稍作了修改
接着用pwndbg调试
分析
初始状态:
0x602000 0x623000 rw-p 21000 0 [heap]
0x602000 FASTBIN { <-最开始分配的,为了完成堆的初始化
prev_size = 0,
size = 33,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x20fe1
}
0x602020 PREV_INUSE { <-最开始的Top Chunk
prev_size = 0,
size = 135137,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
修改Fake Size
pwndbg> heap
0x602000 FASTBIN {
prev_size = 0,
size = 33,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x1fe1
}
0x602020 PREV_INUSE { <-size已经被修改
prev_size = 0,
size = 8161,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
0x604000 {
prev_size = 0,
size = 0,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
malloc(0x2000) 之后
0x602000 FASTBIN {
prev_size = 0,
size = 33,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x1fc1
}
0x602020 PREV_INUSE { <-通过观察fd,bk发现原来的top chunk已经进入unsorted_bin
prev_size = 0,
size = 8129,
fd = 0x7ffff7dd1b78 <main_arena+88>,
bk = 0x7ffff7dd1b78 <main_arena+88>,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
0x603fe0 {
prev_size = 8128,
size = 16,
fd = 0x0,
bk = 0x11,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
0x603ff0 PREV_INUSE {
prev_size = 0,
size = 17,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
0x604000 {
prev_size = 0,
size = 0,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
0x602000 0x646000 rw-p 44000 0 [heap]
//堆地址相比于之前扩大了
malloc(0x60) 之后
pwndbg> heap
0x602000 FASTBIN {
prev_size = 0,
size = 33,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x71
}
0x602020 FASTBIN { <-从unsorted_bin中分割出来的chunk
prev_size = 0,
size = 113,
fd = 0x7ffff7dd2208 <main_arena+1768>,
bk = 0x7ffff7dd2208 <main_arena+1768>,
fd_nextsize = 0x602020,
bk_nextsize = 0x602020
}
0x602090 PREV_INUSE {
prev_size = 0,
size = 8017,
fd = 0x7ffff7dd1b78 <main_arena+88>,
bk = 0x7ffff7dd1b78 <main_arena+88>,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
0x603fe0 {
prev_size = 8016,
size = 16,
fd = 0x0,
bk = 0x11,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
0x603ff0 PREV_INUSE {
prev_size = 0,
size = 17,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
0x604000 {
prev_size = 0,
size = 0,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
0x03
这类利用一般是为了创造条件,比如结合IO_FILE进行下一步的攻击