最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

二進制安全之堆溢出(系列)——堆基礎 & 結構(二)

2020-03-25 17:25 作者:匯智知了堂  | 我要投稿

哈嘍啊這里是知了堂禁衛(wèi)實驗室

今天知了姐給大家搬來《二進制安全之堆溢出(系列)第二期“堆基礎 & 結構”第二節(jié)》!!

?話不多說,直接上干貨!


? ? 微觀結構


? ? 函數(shù)執(zhí)行流程


? ? void *malloc (size_t bytes)


? ? void *__libc_malloc (size_t bytes) //對于_int_malloc做簡單封裝


? ? __malloc_hook? //類似于虛函數(shù),派生接口,指定一個malloc的方式


? ? _int_malloc(mstate av, size_t bytes) //申請內存塊的核心


? ? main_arena


? ? 集中管理bins鏈的結構體,使用含fd和bk的bin頭一對一管理各個free的chunk


? ? 分釋放配堆塊是基于main_arena來尋址的,首先找的是fastbin,其次再找bins


? ? main_arena存儲在libc上,用以管理所有bins的頭和尾,每個bins鏈頭的fd和尾的b與之連接


? ? struct malloc_state


? ? {


? ? /* Serialize access. */


? ? __libc_lock_define (, mutex);//定義了一個0x4字節(jié)的lock


? ? /* Flags (formerly in max_fast). */


? ? int flags;//0x4


? ? /* Set if the fastbin chunks contain recently inserted free blocks. */


? ? /* Note this is a bool but not all targets support atomics on booleans. */


? ? int have_fastchunks;//0x4


? ? /* Fastbins */


? ? mfastbinptr fastbinsY[NFASTBINS]; //fastbin鏈的管理頭,總共10個, 每個0x10字節(jié)


? ? /* Base of the topmost chunk -- not otherwise kept in a bin */


? ? mchunkptr top;//0x4 到此為止總共0x96字節(jié)


? ? /* The remainder from the most recent split of a small request */


? ? mchunkptr last_remainder;? ? ? ? //切割后剩下的chunk鏈接到last_remainder


? ? /* Normal bins packed as described above */


? ? mchunkptr bins[NBINS * 2 - 2];? ?// 每個bin頭有fd和bk兩個指針


? ? /* Bitmap of bins */


? ? unsigned int binmap[BINMAPSIZE];? ?//位圖,用32bit來分別表示當前bin哪個鏈上有chunk,通過按位與的方式


? ? /* Linked list */


? ? struct malloc_state *next;


? ? /* Linked list for free arenas. Access to this field is serialized


? ? by free_list_lock in arena.c. */


? ? struct malloc_state *next_free;


? ? /* Number of threads attached to this arena. 0 if the arena is on


? ? the free list. Access to this field is serialized by


? ? free_list_lock in arena.c. */


? ? INTERNAL_SIZE_T attached_threads;


? ? /* Memory allocated from the system in this arena. */


? ? INTERNAL_SIZE_T system_mem;


? ? INTERNAL_SIZE_T max_system_mem;


? ? }


? ? main_arena:用來管理整個bin鏈的結構體,總共128個bin,10個fastbin


? ? 每個bin頭可以簡化為fd和bk兩個前后項指針


? ? glibc ---> main_arena ---> 對應的bins頭的fd和bk ---> 遍歷找到對應free的chunk


? ? main_arena存放在libc中,其中存放的是每一個bin鏈的頭尾


? ? tips:如果我們能打印一個非fastbin鏈中的fd,bk,那我們就可以計算出libc的基地址libc.addr = libc_on - libc.sysbols["main_arena"] - 88


? ? main_chunk


? ? 在程序的執(zhí)行過程中,我們稱malloc申請的內存為chunk。這塊內存在ptmalloc內部用malloc_chunk結構體來表示。


? ? 當程序申請的chunk被free后,會被加入到相應的空閑管理列表中。


? ? 無論一個chunk的大小如何,處于分配狀態(tài)還是釋放狀態(tài),它們都使用一個統(tǒng)一的結構。但根據(jù)是否被釋放,結構會有所更改。


? ? struct malloc_chunk {


? ? INTERNAL_SIZE_T? ? ? mchunk_prev_size;? // 如果前面一個堆塊是空閑的則表示前一個堆塊的大小,否則無意義


? ? INTERNAL_SIZE_T? ? ? mchunk_size;? ? ? ?//當前chunk的大小,由于對齊的原因所以低三位作為flag,意義如下:


? ? /*


? ? A:倒數(shù)第三位表示當前chunk屬于主分配區(qū)(0)還是非主分配區(qū)(1)


? ? M:倒數(shù)第二位表示當前chunk是從mmap(1)[多線程]分配的,還是從brk(0)[子線程]分配的


? ? P:最低為表示前一塊是否在使用中


? ? */


? ? /*


? ? 1.真正的內存從這里開始分配


? ? 2.malloc之后這些指針沒有用,這時存放的是數(shù)據(jù)


? ? 3.只有在free之后才有效。


? ? */


? ? struct malloc_chunk* fd;? ? ? ?//當chunk空閑時才有意義,記錄后一個空閑chunk的地址


? ? struct malloc_chunk* bk;? ?//同上,記錄前一個空閑chunk的地址


? ? /* Only used for large blocks: pointer to next larger size. */


? ? struct malloc_chunk* fd_nextsize; //當前chunk為largebin時才有意義,指向比當前chunk大的第一個空閑chunk


? ? struct malloc_chunk* bk_nextsize; //指向比當前chunk小的第一個空閑堆塊


? ? };


? ? prev_size


? ? malloc(0x18)會分配0x20的內存


? ? malloc(0x19)分會配0x30的內存


? ? 如果該chunk的物理相鄰的前一地址chunk(兩個指針的地址差值為前一個chunk大小)是空閑的話,那該字段記錄的是前一個chunk的大小


? ? 否則用來存儲物理相鄰的前一個chunk的數(shù)據(jù),這里前一個chunk指的是較低地址的chunk。


? ? prev_size位可以被共享,當前的chunk, 如果不夠用就會占用下一塊chunk的prev_size


? ? size


? ? chunk1的數(shù)據(jù)有效區(qū)域覆蓋到chunk2的prev_size位,并且chunk2的size位的prev_inuse被覆蓋為0。系統(tǒng)認為chunk2之前的chunk1已經未在使用了。


? ? 當free(chunk2)的時候,系統(tǒng)會將chunk2與chunk2中prev_size大小的空間合并到bins。


? ? 我們可以通過改變chunk2的prev_size的內容,操縱向前合并的大小。


? ? 造成的問題:overlap(堆塊重疊),chunk1被釋放了,但是我們可以操縱修改它(堆利用的核心思想),從而修改bins鏈的內容,泄露其中的地址。


? ? 形成的攻擊:fastbin ---> fd ---> main_arena ---> 分配新的堆塊,我們通過修改chunk1的fd內容,達到分配任意內存的目的,造成fastbin attack。


? ? 記錄前一個chunk是否被分配。


? ? 一般來說,堆中第一個被分配的內存塊的size字段的P位都會被設置為1,以便于防止訪問前面的非法內存。


? ? 當一個chunk的size位的P位為0時,我們能通過prev_size獲取上一個chunk的大小及地址,方便進行空閑堆塊的合并。


? ? 對于fastbin的堆塊,不管前面還有沒有被分配的chunk,PREV_INUSE都為1。


? ? 64位chunk的size必須是16字節(jié)對齊


? ? 32位chunk的size必須是8 字節(jié)對齊


? ? 64位 低4位沒用 11110000


? ? 32位 低3位沒用 11111000


? ? define chunksize(p) (chunk_nomask (p) & ~(SIZE_BITS))


? ? define SIZE_BITS (PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)


? ? NON_MAIN_ARENA記錄當前chunk是否是main_arena管理的堆塊,1表示不屬于,0表示屬于


? ? IS_MAPPED記錄當前的chunk是否是由mmap分配的。


? ? PREV_INUSE


? ? 最小堆原則 : malloc(0)會分配0x20的空間,prev_size + size + 數(shù)據(jù)對齊的0x10字節(jié)


? ? prev_inuse 漏洞利用




    • fd / bk

      • 釋放到bins鏈有效

      • fd指向下一個(非物理相鄰)空閑的chunk

      • bk指向上一個(非物理相鄰)空閑的chunk

      • 通過fd和bk可以將空閑的chunk塊加入到空閑的chunk鏈表進行統(tǒng)一管理。

    • fd_nextsize / bk_nextsize

      • 釋放到bins鏈有效,不過其用于較大的chunk(large chunk)

      • fd_nextsize指向前一個與當前chunk大小不同的第一個空閑塊,不包含bin的頭指針

      • bk_nextsize指向后一個與當前chunk大小不同的第一個空閑塊,不包含bin的頭指針

      • 一般空閑的largechunk在fd的遍歷順序中,按照從大到小的順序排列,可以避免在尋找合適的chunk時挨個遍歷。

__libc_malloc

void *__libc_malloc (size_t bytes)


? ? {


? ? mstate ar_ptr;


? ? void *victim;


? ? void *(*hook) (size_t, const void *)


? ? = atomic_forced_read (__malloc_hook);


? ? if (__builtin_expect (hook != NULL, 0))


? ? return (*hook)(bytes, RETURN_ADDRESS (0));


? ? #if USE_TCACHE


? ? /* int_free also calls request2size, be careful to not pad twice. */


? ? size_t tbytes;


? ? checked_request2size (bytes, tbytes);? ?//注意:用戶申請的字節(jié)一旦進入申請內存函數(shù)被轉化為了無符號整數(shù)


? ? size_t tc_idx = csize2tidx (tbytes);


? ? MAYBE_INIT_TCACHE ();


? ? DIAG_PUSH_NEEDS_COMMENT;


? ? if (tc_idx < mp_.tcache_bins


? ? /*&& tc_idx < TCACHE_MAX_BINS*/ /* to appease gcc */


? ? && tcache


? ? && tcache->entries[tc_idx] != NULL)


? ? {


? ? return tcache_get (tc_idx);


? ? }


? ? DIAG_POP_NEEDS_COMMENT;


? ? #endif


? ? if (SINGLE_THREAD_P)


? ? {


? ? victim = _int_malloc (&main_arena, bytes);


? ? assert (!victim || chunk_is_mmapped (mem2chunk (victim)) ||


? ? &main_arena == arena_for_chunk (mem2chunk (victim)));


? ? return victim;


? ? }


? ? arena_get (ar_ptr, bytes);


? ? victim = _int_malloc (ar_ptr, bytes);


? ? /* Retry with another arena only if we were able to find a usable arena


? ? before. */


? ? if (!victim && ar_ptr != NULL)


? ? {


? ? LIBC_PROBE (memory_malloc_retry, 1, bytes);


? ? ar_ptr = arena_get_retry (ar_ptr, bytes);


? ? victim = _int_malloc (ar_ptr, bytes);


? ? }


? ? if (ar_ptr != NULL)


? ? __libc_lock_unlock (ar_ptr->mutex);


? ? assert (!victim || chunk_is_mmapped (mem2chunk (victim)) ||


? ? ar_ptr == arena_for_chunk (mem2chunk (victim)));


? ? return victim;


? ? }

  • 該函數(shù)會首先檢查是否有內存分配函數(shù)的鉤子函數(shù)(__malloc_hook),這個主要用于用戶自定義的堆分配函數(shù)。

這就造成了一個利用點:將__malloc_hook指針指向的內容改為one_gadget的地址,再次malloc的時候就會直接啟動shell。__malloc_hook -> one_gadget(直接起shell的地址)這時不能將其修改為system的地址,因為system的參數(shù)為字符型,而malloc_hook的參數(shù)為無符號整數(shù)。
  • 接著會尋找一個arena來試圖分配內存,然后調用__int_malloc函數(shù)去申請對應的內存

如果分配失敗的話,ptmalloc會試圖再去尋找一個可用的arena,并分配內存如果申請到了arena,那么在退出之前還得解鎖(__libc_lock_lock)
  • 判斷目前的狀態(tài)是否滿足以下條件

  • 要么沒有申請到內存

  • 要么是mmap的內存

  • 要么申請的的內存必須在其所分配的arena中

  • assert

  • 最后返回內存,進入__int_malloc

__int_malloc

__int_malloc是內存分配的核心函數(shù),其核心思路為:

它根據(jù)用戶申請的內存塊大小以及相應大小chunk通常使用的頻度,依次實現(xiàn)了不同的分配方法它由小大到大依次檢查不同的bin中是否有相應的空閑塊可以滿足用戶請求的內存當所有空閑的chunk都無法滿足時,他會考慮top_chunk當top_chunk也無法滿足時,堆分配器才會進行內存塊申請

1. 定義變量


2. 判斷有沒有可用的arena

如果沒有可用的arena,則返回系統(tǒng)調用mmap去申請一塊內存


3. 判斷是否在fastbin范圍

如果申請的chunk的大小正好位于fastbin的范圍,則從fastbin的頭節(jié)點開始取chunk。需要注意的是,這里比較的是無符號整數(shù)調用remove_fb取出,并返回得到的fastbin的頭

4. 判斷是否在smallbin

如果獲取的內存塊的范圍為smallbin的范圍,執(zhí)行以下流程找到其大小對應的下標,判斷其鏈表是否為空,不為空則取最后一個

注意,為了防止一個堆塊能夠正常free且不前向后并,需要修改當前堆塊的物理相鄰的緊接著的2個堆塊的inuse位為1。

5.調用consolidate

當fastbin,small bin中的chunk都不能滿足要求時,就會考慮是不是largebin,在此之前先調用malloc_consolidate處理fastbin中的chunk

將有可能合并的chunk先進行合并后放到unsorted bin中,不能合并的就直接放到unsorted bin中,然后再進入大循環(huán),以減少堆中的碎片。只有在分配一個size在largebin范圍內的堆塊,才能觸發(fā)malloc_consolidate

6. 小總結

在fastbin范圍內,先判斷對應鏈表是否為空,不為空則取剛放入的chunk在smallbin范圍內,先判斷對應鏈表是否為空,不為空則取第一個放入的chunk這兩者都無法匹配用戶申請的chunk時,就會進入大循環(huán)

7. 進入大循環(huán)

a. 嘗試從unsorted bin中分配用戶需要的內存b. 嘗試從large bin中分配用戶需要的內存b. 嘗試從top_chunk中分配用戶需要的內存

8. 從unsorted bin中分配nb

如果申請的size小于unsorted bin中符合要求的chunk的size,會對其進行切割,剩下的進入last_remainder(由unsorted bin管理)如果unsorted bin中沒有滿足要求的chunk時,會先place in order整理,然后再去large bin中尋找

9. 從large bin中分配nb

注意,large bin中的堆塊不會split,不滿足的話就從top_chunk中切割

10. 大循環(huán)之對于unsorted bin的check

對于size的check:檢查當前size是否滿足對齊的 要求對于fd和bk的check:bck -> fd != victim對于double free的check:next->prev_inuse = 0

11. 大循環(huán)之切割unsorted bin

如果用戶請求為small bin chunk,那么我們首先考慮last_remainder如果last_remainder分割后還夠可以作為一個chunk,則使用set_head,set_foot設置標志位,將last_remainder放入原來unsorted bin的位置

12. 大循環(huán)之取出unsorted bin

首先將unsorted bin取出,如果其size和我們的nb(need bytes)一樣則直接放回這個unsorted bin

13. 大循環(huán)之放入對應的bin

根據(jù)取出的size來判斷應該放入哪個bin,放入small bin的時候則雙向鏈表插入在else if中處理large bin的邏輯,包括大小排序以及fd_nextsize和bk_nextsize

14. 大循環(huán)總結

整個過程迭代了10000次

__int_malloc的大循環(huán)主要用來處理unsorted bin如果整個循環(huán)沒有找到合適的bin,說明所有的unsorted bin的大小都不滿足要求如果經過了10000次的循環(huán),所有的unsorted bin中的bin都被放入了對應的bin中,即small bin放入對應的index中,large bin排好序后放入對應的index中

15. 大循環(huán)之large bin

如果請求的chunk在large bin范圍內,就在對應的bin中從小到大依次掃描,直到找到第一個合適的,并不一定精確


切割后的remainder會被放入到unsorted bin中,同時設置標志位等信息

16. 尋找較大的chunk

如果走到了這里,說明對于用戶所需的chunk,不能直接從其對應的合適的bin中獲取chunk,需要掃描所有的bin,查找比當前bin更大的fast bin或small bin 以及l(fā)arge bin

17. 找到一個合適的map

18. 取出chunk

切割之后還是一樣,放入到unsorted bin

19. 使用top_chunk

如果所有的bin中的chunk都沒有辦法直接滿足要求(即不合并),或者沒有空閑的chunk時,就只能使用top_chunk了

20. top_chunk不夠用

? > 如果top_chunk不夠用的時候并不是直接申請內存,而是先調用consolidate合并空閑的fastbin


? ? >


? ? > 然后等待下次循環(huán)再去判斷是否夠用,不夠用才會調用sysmalloc申請內存


? ? >


? ? > ![](https://ws1.sinaimg.cn/large/006nFhrCly1g47vckz6b7j30gn0cmgnb.jpg

_int_malloc總結

  • malloc尋找堆塊的順序

  1. 在fastbin中尋找有沒有對應的chunk

  2. 請求大小為small bin范圍,在small bin中尋找有沒有對應的chunk

  3. 請求大小為large bin范圍,僅調用malloc_consolidate合并fastbin

  4. 在unsorted bin中尋找有沒有合適的chunk

  5. 在large bin中尋找有沒有合適的chunk

  6. 尋找較大的bin鏈中有沒有合適的chunk

  7. 尋找top_chunk

  8. top_chunk不夠用,調用malloc_consolidate合并fastbin

  9. top_chunk不夠用,系統(tǒng)調用再次申請內存


二進制安全之堆溢出(系列)——堆基礎 & 結構(二)的評論 (共 條)

分享到微博請遵守國家法律
连江县| 荔波县| 通山县| 慈利县| 霞浦县| 南安市| 宾川县| 蓝田县| 吴忠市| 顺义区| 揭东县| 和田县| 安福县| 山阴县| 慈溪市| 合江县| 盈江县| 东源县| 上蔡县| 渭源县| 会理县| 彭山县| 台安县| 东乌珠穆沁旗| 吐鲁番市| 南通市| 从江县| 彭水| 温州市| 象山县| 乌拉特前旗| 宜都市| 大田县| 花垣县| 永安市| 汉沽区| 历史| 阳高县| 江口县| 宜昌市| 富川|