二進制安全之堆溢出(系列)——堆基礎 & 結(jié)構(gòu)(四)
二進制安全之堆溢出(系列)——“堆基礎&結(jié)構(gòu)”第四節(jié)上回咱們聊到碎塊合并問題本次咱們從ulink講起

unlink
unlink用來將一個雙向鏈表bin鏈中的一個元素取出來,即斷鏈過程
引發(fā)unlink的幾種方式
malloc
從恰好大小合適的largebin中獲取chunk會unlink
fastbin和smallbin沒有使用unlink
依次遍歷unsorted bin時也沒有使用unlink
合并和切割的時候都會unlink
free
后向合并,合并物理相鄰低地址空閑chunk的時候會unlink
前向后并,合并物理相鄰高地址空閑chunk的時候會unlink(除了top chunk)
relloc
consolidate
unlink源碼分析
? ? /* Take a chunk off a bin list 用于將某一個空閑 chunk從其所處的bin中脫鏈*/
? ? #define unlink(AV, P, BK, FD) {? //P 即為待脫鏈的空閑 chunk? ? ? ? ? ? ? ? ? ? ? ? \
? ? if (__builtin_expect (chunksize(P) != prev_size (next_chunk(P)), 0))
? ? /*檢查一下其大小是否一致(size檢查)
? ? 故在做overlap的時候,偽造的堆塊的size需要和presize一致
? ? */
? ? malloc_printerr ("corrupted size vs. prev_size");? ? ? ? ? ? ? ?\
? ? FD = P->fd;? ? ? ? ?//FD為? ?P的前一個空閑chunk
? ? BK = P->bk;? ? ? ? ?//BK為p的后一個空閑chunk
? ? if (__builtin_expect (FD->bk != P || BK->fd != P, 0))
? ? /*承上檢查,檢查當前的p是否與兩邊相連
? ? */
? ? malloc_printerr ("corrupted double-linked list");
? ? else {? ? ? //設置相鄰 chunk 的 fd 或 bk 指針
? ? FD->bk = BK;
? ? BK->fd = FD;
? ? /*
? ? 可以在這里修改p的fd和bk
? ? p->fd = target? //修改fd
? ? p->bk = target? ? //修改bk
? ? 因此
? ? FD = target
? ? BK = target
? ? FD->bk = *(target + 0x18)? ?//prev_size + size +fd = 0x18
? ? BK->fd = *(target + 0x10)
? ? 上面的改法無法繞過FD->bk != P || BK->fd != P的檢查
? ? //TODO follow
? ? FD = target - 0x18? ? ? ? ? ? ? ?//自己控制堆塊修改值即可
? ? BK = target - 0x10
? ? FD->bk = *(target - 0x18 + 0x18) = BK = target - 0x10 = p
? ? BK->fd = *(target - 0x10 + 0x10) = FD = target - 0x18 = p
? ? 這樣就可以繞過當前的校驗
? ? payload = 0x18 *'a' + target_addr
? ? 構(gòu)造payload,替換target為got或任意地址
? ? */
? ? /*對于smallbin而言,以上脫鏈完成
? ? 下面處理largebin的脫鏈,多了fd/bk_nextsize的unlink過程
? ? */
? ? if (!in_smallbin_range (chunksize_nomask (P))
? ? && __builtin_expect (P->fd_nextsize != NULL, 0)) {
? ? //說明P是相應bins的第一個chunk,否則fd_nextsize和bk_nextsize沒有意義
? ? if (__builtin_expect (P->fd_nextsize->bk_nextsize != P, 0)
? ? || __builtin_expect (P->bk_nextsize->fd_nextsize != P, 0))? ? \
? ? malloc_printerr ("corrupted double-linked list (not small)");
? ? if (FD->fd_nextsize == NULL) { //p斷鏈之后,FD成為當前bins的第一個chunk
? ? if (P->fd_nextsize == P)? ? //只有唯一的chunk時
? ? FD->fd_nextsize = FD->bk_nextsize = FD;
? ? else {? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//正常斷鏈加鏈
? ? FD->fd_nextsize = P->fd_nextsize;
? ? FD->bk_nextsize = P->bk_nextsize;
? ? P->fd_nextsize->bk_nextsize = FD;
? ? P->bk_nextsize->fd_nextsize = FD;
? ? }
? ? } else {? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //p斷鏈之后,FD成為下一組bins的第一個chunk
? ? P->fd_nextsize->bk_nextsize = P->bk_nextsize;
? ? P->bk_nextsize->fd_nextsize = P->fd_nextsize;
? ? }
? ? }
? ? }
? ? }
泄露libc的地址
P位于雙向鏈表頭部,bk泄露P位于雙向鏈表尾部,fd泄露雙向鏈表中只包含一個空閑chunk時,P位于雙向鏈表中,fd和bk均可泄露tips:這里的頭部指的是bin的fd指向的chunk,即雙向鏈表中最新加入的chunk,反之亦然
實例分析

斷鏈的目標:p ,p之后需要有一個已經(jīng)free的堆塊覆蓋p->fd = target - 0x18 p->bk = target - 0x10,注意此時的fd和bk都是地址的值
?target 為堆中的任意堆塊的地址的值,前提是可以通過heap_base + offset 獲得地址現(xiàn)在假設target為note2,note2的地址為heap_base+0x60,則target需要填heap_base+0x60
當free p的時候,就會和之后的空閑堆塊發(fā)生合并,從而引發(fā)unlink此時按順序斷鏈 *(p->fd->bk)= bk,*(p->bk->fd) = fd,即最終實現(xiàn)*(target)=target-0x18
?p->fd->bk的內(nèi)容為bk的值,故`*(p->fd->bk)= bk`p->bk->fd的內(nèi)容為bk的值,故`*(p->bk->fd)= fd`最終結(jié)果為第二條語句的執(zhí)行結(jié)果這時前面的target為指針,上述結(jié)果相當于target指向了target-0x18的地址空間
此時我們向target里面寫入0x18 * 'a',就相當于指針target+0x18指向了target起始的地址緊接著寫入malloc_hook的地址,然后再edit target,寫入system的地址,就相當于target+0x18+0x8指向了target+0x8的地址空間此時就相當于*(malloc_hook) = system ,再次malloc的時候就會調(diào)用system了。
調(diào)試
源代碼一
? #include<stdio.h>
? ? #include<malloc.h>
? ? #include<unistd.h>
? ? #include<string.h>
? ? int main(){
? ? int size = 0x70;
? ? void *p = malloc(size);
? ? void *q = malloc(size);
? ? void *junk = malloc(size);
? ? sleep(0);
? ? free(q);
? ? sleep(0);
? ? printf("%p\n",q);
? ? int *r = malloc(0x60);
? ? printf("%p\n",r);
? ? sleep(0);
? ? return 0;
堆塊分配后的heap與內(nèi)存布局
?0x602000 FASTBIN {? ===>chunk1
? ? prev_size = 0,
? ? size = 129,
? ? fd = 0x0,
? ? bk = 0x0,
? ? fd_nextsize = 0x0,
? ? bk_nextsize = 0x0
? ? }
? ? 0x602080 FASTBIN {? ===>chunk2
? ? prev_size = 0,
? ? size = 129,
? ? fd = 0x0,
? ? bk = 0x0,
? ? fd_nextsize = 0x0,
? ? bk_nextsize = 0x0
? ? }
? ? 0x602100 FASTBIN {? ===>chunk3
? ? prev_size = 0,
? ? size = 129,
? ? fd = 0x0,
? ? bk = 0x0,
? ? fd_nextsize = 0x0,
? ? bk_nextsize = 0x0
? ? }
? ? 0x602180 PREV_INUSE {
? ? prev_size = 0,
? ? size = 134785,? ? ? ? ? ? ===>top_chunk
? ? fd = 0x0,
? ? bk = 0x0,
? ? fd_nextsize = 0x0,
? ? bk_nextsize = 0x0
? ? }
? ? }
---------------------------------------------------------------------------------------------------------------------------
?0x602000:? ? ? ?0x0000000000000000? ? ? 0x0000000000000081 <=== chunk1
? ? 0x602010:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602020:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602030:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602040:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602050:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602060:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602070:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602080:? ? ? ?0x0000000000000000? ? ? 0x0000000000000081 <=== chunk2
? ? 0x602090:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x6020a0:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x6020b0:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x6020c0:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x6020d0:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x6020e0:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x6020f0:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602100:? ? ? ?0x0000000000000000? ? ? 0x0000000000000081? <=== chunk3
? ? 0x602110:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602120:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602130:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602140:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602150:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602160:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602170:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602180:? ? ? ?0x0000000000000000? ? ? 0x0000000000020e81? <=== top chunk
? ? 0x602190:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x6021a0:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x6021b0:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x6021c0:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x6021d0:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
free(q)之后的heap與內(nèi)存布局
?0x602000 FASTBIN {
? ? ? prev_size = 0,
? ? ? size = 129,
? ? ? fd = 0x0,
? ? ? bk = 0x0,
? ? ? fd_nextsize = 0x0,
? ? ? bk_nextsize = 0x0
? ? }
? ? 0x602080 FASTBIN {
? ? ? prev_size = 0,
? ? ? size = 129,
? ? ? fd = 0x7ffff7dd1be8 <main_arena+200>,
? ? ? bk = 0x7ffff7dd1be8 <main_arena+200>,
? ? ? fd_nextsize = 0x0,
? ? ? bk_nextsize = 0x0
? ? }
? ? 0x602100 FASTBIN {
? ? ? prev_size = 128,
? ? ? size = 129,
? ? ? fd = 0x0,
? ? ? bk = 0x0,
? ? ? fd_nextsize = 0x0,
? ? ? bk_nextsize = 0x0
? ? }
? ? 0x602180 PREV_INUSE {
? ? ? prev_size = 0,
? ? ? size = 1041,
? ? ? fd = 0x3039303230367830,
? ? ? bk = 0xa,
? ? ? fd_nextsize = 0x0,
? ? ? bk_nextsize = 0x0
? ? }
? ? 0x602590 PREV_INUSE {
? ? ? prev_size = 0,
? ? ? size = 133745,
? ? ? fd = 0x0,
? ? ? bk = 0x0,
? ? ? fd_nextsize = 0x0,
? ? ? bk_nextsize = 0x0
? ? }
---------------------------------------------------------------------------------------------------------------------------
?0x602000:? ? ? ?0x0000000000000000? ? ? 0x0000000000000081
? ? 0x602010:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602020:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602030:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602040:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602050:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602060:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602070:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602080:? ? ? ?0x0000000000000000? ? ? 0x0000000000000081? ==>chunk未發(fā)生變化
? ? 0x602090:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x6020a0:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x6020b0:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x6020c0:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x6020d0:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x6020e0:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x6020f0:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602100:? ? ? ?0x0000000000000000? ? ? 0x0000000000000081
? ? 0x602110:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602120:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602130:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602140:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602150:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602160:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602170:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602180:? ? ? ?0x0000000000000000? ? ? 0x0000000000020e81
? ? //此時free掉的chunk_size為81的原因 :free掉了,但沒有把指針置空,第二個堆塊變成空閑堆塊,由bins鏈管理,chunk_size依然為0x80
此時的bins鏈
fastbins
? ? 0x20: 0x0
? ? 0x30: 0x0
? ? 0x40: 0x0
? ? 0x50: 0x0
? ? 0x60: 0x0
? ? 0x70: 0x0
? ? 0x80: 0x602080 ?— 0x0? ? ? ? ? ?==》被釋放的chunk進入了fastbin鏈
? ? unsortedbin
? ? all: 0x0
? ? smallbins
? ? empty
? ? largebins
? ? empty
分配新的0x60的chunk后的heap和內(nèi)存布局
0x602000 FASTBIN {
? ? ? prev_size = 0,
? ? ? size = 129,
? ? ? fd = 0x0,
? ? ? bk = 0x0,
? ? ? fd_nextsize = 0x0,
? ? ? bk_nextsize = 0x0
? ? }
? ? 0x602080 FASTBIN {? ? ===>chunk2被切割出0x70的空間,剩下的0x10自動和top_chunk合并
? ? ? prev_size = 0,
? ? ? size = 129,
? ? ? fd = 0x7ffff7dd1be8 <main_arena+200>,
? ? ? bk = 0x7ffff7dd1be8 <main_arena+200>,
? ? ? fd_nextsize = 0x0,
? ? ? bk_nextsize = 0x0
? ? }
? ? 0x602100 {
? ? ? prev_size = 128,? ? ? //說明上一個chunk被free掉了,大小為0x80
? ? ? size = 128,
? ? ? fd = 0x0,
? ? ? bk = 0x0,
? ? ? fd_nextsize = 0x0,
? ? ? bk_nextsize = 0x0
? ? }
? ? 0x602180 PREV_INUSE {? ?//printf的緩沖區(qū)堆塊 ,從top_chunk中分配,多個printf分配一個chunk
? ? ? prev_size = 0,
? ? ? size = 1041,
? ? ? fd = 0x3039303230367830,? ? ??
? ? ? bk = 0xa,
? ? ? fd_nextsize = 0x0,
? ? ? bk_nextsize = 0x0
? ? }
? ? 0x602590 PREV_INUSE {
? ? ? prev_size = 0,
? ? ? size = 133745,
? ? ? fd = 0x0,
? ? ? bk = 0x0,
? ? ? fd_nextsize = 0x0,
? ? ? bk_nextsize = 0x0
? ? }
---------------------------------------------------------------------------------------------------------------------------
0x602000:? ? ? ?0x0000000000000000? ? ? 0x0000000000000081
? ? 0x602010:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602020:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602030:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602040:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602050:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602060:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602070:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602080:? ? ? ?0x0000000000000000? ? ? 0x0000000000000081? ==>重新組裝的chunk2
? ? 0x602090:? ? ? ?0x00007ffff7dd1be8? ? ? 0x00007ffff7dd1be8? ==>fd和bk指向main_arena的地址
? ? 0x6020a0:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x6020b0:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x6020c0:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x6020d0:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x6020e0:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x6020f0:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602100:? ? ? ?0x0000000000000080? ? ? 0x0000000000000081
? ? 0x602110:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602120:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602130:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602140:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602150:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602160:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602170:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x602180:? ? ? ?0x0000000000000000? ? ? 0x0000000000000411
? ? 0x602190:? ? ? ?0x3039303230367830? ? ? 0x000000000000000a
? ? 0x6021a0:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x6021b0:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x6021c0:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
? ? 0x6021d0:? ? ? ?0x0000000000000000? ? ? 0x0000000000000000
此時的bins鏈
fastbins
? ? 0x20: 0x0
? ? 0x30: 0x0
? ? 0x40: 0x0
? ? 0x50: 0x0
? ? 0x60: 0x0
? ? 0x70: 0x0
? ? 0x80: 0x0
? ? unsortedbin
? ? all: 0x0
? ? smallbins
? ? 0x80: 0x602080 —? 0x7ffff7dd1be8 (main_arena+200) ?— 0x602080
? ? largebins
? ? empty
源代碼二
#include<stdio.h>
#include<malloc.h>
#include<unistd.h>
#include<string.h>
int main(int argc,char *argv[])
{
? ? ?int size = 0x100;
? ? ?void *p = malloc(size);
? ? ?void *junk = malloc(size);? ? ?//創(chuàng)建以junk防止釋放p,q時q的prev_inuse為0而合并
? ? ?void *q = malloc(size);
? ? ?void *r = malloc(size);? ? ? ? ? //防止q和top_chunk合并,在沒有printf的前提下
? ? ?sleep(0);
? ? ?printf("p:0x%x\n",p);
? ? ?printf("q:0x%x\n",q);
? ? ?printf("r:0x%x\n",r);
? ? ?sleep(0);
? ? ?strcpy(p,"aaaaaaaaaaaaaaaaa");
? ? ?strcpy(q,"bbbbbbbbbbbbbbbbb");
? ? ?strcpy(r,"ccccccccccccccccc");
? ? ?sleep(0);
? ? ?free(p);
? ? ?free(q);
? ? ?sleep(0);
? ?return 0;
}
在不創(chuàng)建junc和r的情況下,p,q以及p,q,top_chunk會發(fā)生合并
#include<stdio.h>
#include<malloc.h>
#include<unistd.h>
#include<string.h>
int main(int argc,char *argv[])
{
? ? ?int size = 0x100;
? ? ?void *p = malloc(size);
? ? ?void *q = malloc(size);
? ? ?sleep(0);
? ? ?strcpy(p,"aaaaaaaaaaaaaaaaa");
? ? ?strcpy(q,"bbbbbbbbbbbbbbbbb");
? ? ?free(p);
? ? ?free(q);
? ? ?sleep(0);
? ?return 0;
}
---------------------------------------------------------------------------------------------------------------------------
0x602000 PREV_INUSE {? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?===>p、q合并
? prev_size = 0,?
? size = 545,?
? fd = 0x7ffff7dd1b78 <main_arena+88>,? ===>fd指向main_arena
? bk = 0x7ffff7dd1b78 <main_arena+88>,? ===>bk指向main_arena
? // 因為當前只有一個main_arena只管理一個合并之后的堆塊了
? fd_nextsize = 0x61,?
? bk_nextsize = 0x0
}
0x602220 {
? prev_size = 544,?
? size = 1040,?
? fd = 0x3132303678303a71,? ? ? ? ? ? ? ? ? ? ? ? ? ===>print
? bk = 0xa3032,?
? fd_nextsize = 0x0,?
? bk_nextsize = 0x0
}
0x602630 PREV_INUSE {
? prev_size = 0,?
? size = 133585,?
? fd = 0x0,?
? bk = 0x0,?
? fd_nextsize = 0x0,?
? bk_nextsize = 0x0
}?
此時的bins鏈
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x602000 —? 0x7ffff7dd1b78 (main_arena+88) ?— 0x602000 ==>只有一個合并之后的堆塊
smallbins
empty
largebins
empty
(main_arena+88)的原因
main_arena的結(jié)構(gòu)體前項變量:
__libc_lock_define (, mutex);? ? ? ?//定義了一個0x4字節(jié)的lock
int flags;? ? ? ? ? ? ? ? ? ? ? //0x4
int have_fastchunks;? ? ? ? ? ? ? ? //0x4
mfastbinptr fastbinsY[NFASTBINS]; //fastbin鏈的管理頭,總共10個, 每個0x10字節(jié)
mchunkptr top;? ? ? //0x4 到此為止總共0x96字節(jié)
注:glibc2.27為0x96
vmmap查看到(main_arena+88)出現(xiàn)在libc的地址范圍
0x7ffff7dd1000 0x7ffff7dd3000 rw-p 2000 1c4000 /lib/x86_64-linux-gnu/libc-2.23.so
相同版本的libc,main_arena的偏移固定
main_arena的地址存放在0x602000中
pwndbg> x/20gz 0x602000
0x602000:? ?0x0000000000000000? 0x0000000000000221
0x602010:? ?0x00007ffff7dd1b78? 0x00007ffff7dd1b78
利用方法
overlap --> 打印當前堆塊的內(nèi)容 --> 獲取main_arena的地址 --> 通過固定的偏移計算出libc的地址
當size大于0x400的時候,free之后的堆塊首先會進入unsorted bin,觸發(fā)整理后才會進入large bin
free掉0x400以上的堆塊后,再malloc一個堆塊,才會觸發(fā)整理,進入到large bin如在源碼二的最后加上malloc(0x2000),并把size改為0x1000
#include<stdio.h>
?#include<malloc.h>
?#include<unistd.h>
?#include<string.h>
?int main(int argc,char *argv[])
{
? ? ? int size = 0x1000;
? ? ? void *p = malloc(size);
? ? ? void *junk = malloc(size);
? ? ? void *q = malloc(size);
? ? ? void *r = malloc(size);
? ? ? sleep(0);
? ? ? printf("p:0x%x\n",p);
? ? ? printf("q:0x%x\n",q);
? ? ? printf("r:0x%x\n",r);
? ? ? strcpy(p,"aaaaaaaaaaaaaaaaa");
? ? ? strcpy(q,"bbbbbbbbbbbbbbbbb");
? ? ? strcpy(r,"ccccccccccccccccc");
? ? ? free(p);
? ? ? free(q);
? ? ? sleep(0);
? ? ? malloc(0x2000);
? ? ? sleep(0);? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ?return 0;
? ? ? ? }?
此時fd_nextsize和bk_nextsize有效
0x602000 PREV_INUSE {
? prev_size = 0,?
? size = 4113,?
? fd = 0x604020,?
? bk = 0x7ffff7dd2198 <main_arena+1656>,?
? fd_nextsize = 0x602000,?
? bk_nextsize = 0x602000
}
未malloc(2000)當前的bins鏈
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x604020 —? 0x602000 —? 0x7ffff7dd1b78 (main_arena+88) ?— 0x604020 /* ' @`' */
smallbins
empty
largebins
empty
malloc(0x2000)的bins鏈
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
0x1000: 0x602000 —? 0x604020 —? 0x7ffff7dd2198 (main_arena+1656) ?— 0x602000
對于新malloc的堆塊大小,有這幾種情況
0-0x999
0x1000-0x1008
0x1009以上

當size小于0x80的時候,free后會進入到fastbin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x6020e0 —? 0x602000 ?— 0x0? ?//p , q都進入fastbin
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty
當malloc(0x60)的新chunk時,會首先從后free的0x6020e0中分配空間,分配之后,0x6020e0退出fastbin
0x70: 0x602000 ?— 0x0
源代碼三
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<pthread.h>
void* threadFunc(void* arg)
{
? int size = 0x200;
? sleep(0);
? void *q = malloc(size);
? printf("%p\n",q);
? sleep(0);
? free(q);
? sleep(0);
}
int main(int argc,char *argv[])
{
? ? int size = 0x100;
? void *p = malloc(size);
? free(p);
? pthread_t t1;
? void *s;
? int ret;
? ret = pthread_create(&t1,NULL,threadFunc,NULL);
? ? ret = pthread_join(t1,&s);
? return 0;
}
子線程的堆空間
pwndbg> c
Continuing.
0x7ffff00008c0? ? ? ? ==>第一個堆塊
pwndbg>vmmap
?0x602000? ? ? ? ? ?0x623000 rw-p? ? 21000 0? ? ? [heap]
? ? 0x7ffff0000000? ? ?0x7ffff0021000 rw-p? ? 21000 0?
? ? 0x7ffff0021000? ? ?0x7ffff4000000 ---p? 3fdf000 0? ? ?
? ?0x7ffff6fef000? ? ?0x7ffff6ff0000 ---p? ? ?1000 0?
查看內(nèi)存布局
pwndbg> x/20gz 0x7ffff00008c0 -0x10
0x7ffff00008b0:? 0x0000000000000000? 0x0000000000000215? ?NO_MAIN_ARENA & PREV_INUSE = 5
0x7ffff00008c0:? 0x0000000000000000? 0x0000000000000000
0x7ffff00008d0:? 0x0000000000000000? 0x0000000000000000
0x7ffff00008e0:? 0x0000000000000000? 0x0000000000000000
偏移查看arena結(jié)構(gòu)
pwndbg> x/100gz 0x7ffff00008c0 -0x10 + 0x200
0x7ffff0000ab0:? 0x0000000000000000? 0x0000000000000000
0x7ffff0000ac0:? 0x0000000000000000? 0x0000000000000415? ? ==>第二個堆塊,分配了0x410的空間
0x7ffff0000ad0:? 0x3066666666377830? 0x000a306338303030? ? ?==>printf的堆塊
0x7ffff0000ae0:? 0x0000000000000000? 0x0000000000000000
pwndbg> x/s 0x7ffff0000ad0
0x7ffff0000ad0:? "0x7ffff00008c0\n"
pwndbg> x/20gz 0x7ffff00008c0 -0x10 + 0x200 + 0x420
0x7ffff0000ed0:? 0x0000000000000000? 0x0000000000020131? ? ?==>子線程的top_chunk
0x7ffff0000ee0:? 0x0000000000000000? 0x0000000000000000
free掉q之后NO_MAIN_ARENA置0
pwndbg> x/20gz 0x7ffff00008c0 -0x10?
0x7ffff00008b0: 0x0000000000000000? 0x0000000000000211
0x7ffff00008c0: 0x00007ffff0000078? 0x00007ffff0000078? ? ? ==> 類似于主線程的main_arena + 88
pwndbg> x/20gz 0x00007ffff0000078
0x7ffff0000078: 0x00007ffff0000ed0? 0x0000000000000000? ? ==> 子線程的top_chunk
0x7ffff0000088: 0x00007ffff00008b0? 0x00007ffff00008b0? ? ==> 子線程的第一個堆塊
0x7ffff0000098: 0x00007ffff0000088? 0x00007ffff0000088?
0x7ffff00000a8: 0x00007ffff0000098? 0x00007ffff0000098? ??
0x7ffff00000b8: 0x00007ffff00000a8? 0x00007ffff00000a8
0x7ffff00000c8: 0x00007ffff00000b8? 0x00007ffff00000b8
0x7ffff00000d8: 0x00007ffff00000c8? 0x00007ffff00000c8
0x7ffff00000e8: 0x00007ffff00000d8? 0x00007ffff00000d8
0x7ffff00000f8: 0x00007ffff00000e8? 0x00007ffff00000e8
0x7ffff0000108: 0x00007ffff00000f8? 0x00007ffff00000f8
//此這里可以leak main_arena的結(jié)構(gòu)
實驗總結(jié)
main_arena為主線程的arena
在第一次調(diào)用malloc之后,會用brk調(diào)用生成堆,并生成top_chunk之后分配的堆,都會從top_chunk上切割當top_chunk不夠用時,會再次通過brk系統(tǒng)調(diào)用申請內(nèi)存副線程的arena通過mmap獲得,并也會生成top_chunk
好了,到這兒,二進制安全之堆溢出(系列)——堆基礎 & 結(jié)構(gòu)就更完了??!
