linux程序的經常使用保護機制

linux程序的經常使用保護機制

來源 http://www.javashuo.com/article/p-zleytjuq-ey.htmlhtml

 

操做系統提供了許多安全機制來嘗試下降或阻止緩衝區溢出攻擊帶來的安全風險,包括DEP、ASLR等。在編寫漏洞利用代碼的時候,須要特別注意目標進程是否開啓了DEP(Linux下對應NX)、ASLR(Linux下對應PIE)等機制,例如存在DEP(NX)的話就不能直接執行棧上的數據,存在ASLR的話各個系統調用的地址就是隨機化的。linux

1、checksec

checksec是一個腳本軟件,也就是用腳本寫的一個文件,不到2000行,可用來學習shell。git

源碼參見github

http://www.trapkit.de/tools/checksec.htmlshell

https://github.com/slimm609/checksec.sh/編程

下載方法之一爲數組

wget https://github.com/slimm609/checksec.sh/archive/1.6.tar.gz安全

checksec究竟是用來幹什麼的?cookie

它是用來檢查可執行文件屬性,例如PIE, RELRO, PaX, Canaries, ASLR, Fortify Source等等屬性。dom

checksec的使用方法: img

checksec –file /usr/sbin/sshd img

通常來講,若是是學習二進制漏洞利用的朋友,建議你們使用gdb裏peda插件裏自帶的checksec功能,以下:

img

下面咱們就圖中各個保護機制進行一個大體的瞭解。

2、CANNARY(棧保護)

這個選項表示棧保護功能有沒有開啓。

棧溢出保護是一種緩衝區溢出攻擊緩解手段,當函數存在緩衝區溢出攻擊漏洞時,攻擊者能夠覆蓋棧上的返回地址來讓shellcode可以獲得執行。當啓用棧保護後,函數開始執行的時候會先往棧裏插入cookie信息,當函數真正返回的時候會驗證cookie信息是否合法,若是不合法就中止程序運行。攻擊者在覆蓋返回地址的時候每每也會將cookie信息給覆蓋掉,致使棧保護檢查失敗而阻止shellcode的執行。在Linux中咱們將cookie信息稱爲canary。

gcc在4.2版本中添加了-fstack-protector和-fstack-protector-all編譯參數以支持棧保護功能,4.9新增了-fstack-protector-strong編譯參數讓保護的範圍更廣。

所以在編譯時能夠控制是否開啓棧保護以及程度,例如:

1
2
3
4
gcc -o  test test.c // 默認狀況下,不開啓Canary保護
gcc -fno- stack-protector -o test test.c //禁用棧保護
gcc -fstack-protector -o  test test.c //啓用堆棧保護,不過只爲局部變量中含有 char 數組的函數插入保護代碼
gcc -fstack-protector-all -o  test test.c //啓用堆棧保護,爲全部函數插入保護代碼

3、FORTIFY

fority其實很是輕微的檢查,用於檢查是否存在緩衝區溢出的錯誤。適用情形是程序採用大量的字符串或者內存操做函數,如memcpy,memset,stpcpy,strcpy,strncpy,strcat,strncat,sprintf,snprintf,vsprintf,vsnprintf,gets以及寬字符的變體。

_FORTIFY_SOURCE設爲1,而且將編譯器設置爲優化1(gcc -O1),以及出現上述情形,那麼程序編譯時就會進行檢查但又不會改變程序功能

_FORTIFY_SOURCE設爲2,有些檢查功能會加入,可是這可能致使程序崩潰。

gcc -D_FORTIFY_SOURCE=1 僅僅只會在編譯時進行檢查 (特別像某些頭文件 #include <string.h>)

gcc -D_FORTIFY_SOURCE=2 程序執行時也會有檢查 (若是檢查到緩衝區溢出,就終止程序)

舉個例子可能簡單明瞭一些: 一段簡單的存在緩衝區溢出的C代碼

1
2
3
4
5
6
void  fun(char *s) {
char buf[ 0x100];
strcpy(buf, s);
/* Don't allow gcc to optimise away the buf */
asm  volatile("" :: "m" (buf));
}

用包含參數-U_FORTIFY_SOURCE編譯

1
2
3
4
5
6
7
8
9
10
11
12
13
0804845 0 <fun>:
push %ebp ;
mov %esp,%ebp
 
sub $0x118,%esp ; 將0x118存儲到棧上
mov  0x8(%ebp),%eax ; 將目標參數載入eax
mov %eax, 0x4(%esp) ; 保存目標參數
lea - 0x108(%ebp),%eax ; 數組buf
mov %eax,(%esp) ; 保存
call  8048320 <strcpy@plt>
 
leave ;
ret

用包含參數-D_FORTIFY_SOURCE=2編譯

1
2
3
4
5
6
7
8
9
10
11
12
13
14
0804847 0 <fun>:
push %ebp ;
mov %esp,%ebp
 
sub $0x118,%esp ;
movl $0x10 0,0x8(%esp) ; 把0x100看成目標參數保存
mov  0x8(%ebp),%eax ;
mov %eax, 0x4(%esp) ;
lea - 0x108(%ebp),%eax ;
mov %eax,(%esp) ;
call  8048370 <__strcpy_chk@plt>
 
leave ;
ret

咱們能夠看到gcc生成了一些附加代碼,經過對數組大小的判斷替換strcpy, memcpy, memset等函數名,達到防止緩衝區溢出的做用。

總結下就有:

1
2
3
gcc -o  test test.c // 默認狀況下,不會開這個檢查
gcc -D_FORTIFY_SOURCE=1 -o  test test.c // 較弱的檢查
gcc -D_FORTIFY_SOURCE=2 -o  test test.c // 較強的檢查

4、NX(DEP)

NX即No-eXecute(不可執行)的意思,NX(DEP)的基本原理是將數據所在內存頁標識爲不可執行,當程序溢出成功轉入shellcode時,程序會嘗試在數據頁面上執行指令,此時CPU就會拋出異常,而不是去執行惡意指令。

工做原理如圖: img gcc編譯器默認開啓了NX選項,若是須要關閉NX選項,能夠給gcc編譯器添加-z execstack參數。 例如:

1
2
3
gcc -o  test test.c // 默認狀況下,開啓NX保護
gcc -z execstack -o  test test.c // 禁用NX保護
gcc -z noexecstack -o  test test.c // 開啓NX保護

在Windows下,相似的概念爲DEP(數據執行保護),在最新版的Visual Studio中默認開啓了DEP編譯選項。

5、PIE(ASLR)

通常狀況下NX(Windows平臺上稱其爲DEP)和地址空間分佈隨機化(ASLR)會同時工做。

內存地址隨機化機制(address space layout randomization),有如下三種狀況

1
2
3
0 - 表示關閉進程地址空間隨機化。
1 - 表示將mmap的基址,stack和vdso頁面隨機化。
2 - 表示在1的基礎上增長棧(heap)的隨機化。

能夠防範基於Ret2libc方式的針對DEP的攻擊。ASLR和DEP配合使用,能有效阻止攻擊者在堆棧上運行惡意代碼。

Built as PIE:位置獨立的可執行區域(position-independent executables)。這樣使得在利用緩衝溢出和移動操做系統中存在的其餘內存崩潰缺陷時採用面向返回的編程(return-oriented programming)方法變得可貴多。

liunx下關閉PIE的命令以下:

1
sudo -s echo  0 > /proc/sys/kernel/randomize_va_space

gcc編譯命令

1
2
3
4
5
gcc -o  test test.c // 默認狀況下,不開啓PIE
gcc -fpie -pie -o  test test.c // 開啓PIE,此時強度爲1
gcc -fPIE -pie -o  test test.c // 開啓PIE,此時爲最高強度2
gcc -fpic -o  test test.c // 開啓PIC,此時強度爲1,不會開啓PIE
gcc -fPIC -o  test test.c // 開啓PIC,此時爲最高強度2,不會開啓PIE

說明:

PIE最先由RedHat的人實現,他在鏈接起上增長了-pie選項,這樣使用-fPIE編譯的對象就能經過鏈接器獲得位置無關可執行程序。fPIE和fPIC有些不一樣。能夠參考Gcc和Open64中的-fPIC選項.

gcc中的-fpic選項,使用於在目標機支持時,編譯共享庫時使用。編譯出的代碼將經過全局偏移表(Global Offset Table)中的常數地址訪存,動態裝載器將在程序開始執行時解析GOT表項(注意,動態裝載器操做系統的一部分,鏈接器是GCC的一部分)。而gcc中的-fPIC選項則是針對某些特殊機型作了特殊處理,好比適合動態連接並能避免超出GOT大小限制之類的錯誤。而Open64僅僅支持不會致使GOT表溢出的PIC編譯。

gcc中的-fpie和-fPIE選項和fpic及fPIC很類似,但不一樣的是,除了生成爲位置無關代碼外,還能假定代碼是屬於本程序。一般這些選項會和GCC連接時的-pie選項一塊兒使用。fPIE選項僅能在編譯可執行碼時用,不能用於編譯庫。因此,若是想要PIE的程序,須要你除了在gcc增長-fPIE選項外,還須要在ld時增長-pie選項才能產生這種代碼。即gcc -fpie -pie來編譯程序。單獨使用哪個都沒法達到效果。

6、RELRO

在Linux系統安全領域數據能夠寫的存儲區就會是攻擊的目標,尤爲是存儲函數指針的區域。 因此在安全防禦的角度來講儘可能減小可寫的存儲區域對安全會有極大的好處.

GCC, GNU linker以及Glibc-dynamic linker一塊兒配合實現了一種叫作relro的技術: read only relocation。大概實現就是由linker指定binary的一塊通過dynamic linker處理過 relocation以後的區域爲只讀.

設置符號重定向表格爲只讀或在程序啓動時就解析並綁定全部動態符號,從而減小對GOT(Global Offset Table)攻擊。RELRO爲」 Partial RELRO」,說明咱們對GOT表具備寫權限。

gcc編譯:

1
2
3
4
gcc -o  test test.c // 默認狀況下,是Partial RELRO
gcc -z norelro -o  test test.c // 關閉,即No RELRO
gcc -z lazy -o  test test.c // 部分開啓,即Partial RELRO
gcc -z now -o  test test.c // 所有開啓,即

7、總結

各類安全選擇的編譯參數以下:

  • NX:-z execstack / -z noexecstack (關閉 / 開啓)
  • Canary:-fno-stack-protector /-fstack-protector / -fstack-protector-all (關閉 / 開啓 / 全開啓)
  • PIE:-no-pie / -pie (關閉 / 開啓)
  • RELRO:-z norelro / -z lazy / -z now (關閉 / 部分開啓 / 徹底開啓)

參考連接:上善若水

只知道不行動是紙上談兵,只行動不思考更像是無頭的蒼蠅,要知行合一。

 

========================= End

相關文章
相關標籤/搜索