linux常用保護機制
操作系統提供了許多安全機制來嘗試降低或阻止緩沖區溢出攻擊帶來的安全風險,包括DEP、ASLR等。在編寫漏洞利用代碼的時候,需要特別注意目標進程是否開啟了DEP(Linux下對應NX)、ASLR(Linux下對應PIE)等機制,例如存在DEP(NX)的話就不能直接執行棧上的數據,存在ASLR的話地址就是隨機化的。
checksec
拿到pwn題的第一步大都是運行下,再拿checksec看開啟了哪些保護機制。
checksec是一個腳本軟件,它是用來檢查可執行文件屬性,例如PIE, RELRO, PaX, Canaries, ASLR, Fortify Source等等屬性。
這里建議大家使用gdb里peda插件里自帶的checksec功能。checksec filename

RELRO
GCC, GNU linker以及Glibc-dynamic linker一起配合實現了一種叫做relro的技術: read only relocation。大概實現就是由linker指定binary的一塊經過dynamic linker處理過 relocation之后的區域為只讀.
設置符號重定向表格為只讀或在程序啟動時就解析并綁定所有動態符號,從而減少對GOT(Global Offset Table)攻擊。RELRO為” Partial RELRO”,說明我們對GOT表具有寫權限。
gcc -o hello test.c // 默認情況下,是Partial RELRO
gcc -z norelro -o hello test.c // 關閉,即No RELRO
gcc -z lazy -o hello test.c // 部分開啟,即Partial RELRO
gcc -z now -o hello test.c // 全部開啟,即Full RELRO
CANNARY(棧保護)
表示棧保護功能有沒有開啟。
棧溢出保護是一種緩沖區溢出攻擊緩解手段,當函數存在緩沖區溢出攻擊漏洞時,攻擊者可以覆蓋棧上的返回地址來讓shellcode能夠得到執行。當啟用棧保護后,函數開始執行的時候會先往棧里插入cookie信息,當函數真正返回的時候會驗證cookie信息是否合法,如果不合法就停止程序運行。攻擊者在覆蓋返回地址的時候往往也會將cookie信息給覆蓋掉,導致棧保護檢查失敗而阻止shellcode的執行。在Linux中我們將cookie信息稱為canary。
可以在 GCC 中使用以下參數設置 Canary:
-fstack-protector 啟用保護,不過只為局部變量中含有數組的函數插入保護
-fstack-protector-all 啟用保護,為所有函數插入保護
-fstack-protector-strong
-fstack-protector-explicit 只對有明確 stack_protect attribute 的函數開啟保護
-fno-stack-protector 禁用保護
NX(DEP)
NX即No-eXecute(不可執行)的意思,NX(DEP)的基本原理是將數據所在內存頁標識為不可執行,當程序溢出成功轉入shellcode時,程序會嘗試在數據頁面上執行指令,此時CPU就會拋出異常,而不是去執行惡意指令。
工作原理如圖:

gcc編譯器默認開啟了NX選項,如果需要關閉NX選項,可以給gcc編譯器添加-z execstack參數。
例如:
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編譯選項。
PIE
PIE(Position-Independent Executable, 位置無關可執行文件)技術與 ASLR 技術類似,ASLR 將程序運行時的堆棧以及共享庫的加載地址隨機化, 而 PIE 技術則在編譯時將程序編譯為位置無關, 即程序運行時各個段(如代碼段等)加載的虛擬地址也是在裝載時才確定。這就意味著, 在 PIE 和 ASLR 同時開啟的情況下, 攻擊者將對程序的內存布局一無所知, 傳統的改寫
GOT 表項的方法也難以進行, 因為攻擊者不能獲得程序的.got 段的虛地址。
若開啟一般需在攻擊時泄露地址信息
liunx下關閉PIE的命令如下:
sudo -s echo 0 > /proc/sys/kernel/randomize_va_space
gcc編譯命令
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
總結
各種安全選擇的編譯參數如下:
- 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(關閉 / 部分開啟 / 完全開啟)
參考