作者: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沒有提供這個功能。

同樣為了檢測是否有內存破壞的現象, 通常會在一些管理結構體中加入一個隨機化的cookie值,內存釋放時判斷cookie是否有被污染。freebsd沒有提供這個功能。


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/1451/