linux安全機制
Stack Canaries
Stack Canaries(取名自地下煤礦的金絲雀,因為它能比礦工更早地發現煤氣洩漏,有預警的作用)是一種用於對抗棧溢位攻擊的技術,即ssp安全機制,有時也叫做Stack cookies。Canary的值是棧上的一個隨機數,在程式啟動時隨機生成並儲存在比函式返回地址更低的位置。由於棧溢位是從低地址向高地址進行覆蓋,因此攻擊者要想控制函式的返回指標,就一定要先覆蓋到Canary。程式只需要在函式返回前檢查Canary是否被篡改,就可以達到保護棧的目的。
No-eXecute
No-eXecute(NX),表示不可執行,其原理是將資料所在的記憶體頁(例如棧和堆)標識為不可執行,如果程式產生溢位轉入執行shellcode時,CPU就會丟擲異常。通常我們使用可執行空間保護(executable space protection)作為一個統稱,來描述這種防止傳統程式碼注入攻擊的技術———攻擊者將惡意程式碼注入正在執行的程式中,然後使用記憶體損壞漏洞將控制流重定向到該程式碼。實施這種保護的技術有多種名稱,在windows上稱為資料執行保護(DEP),在Linux上有NX、W^X、PaX和Exec Shield等。
ASLR
大多數攻擊都基於這樣一個前提,即攻擊者知道程式的內部佈局。因此,引入記憶體佈局的隨機化能有效增加漏洞利用的難度,其中一種技術就是地址空間佈局隨機化(Address Space Layout Randomization,ASLR)它最早出現於2001年出現在PaX專案中,於2005年正式成為Linux的一部分,如今已經廣泛使用在各類作業系統中。ASLR提供的只是概率上的安全性,根據用於隨機化的熵,攻擊者有可能幸運地猜測到正確的地址,有時攻擊者還可以爆破。一個著名的例子是Apache伺服器,它的每個連線都會復刻一個子程序,但這些子程序並不會重新進行隨機化,而是與主程序共享記憶體佈局,所以攻擊者可以不斷嘗試,直到找到正確地址。
PIE
由於ASLR是一種作業系統層面的技術,而二進位制程式本身是不支援隨機化載入的,便出現了一些繞過的方式,例如ret2plt、GOT劫持、地址爆破。於是人們於2003年引入了位置無關可執行檔案(Position-Independent Executable,PIE),它在應用層的編譯器上實現,通過將程式編譯為位置無關程式碼(Position-Independent Code,PIC),使程式可以載入到任意位置,就像一個特殊的共享庫。在PIE和ASLR同時開啟的情況下,攻擊者將對程式內部佈局一無所知,大大增加了利用難度。當然凡事有利有弊,在增加安全性的同時,PIE也會一定程度的影響效能,因此在大多數作業系統上PIE僅用於一些對安全性要求比較高的程式
FORTIFY_SOURCE
我們知道緩衝區溢位常常發生在程式呼叫了一些危險函式的時候,例如操作字串的函式memcpy(),當源字串的長度大於目的緩衝區的長度時,就會發生緩衝區溢位。這時就需要一種針對危險函式的檢查機制,在編譯時嘗試去確定風險是否存在,或者將危險函式替換為相對安全的函式實現,以大大降低緩衝區溢位發生的風險。
FORTIFY_SOURCE就是這樣的一個檢查機制它最初來自2004年RedHat工程師針對GCC和glibc的一個安全補丁,該補丁為字串操作函式提供了輕量級的緩衝區溢位攻擊和格式化字串攻擊檢查,它會將危險函式替換成安全函式,且不會對程式執行的效能產生大的影響。目前所支援的函式有memcpy,memmove、memset、strcpy、stpcpy、strncpy、strncat、sprintf、vsprintf、snprintf、vsnprintf、gets等,這些安全函式位於glibc原始碼的debug下。
在Ubuntu16.04(GCC-5.4.0)上,該機制是預設關閉的。當指定優化等級(-O)為1以上,相當於預設開啟FORTIFY_SOURCE的等級為1,如果我們希望檢查等級為2,則需要手動指定引數。當然該機制並不僅僅能夠用於glibc,只需要將相應的標頭檔案string.h、stdio.h等打上補丁,也能夠獲得該機制保護。
-D_FORTIFY_SOURCE=1時,開啟緩衝區溢位攻擊檢查;
-D_FORTIFY_SOURCE=2時,開啟緩衝區溢位以及格式化字串攻擊檢查。
RELRO
在啟用延遲繫結時,符號的解析只發生在第一次使用的時候,該過程是通過PLT表進行的,解析完成後,相應的GOT條目會被修改為正確的函式地址。因此,在延遲繫結的情況下,.got.plt必須是可寫的,這就給了攻擊者篡改地址劫持程式的可能。
RELRO(ReLocation Read-Only)機制的提出就是為了解決延遲繫結的安全問題,它最初於2004年由Redhat工程師Jakub Jlinek實現,他將符號重定向表設定為只讀,或者在程式啟動時就繫結所有動態符號,從而避免GOT上的地址被篡改。如今,RELOR有兩種形式:
Partial RELRO:一些段(包括.dynamic、.got等)在初始化後將會被標記為只讀。在Ubuntu16.04(GCC-5.4.0)上,預設開啟Partial RELRO
Full RELRO:除了Partial RELRO,延遲繫結被禁止,所有人的匯入符號將在開始時被解析,.got.plt段會被完全初始化為目標函式的最終地址,並被mprotect標記為只讀,但其實.got.plt會直接被合併到.got,也就看不到這段了。另外link_map和_dl_runtime_resolve的地址也不會被裝入。開啟Full RELRO會對程式啟動時的效能造成一定的影響,但也只有這樣才能防止攻擊者篡改GOT。