作者:wzt
原文鏈接:https://mp.weixin.qq.com/s/20ACZFyQiUWZf5cIm_ZW-w
1.1 簡介
Freebsd的內核內存分配器叫做UMA(Universal Memory Allocator),這篇文章只關心它的安全特性,對於常規功能實現請讀者朋友參考網絡上的其他文章。它的安全功能特性相比XNU、NT、LINUX都少了很多,並且還存在一些不安全的構架設計,下面將會詳細分析。
1.2 架構設計缺點
UMA的總體架構也是基於solaris slab, 我們直接看最底層的slab結構,一個slab大小爲PAGE_SIZE,slab的管理體結構依據slab裏的每個item大小而決定,對於小塊item,slab管理結構體放在slab裏,並且是放到PAGE_SIZE的最後。對於大塊item,管理結構體則單獨分配一個內存,不包含在slab裏。
對於小塊item, slab這種設計屬於嚴重的安全錯誤設計,slab header放在所有item的最後,如果最後一個item發生溢出,就可以直接覆蓋slab header裏的數據結構。
struct uma_slab {
uma_keg_t us_keg; /* Keg we live in */
...
}
Slab header結構爲struct Uma_slab,它的第一個成員是us_keg。
struct uma_keg {
LIST_HEAD(,uma_zone) uk_zones; /* Keg's zones */
...
}
Uk_zones結構爲:
struct uma_zone {
uma_ctor uz_ctor; /* Constructor for each allocation */
uma_dtor uz_dtor;
}
結構體成員uz_ctor和uz_dtor爲每個zone在創建和銷燬時調用的析構函數指針,exploit程序一般都會替換這兩個函數指針,使其指向shellcode地址。Slab header放在最後,使堆溢出攻擊相對linux變得更加簡單, 因爲linux的slab header就是放在最前面的。我們在設計內存分配器時就要避免這個糟糕的設計,同時管理結構體中函數指針的定義一定要做到最少,防止被exploit程序濫用。
1.3 安全特性缺失
1.3.1 溢出檢測
能檢測到溢出情況的發生是每個內存分配器的基礎安全能力,業界的通用算法是在內存區塊的前後加入redzone,在初始化時填充一個固定值,在內存釋放時檢測redzone裏的固定值是否有改變來判斷是否有溢出行爲的發生。
UMA的redzone結構爲:
在data的前面分別爲struct stack 保存的是當前棧信息,size爲data的大小,0x42則爲redzone的固定值,一共16字節。在data的最後同樣爲16字節的固定值。
由於設置redzone會佔用更多的內存,同時會使初始化和釋放邏輯變得複雜,從而影響效率,所以檢測溢出的發生都是作爲debug選項來開啓的。幾乎所有主流的os內核內存分配器在設置redzone時都使用了固定值,筆者認爲這也是一個不安全的設計,exploit編寫者可以精心構造內存結構,使其shellcode地址指向0x42424242,就可以繞過檢測。
1.3.2 UAF檢測
對於UAF(Use After Free)的檢測,freebsd沒有實現這個功能,一般算法是在slab item釋放時對data區域填充固定的值,在分配時先檢測固定值有沒有被污染,以此來判斷有無UAF的發生。
1.3.3 雙向安全鏈表
雙向鏈表的刪除操作時,要先檢測前後節點是否爲合法地址, freebsd同樣沒有設計這個功能。
1.3.4 item地址隨機化
Slab裏保存的item爲了初始化簡單, 每個item都是順序鏈接的, 這給exploit程序的利用提供了極大的方便。Linux內核使用了洗牌算法將item的鏈接順序打亂來規避這種攻擊。Freebsd沒有提供這個功能。
1.3.5 管理結構體cookie
同樣爲了檢測是否有內存破壞的現象, 通常會在一些管理結構體中加入一個隨機化的cookie值,內存釋放時判斷cookie是否有被污染。freebsd沒有提供這個功能。
本文由 Seebug Paper 發佈,如需轉載請註明來源。本文地址:https://paper.seebug.org/1451/