国产精品天干天干,亚洲毛片在线,日韩gay小鲜肉啪啪18禁,女同Gay自慰喷水

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

二進(jìn)制安全之堆溢出(系列)——堆基礎(chǔ) & 結(jié)構(gòu)(一)

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

二進(jìn)制安全之堆溢出(系列)第二期來啦
鑒于本期干貨夠多
知了姐怕大家一時間消化不了,特意幫大家拆分成了四節(jié)內(nèi)容以下為“堆基礎(chǔ) & 結(jié)構(gòu)”第一節(jié)

堆基礎(chǔ)
堆的概念

  • 在程序運行過程中,堆可以提供動態(tài)內(nèi)存的分配,允許程序申請大小未知的內(nèi)存。

  • 堆其實就是在程序虛擬地址空間的一塊連續(xù)的線性區(qū)域,它由低地址向高地址生長。

  • 我們一般稱管理堆的那部分程序為堆管理器。

  • 堆管理器位于用戶程序和內(nèi)核中間,主要負(fù)責(zé) :

    • double free : 當(dāng)p已經(jīng)被釋放后再次釋放,造成亂七八糟的現(xiàn)象。

    • malloc

    • free

  • 請求堆

    • 響應(yīng)用戶的申請內(nèi)存請求,向操作系統(tǒng)申請內(nèi)存,然后返回給用戶程序。為了保持內(nèi)存管理的高效性,內(nèi)核一般會預(yù)先分配很大的一塊連續(xù)的內(nèi)存。

  • 釋放堆

    • 管理用戶釋放的內(nèi)存。用戶釋放的內(nèi)存并不是直接返還給操作系統(tǒng),而是由堆管理器進(jìn)行管理。這些釋放的內(nèi)存可以用來響應(yīng)用戶新申請的內(nèi)存的請求。

堆的歷史

  • Linux中早期的堆分配和回收由Doug lea實現(xiàn),但它在并行處理多個線程時,會共享進(jìn)程的堆內(nèi)存空間。因此為了安全性,一個線程使用堆時,會進(jìn)行加鎖。

  • 然而,加鎖會導(dǎo)致其他線程無法使用堆,降低了內(nèi)存分配和回收的高效性。在多線程使用時,沒能正確控制,也可能引起內(nèi)存分配和回收的正確性。

  • Wolffram Gloger在Doug Lea的基礎(chǔ)上進(jìn)行改進(jìn)使其可以支持多線程,這個堆分配器就是ptmalloc。在glibc-2.3.x之后,glibc中集成了ptmalloc2。ptmalloc2主要通過malloc/free函數(shù)來分配和釋放內(nèi)存塊。

堆的實現(xiàn)

  • dlmalloc : Genral purpose allocator

  • ptmalloc2 : glibc

  • jemalloc : Freebsd and Firefox

  • tcmalloc : Google

  • libumen : Solaris

  • 主要以ptmalloc2中堆的實現(xiàn)為主

內(nèi)存管理

  • 只有當(dāng)真正訪問一個地址的時候,系統(tǒng)才會在虛擬內(nèi)存和物理頁面的映射關(guān)系。

  • 所以操作系統(tǒng)已經(jīng)給程序分配了很大的一塊內(nèi)存,但是這開內(nèi)存其實只是虛擬內(nèi)存。只有當(dāng)用戶使用到相應(yīng)的內(nèi)存時,系統(tǒng)才會真正分配物理內(nèi)存給用戶使用。

系統(tǒng)調(diào)用

  • malloc和free在動態(tài)申請或釋放內(nèi)存時,主要是調(diào)用(s)brk和mmap,unmmap函數(shù)實現(xiàn)的。

  • (s)brk函數(shù)機制

# include <stdio.h> # include <unistd.h> # icclude <sys/types.h> int main() { void *cuur_bkr,*tmp_brk = NULL; printf("%d\n",getid()); tm_brk = curr_brk = sbrk(0);//給當(dāng)前程序一個brk printf("%p\n",curr_brk); getchar(); brk(curr_brk+4096);//設(shè)置結(jié)尾位置,即分配了4096字節(jié)的堆塊 curr_brk=sbrk(0); printf("%p\n",curr_brk); getchar(); brk(tmp_brk); curr_brk=sbrk(0); printf("%p\n",curr_brk); getchar(); return 0; }

  1. 初始時,堆的起始地址start_brk以及堆的當(dāng)前末尾brk指向同一地址。根據(jù)是否開啟ALSR,兩者的具體位置會有所不同。

    1. 不開啟ASMR時,start_brk以及brk會指向data/bss段的結(jié)尾。

    2. 開啟ASMR時,start_brk以及brk也會指向同一位置,只是這個位置是在data/bss段結(jié)尾后的隨機偏移處。

    3. sbrk創(chuàng)建的chunk緊鄰數(shù)據(jù)段

  • mmap函數(shù)機制

  1. malloc會使用mmap來創(chuàng)建獨立的匿名映射段。

  2. 匿名映射的目的主要是可以申請以0填充的內(nèi)存,并且這塊內(nèi)存僅被調(diào)用進(jìn)程所使用,這塊內(nèi)存為系統(tǒng)隨機分配。

  3. munmap用于釋放內(nèi)存。

  4. mmap創(chuàng)建的chunk緊鄰libc

data/bss

  • bss段通常是指用來存放程序中未初始化的全局變量的一塊內(nèi)存區(qū)域。

  • data段通常是指用來存放程序中已初始化的全局變量的一塊內(nèi)存區(qū)域。

多線程支持

  • 在原來的dlmalloc實現(xiàn)中,當(dāng)兩個線程同時要申請內(nèi)存時,只有一個線程可以進(jìn)入臨界區(qū)申請內(nèi)存,而另外一個線程必須等待直到臨界區(qū)中不再有線程。

  • 這是因為所有的線程共享一個堆。

  • 在glibc和ptmalloc實現(xiàn)中,支持了多線程的快速訪問,在新的實現(xiàn)中,所有的線程共享多個堆。

堆數(shù)據(jù)結(jié)構(gòu)

  • 宏觀結(jié)構(gòu):包括堆的宏觀信息,通過這些數(shù)據(jù)結(jié)構(gòu)索引堆的基本信息

    • 宏觀結(jié)構(gòu)主要是堆塊之間的連接

  • 微觀結(jié)構(gòu):主要用于處理堆的分配與回收中的內(nèi)存塊

    • malloc & free

宏觀結(jié)構(gòu)
arena & main_arena

  • 主線程對應(yīng)main_arena,管理所有堆塊的結(jié)構(gòu)體

  • 多線程的子線程對應(yīng)arena,存在于線程的控制塊plt中

不是每個線程都會有對應(yīng)的arena
因為每個系統(tǒng)的核數(shù)有限,當(dāng)線程數(shù)大于核數(shù)的二倍時,就必然有線程處于等待狀態(tài),所以沒有必要為每個線程分配一個arena
32bit --> arena_num = 2 * core
64bit --> arena_num = 8 * core

  • chunk_size的倒數(shù)第三個標(biāo)志位NON_MAIN_ARENA,多線程時為1,主線程為0

  • 子線程的堆和主線程的堆不一樣

  • 每個線程會預(yù)分配一個堆空間

  1. 線程會從這個對空間創(chuàng)建top_chunk和堆塊

  2. 當(dāng)malloc的空間超過預(yù)分配的大小,會回到main_arena之前再次分配一個空間

  3. 如果線程的堆存在溢出,可以之前的chunk越界寫堆的arena結(jié)構(gòu)


  • 定位子線程的chunk的技巧

  1. 向子線程的堆塊輸入特殊值:"0xdeadbeef"

  2. 在gdb使用 search -4 0xdeadbeef

  3. 搜索出來的地址即堆的地址


  • 多線程利用思路

  1. 在子線程中找到堆空間的地址空間A

  2. 在A中找到恢復(fù)線程的arena的結(jié)構(gòu)

  3. 通過arena的結(jié)構(gòu)嘗試堆利用


top_chunk

  • 當(dāng)一個chunk處于一個arena的最頂部(最高內(nèi)存地址)的時候,稱之為top_chunk

  • 當(dāng)系統(tǒng)當(dāng)前所有的bin都無法滿足用戶請求的內(nèi)存大小的時候,將此chunk分配給用戶使用

main_arena ---> sbrk
thread arena ---> mmap

  • 如果top_chunk比用戶請求的大小要大的話,就將該top_chunk分為兩部分

  1. 用戶請求的chunk

  2. 剩余的部分成為新的top_chunk


  • 否則需要擴展heap獲分配新的heap,原來的top_chunk劃入unsortedbin

  • top_chunk漏洞利用

  1. 當(dāng)當(dāng)前的top_chunk的空間不夠的時候,系統(tǒng)就會新創(chuàng)建一個top_chunk

  2. 原來的top_chunk被分配到到unsortedbin里面

  3. 在題目中沒有free函數(shù)的時候,則無法將塊進(jìn)入bin鏈

  4. off by one --> 在top_chunk之上構(gòu)建一個0x88的堆塊,改寫top_chunk的size大小

// [漏洞學(xué)名]:house of orange
bins

  • 作用:管理free的malloc_chunk

  • 種類:按照free的chunk大小劃分


  • fastbin :0x20-0x80 :注意fastbin不屬于bins,是ptmalloc單獨用來管理0x20-0x80的堆塊的數(shù)據(jù)結(jié)構(gòu),如果free的chunk大小在0x20-0x80之間,會優(yōu)先進(jìn)入fashbin,

  • smallbin :0x20-0x400

  • unsortedbin : free掉的chunk優(yōu)先進(jìn)入unsortedbin,除了fastbin管理的堆塊

    • 存在整理過程,將所有放在unsortedbin鏈上的堆塊按照大小整理到其它鏈上

    • 將fastbin上的碎片整理到unsorted,再有unsorted整理到其他bin鏈

  • largebin :0x400以上


  • 對于small bins,large bins,unsorted bins來說,ptmalloc將它們維護在同一個數(shù)組中,對應(yīng)的數(shù)據(jù)結(jié)構(gòu)在malloc_state中

#define NBINS 128 // bins總共有128個,除了fastbin
mchunkptr bins[NBINS * 2 - 2] //mchunkptr 是指向chunk頭的指針,bin = fd+bk

  • 管理流程

  1. malloc/free --> glibc --> arena --> fastbin/bins -->smallbin/largebin/unsortedbin

  2. 從glibc找到main_arena

  3. 在main_arena的管理結(jié)構(gòu)體malloc_state通過固定偏移中找到fastbinsY[NFASTBINS],用以管理fastbin。

  4. 找到bins[NBINS * 2 - 2],用以管理unsortedbin。


  • bin的放置順序

索引為1的是unsortedbin,這里面的chunk沒有進(jìn)行排序,比較雜亂。
索引從2到63的bin稱為small bin,同一個small bin鏈表中的chunk的大小相同。兩個相鄰索引的small bin鏈表中的chunk大小為2個機器字節(jié),即32-->4字節(jié),64-->8字節(jié)。
索引從64到126的bin被稱為large bin。large bins中的每一個bin都包含一定范圍內(nèi)的chunk,其中的chunk按fd指針的順序從大到小排列,最靠近bin頭的越大,相同大小的chunk按照最近使用順序排列。

  • 任意兩個物理相鄰的空閑chunk不能在一起,否則會合并。

  • free之后的chunk,與top_chunk相鄰的,會與top_chunk合并,不與之相鄰的,會根據(jù)其大小進(jìn)入到不同的bin

小的進(jìn)入fastbin,大的進(jìn)入unsortedbin
此時,釋放掉的chunk不會馬上歸還系統(tǒng),ptmalloc會統(tǒng)一管理heap和mmap映射區(qū)域的空閑的chunk。
當(dāng)用戶再一次請求分配內(nèi)存時,ptmalloc分配器會試圖在空閑的chunk中挑選一塊合適的給用戶,這樣可以避免頻繁的系統(tǒng)調(diào)用,減少內(nèi)存分配的開銷。

  • 需要注意的是,并不是所有的chunk被釋放之后立即放到bin中。ptmalloc為了提高分配的速度,會把一些小的堆塊先放到fast bin的容器內(nèi)。而且fast bin容器中的chunk的使用標(biāo)記總是被置為1的,所以不會自動合并。

后續(xù)內(nèi)容請鎖定第二期哦~~


二進(jìn)制安全之堆溢出(系列)——堆基礎(chǔ) & 結(jié)構(gòu)(一)的評論 (共 條)

分享到微博請遵守國家法律
宁乡县| 工布江达县| 蒙自县| 两当县| 固镇县| 洛川县| 双峰县| 吴江市| 中西区| 资中县| 靖江市| 青河县| 彭州市| 梨树县| 哈尔滨市| 会宁县| 陆川县| 象山县| 景谷| 卢氏县| 满洲里市| 环江| 安阳市| 沁源县| 兴业县| 张北县| 平果县| 射洪县| 秦皇岛市| 津市市| 泽普县| 阜南县| 潮州市| 抚宁县| 贵溪市| 潼南县| 边坝县| 桓仁| 晋城| 盖州市| 安吉县|