session0注入

前言

当我们使用远程线程注入将dll注入至系统服务进程中往往会失败,这是因为大多数系统服务都是在Session0中运行的

"Session 0"是Windows操作系统中的一个特殊的会话,专门用于运行系统服务和其他在用户登录之前就需要运行的程序。从Windows Vista和Windows Server 2008开始,为了提高安全性,Windows将用户和系统服务分隔在不同的会话中。具体来说,所有的服务和系统任务都在Session 0中运行,而所有用户交互任务都在其他会话中运行

"Session 0注入"一般指的是把一个程序(通常是一个恶意程序)注入到Session 0的过程。因为Session 0有许多特权,所以如果恶意程序能够成功注入到Session 0,就可以获得比正常用户更高的权限,从而进行更多的恶意操作

然而,由于Windows Vista和后续版本的Windows的安全性提高,使得Session 0注入变得更加困难。尤其是,Session 0是隔离的,不能直接与用户的图形会话进行交互

image

远程线程注入函数调用流程

1.CreateRemoteThreadStub

CreateRemoteThreadStub是在kernel32.dll中,用于对CreateRemoteThread函数的封装,对CreateRemoteThread的参数进行处理,由原来的7个参数扩展到8个参数,并对dwCreationFlags参数进行安全处理

image-20230611165350503

2.CreateRemoteThread

CreateRemoteThread函数位于KernelBase.dll中,最终调用了NtCreateThreadEx函数

image-20230611165720925

3.NtCreateThread

NtCreateThread是内核级别的函数,它是属于NTDLL库中的一部分。NTDLL库中的函数主要是由操作系统的内核(即内核模式)使用的,而用户模式的程序一般不直接调用这些函数

image-20230611170023100

mov eax, 0C7h:将值0c7h移动至eax寄存器,表示执行编号为0c7h的系统调用

syscall:这是执行系统调用的指令。系统调用编号和参数应在此之前已被设置好(在这种情况下,通过将 0xC7rcx 的内容移动到 eaxr10

这段代码表示执行编号为 0xC7 的系统调用,如果 ds:7FFE0308h 的最低位被设置,那么在系统调用前会先跳转到另一段代码(位于 loc_1800A0525,使用int 2Eh中断进入内核)。如果该位未被设置,那么直接执行系统调用

image-20230611170146936

总结

以下是CreateRemoteThread函数的调用流程图

  1. 应用程序调用 CreateRemoteThread,这是一个由 kernel32.dll 提供的 Win32 API,用于在另一个进程的地址空间中创建新线程。

  2. CreateRemoteThread 内部调用 CreateRemoteThreadEx,这是一个由 KernelBase.dll 提供的更底层的 API,提供了更多的选项,比如可以指定安全描述符,可以控制新线程是否立即开始运行等

  3. CreateRemoteThreadEx 内部调用 NtCreateThreadEx,这是由 ntdll.dll 提供的 Native API,也是用户空间可以直接调用的最底层的 API。

  4. NtCreateThreadEx 函数设置好系统调用的参数后,执行 syscall 指令,切换到内核模式。

  5. 在内核模式下,根据 syscall 提供的系统调用编号,在 SSDT 表中查找对应的内核函数。

  6. 执行 SSDT 表中找到的函数,完成线程的创建。

image-20230611174832964

普通线程和远程线程的区别

可以看到普通线程函数CreateThread也调用了CreateRemoteThread函数,只不过其线程句柄参数的值为-1,而远程线程的句柄参数为一个具体的值

image-20230611175907620

代码实现思路

1.ZwCreateThread函数的声明及定义

当我们使用DLL注入系统服务的进程时会失败,失败的原因在于,当CreateRemoteThread函数尝试在Session 0隔离的系统服务进程中注入DLL时,它通过调用ZwCreateThread函数创建远程线程,其中第七个参数CreateThreadFlags被设置为1。这意味着创建的线程在完成后将被挂起,无法被恢复,因此导致注入失败。为了成功注入,需通过调用ZwCreateThreadEx函数将此参数修改为0。

以下是对ZwCreateThreadEx函数的描述:

由于ZwCreateThread函数未在官方文档中说明,所以我们需对ZwCreateThread函数进行声明:

然后通过GetProcAddress函数来获取这个函数

2.提升进程权限

如果要将dll注入至系统服务进程,还需提升当前进程的权限,以下是提权函数的代码:

3.Session0注入函数

此函数的主要作用是在Session0中注入指定的DLL。其步骤包括提权、打开目标进程、在目标进程中分配内存并写入DLL路径、获取LoadLibraryA函数地址、获取ZwCreateThreadEx函数地址、在目标进程中创建线程运行LoadLibraryA函数,最后释放资源

完整代码

运行测试

首先获取lsass进程的PID,此处为696

image-20230611233900720

以管理员权限运行cmd,使用session0注入将dll注入至lsass进程中

image-20230611233625460

Cobalt Strike成功上线

image-20230611234019447

在火绒剑可以看到lsass进程注入的dll

image-20230611234104530

项目地址

https://github.com/xf555er/Session0_Inject

最后更新于