<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    深度剖析堆棧中ShellCode的利用原理

    VSole2022-08-17 06:56:54

    前言

    在進入正題之前,需要先了解一下函數調用的堆棧變化。

    //代碼內容:一個簡單的函數調用//環境:vs2022 debug x86#include <iostream>
    void fun() {
    }
    int main() {  fun();  return 0;}
    ;fun函數調用的匯編代碼;在執行該匯編語句時,會將該代碼的下一個指令的地址進行壓棧(0x006C1886);目的是為了回跳,繼續執行后續代碼006C1881  call        006C10F0006C1886  xor         eax,eax
    

    在執行完call指令之后,正式進入函數內部,進行一系列初始化及環境保存操作。

    ;提升堆棧006C1800  push        ebp  006C1801  mov         ebp,esp  006C1803  sub         esp,0C0h ;堆棧默認提升0xc0大小;保存函數調用前的寄存器狀態006C1809  push        ebx  006C180A  push        esi  006C180B  push        edi  ;初始化提升的新堆棧006C180C  mov         edi,ebp  006C180E  xor         ecx,ecx  006C1810  mov         eax,0CCCCCCCCh  006C1815  rep stos    dword ptr es:[edi]  006C1817  mov         ecx,6CC066h  006C181C  call        006C1311  
    ;一般功能代碼在中間附近出現
    ;結束功能代碼后,恢復現場006C1821  pop         edi  006C1822  pop         esi  006C1823  pop         ebx  006C1824  add         esp,0C0h  006C182A  cmp         ebp,esp  006C182C  call        006C123A  006C1831  mov         esp,ebp ;恢復調用前的堆棧006C1833  pop         ebp  ;跳轉回地址0x006C1886處006C1834  ret
    

    函數調用中的堆棧情況如下:

    正文

    • 對上述兩個堆棧狀態有個印象,接下來繼續進行代碼分析。
    • 在用vs環境進行代碼編寫的時候,遇見類似strcpy,strcmp等函數調用時,如果不將設置中的安全檢查取消,那么將判定上述函數為危險函數。其危險的根本就是沒有對拷貝、比較等操作限制字符個數,如果無法預見“\0”字符或比較出差值,那么將一直執行下去。
    #報錯如下D:\Code\CPP\CPP控制臺程序\CPP控制臺程序\main.cpp(7,2): error C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
    //代碼內容:一個簡單的函數調用//環境:vs2022 debug x86#include <iostream>
    void fun(const char * c ) {  char arr[4];  strcpy(arr, c);}
    int main() {  char c[1024] = { 0 };  scanf("%s");  fun(c);  return 0;}/*程序開始后輸入:11111111111111111111*/
    ;提升堆棧00141EC0  | 55              | push ebp                          | main.cpp:500141EC1  | 8BEC            | mov ebp,esp                       |;sub esp,CC這句表示提升棧空間0xCC大小,十進制也就是204字節00141EC3  | 81EC CC000000   | sub esp,CC                        |;保存現場00141EC9  | 53              | push ebx                          |00141ECA  | 56              | push esi                          | esi:__enc$textbss$end+2300141ECB  | 57              | push edi                          |;初始化新堆棧00141ECC  | 8D7D F4         | lea edi,dword ptr ss:[ebp-C]      |00141ECF  | B9 03000000     | mov ecx,3                         |00141ED4  | B8 CCCCCCCC     | mov eax,CCCCCCCC                  | eax:"11111111111111111111"00141ED9  | F3:AB           | rep stosd                         |00141EDB  | B9 66C01400     | mov ecx,_A0FF1F1C_CPP             | main.cpp:1573248000141EE0  | E8 2CF4FFFF     | call cpp控制臺程序.141311          |;拷貝功能代碼的匯編形式00141EE5  | 8B45 08         | mov eax,dword ptr ss:[ebp+8]      | main.cpp:7, [ebp+8]:"11111111111111111111"00141EE8  | 50              | push eax                          | eax:"11111111111111111111"00141EE9  | 8D4D F8         | lea ecx,dword ptr ss:[ebp-8]      |00141EEC  | 51              | push ecx                          |00141EED  | E8 C9F4FFFF     | call cpp控制臺程序.1413BB          | strcpy;結束函數調用,進行堆棧平衡00141EF2  | 83C4 08         | add esp,8                         |00141EF5  | 52              | push edx                          | main.cpp:800141EF6  | 8BCD            | mov ecx,ebp                       |00141EF8  | 50              | push eax                          | eax:"11111111111111111111"00141EF9  | 8D15 1C1F1400   | lea edx,dword ptr ds:[<>]         |00141EFF  | E8 D7F2FFFF     | call cpp控制臺程序.1411DB          |;恢復現場00141F04  | 58              | pop eax                           | eax:"11111111111111111111"00141F05  | 5A              | pop edx                           |00141F06  | 5F              | pop edi                           |00141F07  | 5E              | pop esi                           | esi:__enc$textbss$end+2300141F08  | 5B              | pop ebx                           |00141F09  | 81C4 CC000000   | add esp,CC                        |00141F0F  | 3BEC            | cmp ebp,esp                       |00141F11  | E8 24F3FFFF     | call cpp控制臺程序.14123A          |00141F16  | 8BE5            | mov esp,ebp                       |00141F18  | 5D              | pop ebp                           |;結束當前函數調用00141F19  | C3              | ret                               |
    

    下圖是對fun函數調用時,堆棧棧底值含義的分析

    開始分析功能代碼部分

    ;將輸入的字符串的地址入棧00141EE5  | 8B45 08      | mov eax,dword ptr ss:[ebp+8]            | main.cpp:7, [ebp+8]:"11111111111111111111"00141EE8  | 50           | push eax                                | eax:"11111111111111111111";將目標內存地址入棧,根據ebp-8我們可以清楚地知道,char arr[4]的空間位置00141EE9  | 8D4D F8      | lea ecx,dword ptr ss:[ebp-8]            |00141EEC  | 51           | push ecx                                |;調用strcpy函數00141EED  | E8 C9F4FFFF  | call cpp控制臺程序.1413BB                | strcpy
    

    執行strcpy函數后,堆棧圖如下:

    我們可以清楚地看見,一個strcpy函數的執行,直接將原來的堆棧環境打亂

    • 舊棧底地址值被更改
    • 函數結束的回跳地址被更改(改成shellCOde的起始地址)
    • 更改地址的堆棧也可以被隨意更改(改寫成shellCode具體內容

    利用

    • 思考:如果我們輸入的內容,恰好將函數的回跳地址重新覆蓋,覆蓋成我們shellCode地址的開始地址,那么接下來繼續執行的代碼就是我們的惡意代碼
    • 問題:程序每次執行或操作系統重啟,地址都會發生改變,如果將回跳地址寫死,那么費力編寫的惡意字符串也就變成了無用的字符串
    • 輸入惡意拼接的字符串,就從左側的正常堆棧變成右側被shellCode填充的堆棧

    根據上邊的問題,我們需要一個動態定位ShellCode地址的方法。讓我們詳細分析下函數調用恢復的過程。

    ;恢復寄存器現場00141F04  | 58                 | pop eax                       | eax:"11111111111111111111"00141F05  | 5A                 | pop edx                       |00141F06  | 5F                 | pop edi                       | edi:"111111111111"00141F07  | 5E                 | pop esi                       | esi:__enc$textbss$end+23;將舊棧底重新賦給棧底指針,但是舊棧底會在輸入惡意字符串時被破壞00141F08  | 5B                 | pop ebx                       |;esp棧頂寄存器向高位移動,棧提升使用了sub esp,cc,棧頂恢復與此相反;重點1:此時的esp指向了老ebp的存儲空間00141F09  | 81C4 CC000000      | add esp,CC                    |00141F0F  | 3BEC               | cmp ebp,esp                   |00141F11  | E8 24F3FFFF        | call cpp控制臺程序.14123A      |00141F16  | 8BE5               | mov esp,ebp                   |00141F18  | 5D                 | pop ebp                       |;最后利用ret將回跳地址pop并跳轉;重點2:此時ebp指向了shellCode的首地址00141F19  | C3                 | ret                           |
    

    在考慮更改eip寄存器的常用指令:

    • ret
    • jmp系列指令

    經過兩次跳轉,成功的將eip指向了shellCode位置,進行繼續執行shellCode

    利用跳轉的原因

    • 動態定位shellCode
    • shellCode復用

    總結

    • 盡量尋找系統文件dll中的jmp esp。因為DLL文件有個默認的載入地址,在沒有其他dll占用著位置的時候,dll就會裝入默認的位置,否則就會裝載到隨機的位置,并重新計算函數地址。而操作系統的dll是先于其他應用加載的,因此地址更變得概率不大,成功率高。
    • 相同的系統,shellCode才有通用的可能。因為版本不同,dll加載位置可能不同,最終尋找到的jmp命令位置也不同
    • 全文的操作前提是,能夠將棧中的數據當成了代碼來進行執行。如果不限制權限,那么就可以利用ret + jmp esp來進行跳轉,達到更改eip的效果,進而執行shellcode
    堆棧strcpy
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    ASLR程序加載到內存后不使用默認的加載地址,將加載基址進行隨機化,依賴重定位表進行地址修復。地址隨機化之后,shellcode中固定的地址值將失效。圖-程序地址未隨機化處理開啟/關閉軟件地址隨機化。每個頁目錄表和頁表項都存在 基址與屬性控制位,通過修改這些控制位,達到當前內存是否有執行、讀、寫等權限。圖-表項構成windows 系統上可以調用 VirtualProtect 函數完成內存屬性的修改操作。DWORD flNewProtect, // 請求的保護方式。大小超過 8 個字節且不包含指針的數據結構。
    關于堆棧ShellCode操作:基礎理論002-利用fs寄存器尋找當前程序dll的入口:從動態運行的程序中定位所需dll003-尋找大兵LoadLibraryA:從定位到的dll中尋找所需函數地址004-被截斷的shellCode:加解密,解決shellCode的零字截斷問題
    CVE-2019-10999 是 Dlink IP 攝像頭的后端服務器程序 alphapd 中的一個緩沖區溢出漏洞,漏洞允許經過身份認證的用戶在請求 wireless.htm 時,傳入 WEPEncryption 參數一個長字符串來執行任意代碼。
    ARM 指令集架構,常用于嵌入式設備和智能手機中,是從RISC衍生而來的。
    另外需要說明一下,原文只是一個系列(https://sploitfun.wordpress.com/2015/06/26/linux-x86-exploit-development-tutorial-series/)中的一篇文章:
    本靶機難度為高難度,涉及到了緩沖區溢出的源碼審計 ,逆向分析,動態調試等漏洞技能點,攻擊方法有2種:??SQL 注入得到的密碼可以保留。
    ARM PWN基礎教程
    2022-07-27 17:29:43
    在CTF比賽中,我們所能接觸到的大部分都是x86 x86_64架構的題目,而在我開始接觸IOT方向的研究以后發現智能設備所用到的則是ARM和MIPS架構為主。本篇文章在介紹前置知識的基礎上通過CTF的ARM架構類型題帶讀者更好的入門ARM PWN的世界。
    快速了解 Linux Sudo 高危提權漏洞的研究利用。
    在Windows大部分應用都是基于消息機制,他們都擁有一個消息過程函數,根據不同消息完成不同功能,windows通過鉤子機制來截獲和監視系統中的這些消息。一般鉤子分局部鉤子與全局鉤子,局部鉤子一般用于某個線程,而全局鉤子一般通過dll文件實現相應的鉤子函數。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类