當前位置:
首頁 > 新聞 > 代碼注入技術之Shellcode注入

代碼注入技術之Shellcode注入

代碼注入是指在應用程序中注入任意外部代碼的行為,有兩種類型的代碼注入:

1.注入易受攻擊的程序;

2.注入不易受攻擊的程序;

如果代碼注入是在易受攻擊的應用程序中完成的,則可以通過利用在處理無效數據時發生的漏洞來實現。在這種情況下,代碼注入的程度就取決於應用程序中的錯誤,我們也將其稱為「漏洞」。但問題在於,應用程序應該具有可以被利用來獲得代碼執行的漏洞。

本系列針對第二種情況,即不希望或不需要該應用程序具有漏洞。正如所預料的那樣,這為應用程序提供了一個非常廣泛的領域,同時也為濫用操作系統提供了機會。

惡意軟體通常使用此方法,因為執行代碼注入之前不需要滿足任何條件,並且操作系統本身也完全支持該方法。所有主要的操作系統都提供ABI和API,以與其他進程進行交互,控制它們後,在其他程序的進程空間中讀寫內存。

通過CreateRemoteThread API進行代碼注入

CreateRemoteThread是Win32 API提供的用於在另一個進程中創建線程的函數。在另一個應用程序中創建線程之前,必須滿足兩個條件:

1.試圖在另一個進程中創建線程的進程必須具有創建線程的許可權,簡單地說,這意味著與受害進程(目標是指我們要在其中創建線程的進程)具有相同或更高的許可權。

2.兩個進程(目標進程和攻擊者進程)必須駐留在同一個會話中,如果會話標識符不匹配,將不會創建線程。

如果上述任何一個條件不滿足,則操作系統本身將拒絕代碼注入過程。

但這不並是Windows OS體系結構中的安全漏洞,而是由操作系統提供的功能。由於我們無法修改具有比我們更高的許可權的進程,因此不會跨越安全邊界。

演算法

為了通過CreateRemoteThread API實現代碼注入,我們必須遵循以下演算法:

1.選擇一個進程作為受害者進程;

2.使用帶有參數PROCESS_ALL_ACCESS的OpenProcess函數獲得對進程的訪問許可權,以便能夠執行所需的操作;

3.如果OpenProcess失敗,請退出;

4.使用VirtualAllocEx函數在受害者進程的進程空間中分配內存;

5.如果VirtualAllocEx失敗,請退出;

6.將shellcode寫入VirtualAllocEx分配的內存位置;

7.如果Shellcode寫入失敗或只有部分寫入Shellcode,請退出;

8.編寫完shellcode後,請使用必要的參數調用CreateRemoteThread,將shellcode的地址指向LPTHREAD_START_ROUTINE。

運行環境

就本文的示例而言,必須具備以下環境設置:

1.Visual Studio 2019;

2.Windows 10 RS6(x64);

注意:可以從我的github存儲庫訪問代碼。

代碼注入

訪問遠程進程

要對任何進程執行內存操作,我們必須能夠訪問它。可以使用函數OpenProcess來獲得它,該函數的原型為:

它包含三個參數:

1.dwDesiredAccess:它根據受害者進程的安全令牌進行檢查,不過你可以指定一些所需的訪問值,但是指定PROCESS_ALL_ACCESS包含該進程的所有可能的訪問許可權。

2.bInheritHandle:這是一個布爾值,指示該進程創建的進程是否將繼承此句柄。

3.dwProcessId:這是受害者進程的進程標識符;

這個進程返回其他進程的句柄(成功時),其他API函數可以使用它來操作受害進程的內存。如果失敗,則返回NULL。

為Shellcode分配空間

一旦獲得了受害進程的句柄,我們就可以在受害進程內存中為shell代碼分配空間,這是通過使用VirtualAllocEx API調用實現的。

VirtualAllocEx的原型為:

它包含五個參數:

1.hProcess:處理要在其中分配內存的進程;

2.lpAddress:指向受害者進程內存中指定地址的指針,如果將參數指定為NULL,則該函數自動選擇要分配給的內存頁;

3.dwSize:要分配的內存區域的大小,它是以位元組為單位指定的。

4.flAllocationType:指定要分配的內存類型,該參數必須包含以下三個值之一:MEM_COMMIT,MEM_RESERVE,MEM_RESET,MEM_RESET_UNDO。

5.flProtect:指定分配的內存保護。出於我們的目的,由於它將包含要執行的代碼,並且希望其具有可讀性和可寫性,因此將其設置為PAGE_EXECUTE_READWRITE。

該函數在成功時返回分配的基地址,而在失敗時返回NULL。至此,我們已經成功地在受害進程中分配了可執行內存。

在遠程進程中編寫Shellcode

現在,我們需要在分配的區域中編寫我們的shellcode。為此,我們有一個稱為WriteProcessMemory的函數。

WriteProcessMemory是一種由調用者將數據寫入指定進程的內存區域的函數,需要注意的是,整個內存區域必須是可寫的,否則該函數將會失敗,這就是為什麼我們將內存分配為可寫的,以及可讀和可執行的原因。

WriteProcessMemory的原型為:

WriteProcessMemory具有五個參數:

1.hProcess:處理要向其中寫入數據的進程;

2.lpBaseAddress:我們要在其中寫入數據的地址(以指針的形式);

3.lpBuffer:指向必須寫入的數據的指針,該指針必須是const指針。

4.nSize:必須寫入的數據量(以位元組為單位);

5.* lpNumberOfBytesWritten:指向SIZE_T的指針,該指針將存儲在該目標中寫入的位元組數。

如果函數由於某種原因而失敗,它將返回false;如果成功,則將返回true。

至此,所有設置都已準備就緒,只需要在遠程進程中創建一個線程並運行它即可。

執行shellcode

為了在遠程進程中創建線程,我們使用Win32 API提供的函數CreateRemoteThread。

1.CreateRemoteThread是一個用於創建在另一個進程的虛擬空間中運行的線程的函數。2.CreateRemoteThread提供的功能有限,並且可以訪問可以為線程指定的擴展屬性,可以使用CreateRemoteThreadEx,但在本文的示例下,前者就足夠了。

CreateRemoteThread的原型為:

CreateRemoteThread有七個參數,其中只有三個對我們有用。其餘的可以具有默認值,儘管通過調整它們可以對新創建的線程進行更多控制。

我們感興趣的參數是:

hProcess:受害者進程的句柄,我們希望在其中創建線程。

lpStartAddress:它是指向THREAD_START_ROUTINE的指針,THREAD_START_ROUTINE是線程一旦創建即將從其開始執行代碼的位置。

lpParameters:指向LPTHREAD_START_ROUTINE所需參數的指針。由於在本例中,它是一個簡單的shellcode,因此不需要任何參數,因此,我們將其保留為NULL,該參數在DLL注入中有重要意義。

演示

在演示視頻中,你可以看到我使用了一個Shellcode在Windows 10 RS6 (x64)上啟動cal .exe(使用msfvenom生成)。

演示視頻見https://pwnrip.com/wp-content/uploads/2019/06/ShellcodeInjectionDemo.mp4

該方法的優勢

與其他代碼注入技術相比,使用CreateRemoteThread進行代碼注入具有多個優勢,比如:

1.最容易實現;

2.不需要對庫函數進行地址解析;

3.不需要等待事件的發生;

4.不需要操作內存中的文件結構;

該方法的缺點

該方法除了優點之外,還有一些缺點,這些缺點使其無法成為流行的代碼插入技術,比如:

1.只能注入二進位代碼;

2.更改Shellcode時需要進行大量更改;

3.使用shellcode可以實現的數量有限。

本文翻譯自:https://pwnrip.com/demystifying-code-injection-techniques-part-1-shellcode-injection/

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


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

歐盟發布5G網路威脅圖譜
Windows內核漏洞利用