天天看點

Windows Shellcode學習筆記——通過VirtualProtect繞過DEP

本文講的是<b>Windows Shellcode學習筆記——通過VirtualProtect繞過DEP</b>,

0x00 前言

在掌握了棧溢出的基本原理和利用方法後,接下來就要研究如何繞過Windows系統對棧溢出利用的重重防護,是以測試環境也從xp轉到了Win7(相比xp,Win7的防護更全面)。本文将要介紹經典的DEP繞過方法——通過VirtualProtect繞過DEP。

0x01 簡介

本文将要介紹以下内容:

0x02 相關概念

DEP:

溢出攻擊的根源在于計算機對資料和代碼沒有明确區分,如果将代碼放置于資料段,那麼系統就會去執行

為了彌補這一缺陷,微軟從XP SP2開始支援資料執行保護(Data Exection Prevention)

DEP保護原理:

資料所在記憶體頁辨別為不可執行,當程式溢出成功轉入shellcode時,程式會嘗試在資料頁面上執行指令,而有了DEP,此時CPU會抛出異常,而不是去執行指令

DEP四種工作狀态:

DEP繞過原理:

如果函數傳回位址并不直接指向資料段,而是指向一個已存在的系統函數的入口位址,由于系統函數所在的頁面權限是可執行的,這樣就不會觸發DEP

也就是說,可以在代碼區找到替代指令實作shellcode的功能

但是可供利用的替代指令往往有限,無法完整的實作shellcode的功能

于是産生了一個折中方法:通過替代指令關閉DEP,再轉入執行shellcode

記憶體頁:

x86系統一個記憶體頁的大小為4kb,即0x00001000,4096

ROP:

面向傳回的程式設計(Return-oriented Programming)

VirtualProtect:

lpAddress:記憶體起始位址 

dwsize:記憶體區域大小 

flNewProtect:記憶體屬性,PAGE_EXECUTE_READWRITE(0x40) 

lpflOldProtect:記憶體原始屬性儲存位址

通過VirtualProtect繞過DEP:

在記憶體中查找替代指令,填入合适的參數,調用VirtualProtect将shellcode的記憶體屬性設定為可讀可寫可執行,然後跳到shellcode繼續執行

0x03 VS2012的編譯配置

測試環境:

項目屬性:

具體配置方法:

配置屬性-c/c++-所有屬性

配置屬性-連結器-所有屬性

0x04 實際測試

測試1:

測試代碼:

注:

strcpy在執行時遇到0x00會提前截斷,為便于測試shellcode,将strcpy換成memcpy,遇到0x00不會被截斷

Windows Shellcode學習筆記——通過VirtualProtect繞過DEP

如上圖,成功将傳回位址覆寫為0x45444342

測試2:

shellcode起始位址為0x00403020

對應的機器碼為0x0059016A

将傳回位址覆寫為shellcode起始位址

shellcode實作如下操作:

其他位用0x90填充

c代碼如下:

Windows Shellcode學習筆記——通過VirtualProtect繞過DEP

如上圖,shellcode成功執行,ECX寄存器指派為1

測試3:

開啟DEP,再次調試,發現shellcode無法執行,如圖

Windows Shellcode學習筆記——通過VirtualProtect繞過DEP

測試4:

下載下傳安裝Immunity Debugger

下載下傳mona插件,下載下傳位址如下:

https://github.com/corelan/mona

将mona.py放于C:Program FilesImmunity IncImmunity DebuggerPyCommands下

啟動Immunity Debugger,打開test.exe

使用mona插件自動生成rop鍊,輸入:

如圖

Windows Shellcode學習筆記——通過VirtualProtect繞過DEP

mona會搜尋所有的DLL,用于構造rop鍊

執行指令後在C:Program FilesImmunity IncImmunity Debugger下生成檔案rop.txt、rop_chains.txt、rop_suggestions.txt、stackpivot.txt

檢視rop_chains.txt,會列出可用來關閉DEP的ROP鍊,選擇VirtualProtect()函數

Windows Shellcode學習筆記——通過VirtualProtect繞過DEP

如上圖,成功建構ROP鍊

不同環境有可能無法獲得完整參數,需要具體環境具體分析

對應的測試poc修改如下:

其中0x9059016A為PUSH 1;POP ECX;NOP;的機器碼,如果繞過DEP,該指令将會成功執行

編譯後在OllyDbg中調試

單步跟蹤到CALL KERNELBA.VirtualProtectEX,檢視堆棧

可獲得傳入的函數參數

Windows Shellcode學習筆記——通過VirtualProtect繞過DEP

如上圖,不巧的是shellcode覆寫了SEH鍊

這樣會導緻傳入VirtualProtectEX函數的參數不正确,調用失敗,猜測調用VirtualProtectEX函數的傳回值為0

Windows Shellcode學習筆記——通過VirtualProtect繞過DEP

如上圖,驗證上面的判斷,EAX寄存器表示傳回值,傳回值為0,修改記憶體屬性失敗

解決思路:

我們需要擴大棧空間,将SEH鍊下移,確定shellcode不會覆寫到SEH鍊

解決方法:

修改源代碼,通過申請空間的方式下移SEH鍊

測試5:

關鍵代碼如下:

編譯程式,再次放在OllyDbg中調試

Windows Shellcode學習筆記——通過VirtualProtect繞過DEP

SEH鍊成功“下移”,位于高位址,未被shellcode覆寫

此時傳入VirtualProtectEX函數的參數正确

按F8單步執行,檢視結果

Windows Shellcode學習筆記——通過VirtualProtect繞過DEP

如上圖,傳回值為0,修改記憶體屬性仍失敗

LastErr顯示錯誤為ERRPR_INVALID_ADDRESS(000001E7),表示位址錯誤

測試6:

檢視正常調用函數VirtualProtect()時的堆棧,對比測試5,分析失敗原因

正常調用的實作代碼如下:

測試7:

如果将起始位址修改為一個不能通路的位址,如0x40303020

編譯程式,放在OllyDbg中調試

格式如圖

Windows Shellcode學習筆記——通過VirtualProtect繞過DEP

如圖,産生同樣錯誤:ERRPR_INVALID_ADDRESS(000001E7)

Windows Shellcode學習筆記——通過VirtualProtect繞過DEP

猜測,shellcode傳入的起始位址有問題

繼續我們的測試

測試8

接着測試5,單步跟蹤到CALL KERNELBA.VirtualProtectEX,嘗試修改堆棧中的資料

将記憶體位址0x0012FF2c修改為目前記憶體頁的起始位址,即0x0012F000

Windows Shellcode學習筆記——通過VirtualProtect繞過DEP

如下圖,寄存器EAX的值為1,即傳回值為1,成功修改記憶體屬性

Windows Shellcode學習筆記——通過VirtualProtect繞過DEP

接着向下執行,在CALL ESP的位置按下F7,單步步入

Windows Shellcode學習筆記——通過VirtualProtect繞過DEP

如上圖,發現PUSH 1;POP ECX成功執行,測試成功,成功通過VirtualProtect繞過DEP,執行資料段的shellcode

這種情況下,VirtualProtectEX一次最大隻能修改4096長度的記憶體(即一個記憶體頁的長度),且不能跨頁修改,如果越界,傳回值為0,修改失敗

通過C調用函數VirtualProtect不存在上述問題,可跨頁,長度大于4096

0x05 小結

為了在Win7下搭建測試環境,對VS2012的編譯配置需要特别注意,多重保護在提高程式安全性的同時也給環境搭建帶來了麻煩

不同系統下可供使用的替代指令往往不同,需要不斷變換思路,構造合适的ROP鍊

另外,Immunity Debugger的mona插件可為ROP鍊的編寫提供便利,但要注意存在bug的情況,需要更多的測試和優化

如果shellcode長度大于4096,使用VirtualProtect關閉DEP會失敗,需要選擇其他方法

原文釋出時間為:2017年3月24日

本文作者:3gstudent 

本文來自雲栖社群合作夥伴嘶吼,了解相關資訊可以關注嘶吼網站。

<a href="http://www.4hou.com/technology/3943.html" target="_blank">原文連結</a>