【安全編譯選項-windows平臺】/DYNAMICBASE(地址隨機化)保護原理解讀

0x00 缺陷代碼與利用

1、實驗環境

 

環境

備註

編譯器

VS2017

 

操作系統

Windows7專業版

操作系統必須支持ASLR功能,否則/DYNAMICBASE無作用

實驗其他條件

VS2017中工程禁用/DYNAMICBASE

爲研究/DYNAMICBASE作用,先關閉其查看程序運行狀態。爲使得實驗代碼有漏洞利用關閉SDL選項(SDL開啓將造成示例代碼中有漏洞的危險函數無法使用) 

2、實驗代碼

上一節中將ShellCode注入到了程序棧內並通過跳板指令執行這些惡意代碼。該文中使用了/NXCOMPAT安全編譯選項生成二進制文件,開啓了堆棧不可執行保護。此時無法通過在堆棧區域注入代碼進行惡意代碼執行,然而可以通過另一種方式執行惡意代碼:Return-to-libc。

Return-to-libc攻擊(縮寫:ret2libc),即“返回至C標準庫攻擊”,是一種計算機安全攻擊。這種攻擊方式一般應用於緩衝區溢出中,其堆棧中的返回地址被替換爲另一條指令的地址,並且堆棧的一部分被覆蓋以提供其參數。這允許攻擊者調用現有函數而無需注入惡意代碼到程序中。(來自維基百科)

根據以上解釋,其實在研究/GS使用的漏洞利用方式和這個類似,只是區別在於返回到本程序空間的代碼地址,而不是Return-to-libc所述的回到標準庫地址。

依然使用上一節/NXCOMPAT中的代碼,同時開啓/NXCOMPAT選項,並利用Return-to-libc的漏洞方式進行簡單彈框利用。

實驗代碼如下所示:

#if 1
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#include <windows.h>

#define PASSWORD "1234"
#define BUFFERSIZE 1024
typedef int(*hint)(int param1, int param2);

int verify_password(char *password, int len)
{
   int authenticated = 128;
   char buffer[4]; //字符串數組不大於4,GS將失效,代碼不會增加Cookie的檢查
   //char buffer[5];//字符串數組超過4,GS將生效,代碼增加Cookie的檢查
   authenticated = strcmp(password, PASSWORD);
   //printf("Stack Dynamic:authenticated address: %x\n", &authenticated);
   memcpy(buffer, password, len);//over flowed here!
   return authenticated;
}

int main()
{
   int valid_flag = 0;
   char password[BUFFERSIZE];
   memset(password, 0, BUFFERSIZE);
   FILE * fp;
   HMODULE ui = LoadLibrary("user32.dll");//prepare for messagebox
   //printf("DLL Dynamic:MessageboxA address: %x\n", GetProcAddress(ui, "MessageBoxA"));
   int(*func)(char *, int);
   func = verify_password;
   //printf("image Dynamic:verify_password address: %p\n", (void*)func);

   if (!(fp = fopen("dynamicbase.txt", "r")))
   {
                  printf("open file failure!\n");
                 return 0;
   }

   fgets(password, BUFFERSIZE, fp);
   fseek(fp, 0, SEEK_END);
   int fileSize = ftell(fp);
   valid_flag = verify_password(password, fileSize);

   if (valid_flag)
   {
                  printf("incorrect password!\n");
   }
   else
   {
                  printf("Congratulation! You have passed the verification!\n");
   }

   fclose(fp);
   system("pause");
   return 0;
}
#endif

3、漏洞利用

漏洞利用點依然是 verify_password函數中的memcpy緩衝區溢出問題。由於代碼未變化,所以程序運行時的棧空間佈局沒有變換。棧空間佈局和本文將使用的ret2libc利用過程如下所示:

    上述漏洞利用需要注意幾點:

1、verify_password函數結尾時:回收棧空間->恢復上層函數ebp值->retn指令

retn指令其實有兩個動作,類似的爲下面兩條指令組成的原子指令:

pop eip
jmp eip

在上述恢復ebp時POP操作後,esp指向的位置就是存儲的eip指令地址。如上圖所示在溢出利用時可以寫入標準庫中MessageBoxA的地址。

2、當注入的惡意eip地址被執行時,將會跳轉到MessageBoxA函數的地址進行指令解析。一般在函數開始收條指令就是保存上層函數地址的ebp,MessageBoxA函數也不例外。所以在跳到指定的函數時,原存儲eip的位置此時會存儲ebp值。根據x86彙編指令,一般ebp下面存儲eip地址,所以在訪問MessageBoxA函數的參數時會使用ebp+8訪問第一個參數,其他以此內推。所以這就解釋了在綠色區域填充了四個字節後才放入函數參數。

3、MessageBoxA的字符串參數也放到了棧中,則第二、三參數的值爲該字符串的起始地址。也可指向其他存在的字符串。

    根據以上的分析,使用如下的POC進行利用:

黑色框爲填充數據,最後四個字節覆蓋了原本存儲的ebp數據。

紅色框爲MessageBoxA函數的地址,由於現在OS都開啓了ASLR功能,並且關鍵的系統庫響應的使用了/DYNAMICBASE,所以不同電腦地址可能不一樣,重現時需要修改自己電腦上的值。

黃色框爲上述第2點所述的填充數據

四個綠色框數據分別是MessageBoxA的四個參數,第二、三數值是字符串的地址。本例爲棧中注入字符串的地址。實驗室需要確定並修改該值。

藍色框爲注入想要先的字符串 “failwest”

程序運行發現漏洞被利用:

0x01 安全編譯選項防護

按下圖所示開啓/DYNAMICBASE功能,並重新編譯程序。

運行加入/DYNAMICBASE編譯選項的程序,程序運行異常。

很容易猜測到,加入了該編譯選項後,棧空間地址變化,使得“failwest”字符串的地址找不到,而錯誤的解析了其他地址爲字符串。

0x02 /DYNAMICBASE原理解讀

1、防護原理

通過第一節的利用,讀者很容易發現一個關鍵問題:只有知道MessageBoxA的地址或者說user32.dll這個庫的加載基地址才能正確調用函數並利用成功。

在早期的OS中沒有ASLR防護的情況下所有系統庫的加載基地址是固定的,運行的程序的地址也能容易試探猜測到。爲了增大指令地址的猜測難度,減少命中率。地址空間隨機化的概念出現了。

一方面OS提供了地址空間隨機化的功能,能夠幫助程序或庫加載的基地址隨機化;另一方面,程序編譯時可通過/DYNAMICBASE編譯選項指示程序是否利用ASLR的功能。

ASLR會隨機化地址:1、堆地址 2、棧地址 3、PE文件加載基址 4、PEB與TEB地址

    第一節漏洞利用中使用了棧中的地址,我們以此來驗證/DYNAMICBASE作用。

首先,第一節POC無論運行多少次都能執行彈框的功能,代表棧中的字符串地址不會隨程序重啓次數變化,證明了棧空間是固定的。

然後,開啓/DYNAMICBASE功能後,編譯運行發現上節所述的異常情況。

使用OD或者IDA查看在verify_password函數中在memcpy調用前的棧空間地址,可以發現每次運行地址都會變化,而沒有使用/DYNAMICBASE的程序棧空間地址不會變化。如下圖所示:

所以在使用/DYNAMCBASE上述漏洞利用程序時,MessageBoxA的字符串地址參數產生了異常。

在重啓電腦後,無/DYNAMICBASE選項程序運行時的棧空間地址依然沒有變化。加入/DYNAMICBASE選項程序運行時的堆、棧、基地址、PEB和TEB地址全部變化了。

2、PE文件特點

在微軟官方文檔中指明可選頭中的下述字段用來指示是否啓用ASLR功能

https://img-blog.csdnimg.cn/20190924233836518.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlbnJlbm5hb2Rh,size_16,color_FFFFFF,t_70 ​​

比較開啓/DYNAMICBASE選項編譯的二進制文件差別,也顯示了變化。利用CFF Explorer查看User32.dll的文件頭:

可看到OS將系統中的標準庫設置了啓用ASLR的標誌。所以前文的成功利用的程序中,你能夠發現在重啓後,即使使用OD或IDA查看到程序本身地址是不變的,但是仍然利用失敗。這是因爲User32.dll加載地址隨機化了,重啓後MessageBoxA的函數地址自然也就變了。

0x03 /DYNAMICBASE侷限性

1、如果程序使用固定配置的內存,在添加映像隨機化 (/DYNAMICBASE)選項後有可能由於地址隨機化而不能訪問,導致程序崩潰。

2、隨着運行時間的增加,ASLR會帶來越來越多的內存碎片,有可能導致系統不穩定並造成性能問題。

3、基於緩衝區溢出的攻擊防護中,ASLR需要與DEP配合使用才能達到較好的效果。如果CPU不提供對於DEP的硬件支持,或者應用程序沒有選擇被DEP保護的話,惡意代碼一旦可以執行,就可以通過程序進程表結構來獲得特定DLL的加載基址。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章