我是传送门:
pwn_wiki_fastbinattackFastbin Attack - CTF Wiki (ctf-wiki.org)
how2heap GitHub - shellphish/how2heap: A repository for learning various heap exploitation techniques.
bin结构
struct malloc_chunk {
/* #define INTERNAL_SIZE_T size_t */
INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */
INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */
struct malloc_chunk* fd; /* 这两个指针只在free chunk中存在*/
struct malloc_chunk* bk;
/* Only used for large blocks: pointer to next larger size. */
struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */
struct malloc_chunk* bk_nextsize;
};
当使用状态下,fd,bk无。
默认情况下大小为16到80字节的chunk被分类到fast chunk,按照8字节递增。大小固定。
Double Free
字面意思,free同一个chunk两次。
同一chunk不能直接连续free两次,会报异常,因此采用中间夹一个绕过。
对已malloc的chunk我们分别命名为1,2.
依次free1,free2,free1会产生如下效果
fastbin采用LIFO单链表方式以fd连接,最新free的chunk会放到链表尾,main_arena指向它,其fd指向原链表尾。
利用:完成上述后malloc(chunk1),再篡改fd,则能够实现任意地址分配堆块的效果 (首先要通过验证),这就相当于任意地址写任意值的效果。
验证:_int_malloc 会对欲分配位置的 size 域进行验证,如果其 size 与当前 fastbin 链表应有 size 不符就会抛出异常。
House Of Spirit
伪造fastbin大小的chunk。
除chunk通用结构外需满足
1.fake chunk 的 ISMMAP 位不能为 1,因为 free 时,如果是 mmap 的 chunk,会单独处理。
2.fake chunk 地址需要对齐, MALLOC_ALIGN_MASK
32位程序的话fake_chunk的prev_size所在地址就应该位0xXXXX0
或0xXXXX4
。64位的话地址就应 该在0xXXXX0
或0xXXXX8
3.fake chunk 的 size 大小需要满足对应的 fastbin 的需求,同时也得对齐。
4.fake chunk 的 next chunk 的大小不能小于 2 * SIZE_SZ
,同时也不能大于av->system_mem
。
fake_chunk 的大小,大小必须是 2 * SIZE_SZ 的整数倍。如果申请的内存大小不是 2 * SIZE_SZ 的整数倍,会被转换满足大小的最小的 2 * SIZE_SZ 的倍数。32 位系统中,SIZE_SZ 是 4;64 位系统中,SIZE_SZ 是 8。最大不能超过av->system_mem,即128kb。next_chunk的 大小一般我们会设置成为一个超过fastbin最大的范围的一个数,但要小雨128kb,这样做的目的 是在chunk连续释放的时候,能够保证伪造的chunk在释放后能够挂在fastbin中main_arena的前 面,这样以来我们再一次申请伪造chunk大小的块时可以直接重启伪造chunk
5.fake chunk 对应的 fastbin 链表头部不能是该 fake chunk,即不能构成 double free 的情况。
以数组构造的方式为例
unsigned long long fake_chunks[10] __attribute__ ((aligned (16)));
fake_chunks[1] = 0x40; // this is the size
fake_chunks[9] = 0x1234; // nextsize
[0]为prev_size,[1]为size(隐藏ismmap为0)0-7正好为0x40个字节
Alloc to Stack
修改fd指向构造好的栈,从而实现对栈的修改。与前面区别在于修改fd。
示例
typedef struct _chunk
{
long long pre_size;
long long size;
long long fd;
long long bk;
} CHUNK,*PCHUNK;
int main(void)
{
CHUNK stack_chunk;
void *chunk1;
void *chunk_a;
stack_chunk.size=0x21;
chunk1=malloc(0x10);
free(chunk1);
*(long long *)chunk1=&stack_chunk;
malloc(0x10);
chunk_a=malloc(0x10);
return 0;
}
Arbitrary Alloc
Arbitrary Alloc 其实与 Alloc to stack 是完全相同的,唯一的区别是分配的目标不再是栈中。 事实上只要满足目标地址存在合法的 size 域(这个 size 域是构造的,还是自然存在的都无妨),我们可以把 chunk 分配到任意的可写内存中,比如 bss、heap、data、stack 等等。