Reputation: 1753
Ultimately, I want to spawn a C executable from a Node app that drops all but the necessary privileges for its parent, the Node process itself. My current problem, however, is simply having one process disable all privileges for another process. Here's the program that's supposed to do that, passing in the pid on the command line:
#include <windows.h>
#include <stdio.h>
#include <TlHelp32.h>
void print_privileges(HANDLE hToken)
{
DWORD size;
if (!GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &size) && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
PTOKEN_PRIVILEGES tp = malloc(size);
if (tp != NULL && GetTokenInformation(hToken, TokenPrivileges, tp, size, &size)) {
size_t i;
for (i = 0; i < tp->PrivilegeCount; ++i) {
char name[64] = "?";
size_t name_size = sizeof name;
LookupPrivilegeNameA(0, &tp->Privileges[i].Luid, name, &name_size);
PRIVILEGE_SET ps = {
1, PRIVILEGE_SET_ALL_NECESSARY, {
{ { tp->Privileges[i].Luid.LowPart, tp->Privileges[i].Luid.HighPart } }
}
};
BOOL fResult;
PrivilegeCheck(hToken, &ps, &fResult);
printf("%-*s %s\n", 32, name, fResult ? "Enabled" : "Disabled");
}
}
free(tp);
}
}
int disable_all_privileges(DWORD pid)
{
int ret = 1;
const HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, TRUE, pid);
if (hProcess) {
HANDLE hToken;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
ULONG return_length;
TOKEN_LINKED_TOKEN tlk;
if (GetTokenInformation(hToken, TokenLinkedToken, &tlk, sizeof tlk, &return_length)) {
CloseHandle(hToken);
hToken = tlk.LinkedToken;
puts("\nBefore:");
print_privileges(hToken);
/* Disable all privileges. */
if (AdjustTokenPrivileges(hToken, TRUE, 0, 0, 0, 0) || GetLastError() != NOERROR) {
puts("\nAfter:");
print_privileges(hToken);
ret = 0;
}
}
CloseHandle(hToken);
}
}
return ret;
}
void print_process_info(DWORD pid)
{
const HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot != INVALID_HANDLE_VALUE) {
PROCESSENTRY32 pe32 = { .dwSize = sizeof pe32 };
BOOL ok;
for (ok = Process32First(hSnapshot, &pe32); ok; ok = Process32Next(hSnapshot, &pe32))
if (pe32.th32ProcessID == pid) {
puts("Process info:");
printf("dwSize: %lu\n", pe32.dwSize);
printf("th32ProcessID: %lu\n", pe32.th32ProcessID);
printf("cntThreads: %lu\n", pe32.cntThreads);
printf("th32ParentProcessID: %lu\n", pe32.th32ParentProcessID);
printf("pcPriClassBase: %ld\n", pe32.pcPriClassBase);
wprintf(L"szExeFile: %s\n", pe32.szExeFile);
break;
}
CloseHandle(hSnapshot);
}
}
int main(int argc, char* argv[])
{
int ret = 1;
if (argc > 1) {
DWORD pid;
if (sscanf_s(argv[1], "%u", &pid) == 1) {
print_process_info(pid);
ret = disable_all_privileges(pid);
}
}
return ret;
}
Below, I am trying to disable the privileges for the same Administrator cmd window from which I am running my program (I've tried different variations of this, e.g., changing the privileges of another cmd process). As you can see from the console output, below, the first problem is that the privileges enumerated by my dispriv.exe program do not match the privileges listed by the whoami /priv
command. Can someone explain exactly what's going on here? I assume that's due to some difference between user privileges versus process privileges. Do I just ignore the whoami /priv
output because it does not reflect what I'm interested in, the process privileges?
The second problem is that the privileges that I thought I had successfully disabled when I first ran dispriv.exe are once again enabled when I run it again (you can see, below, that I run the program twice in a row). Why is that? Were my privilege changes somehow not "committed" in order to be persistent across runs?
The final problem is that my program does not affect the privileges displayed by whoami /priv
. Specifically, SeChangeNotifyPrivilege is marked Enabled before and after I run my dispriv.exe program. Further evidence that I have an apples-and-oranges situation here. Can you help clarify what's going on?
C:\WINDOWS\system32>whoami /priv
PRIVILEGES INFORMATION
----------------------
Privilege Name Description State
=============================== ========================================= ========
SeIncreaseQuotaPrivilege Adjust memory quotas for a process Disabled
SeSecurityPrivilege Manage auditing and security log Disabled
SeTakeOwnershipPrivilege Take ownership of files or other objects Disabled
SeLoadDriverPrivilege Load and unload device drivers Disabled
SeSystemProfilePrivilege Profile system performance Disabled
SeSystemtimePrivilege Change the system time Disabled
SeProfileSingleProcessPrivilege Profile single process Disabled
SeIncreaseBasePriorityPrivilege Increase scheduling priority Disabled
SeCreatePagefilePrivilege Create a pagefile Disabled
SeBackupPrivilege Back up files and directories Disabled
SeRestorePrivilege Restore files and directories Disabled
SeShutdownPrivilege Shut down the system Disabled
SeDebugPrivilege Debug programs Disabled
SeSystemEnvironmentPrivilege Modify firmware environment values Disabled
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeRemoteShutdownPrivilege Force shutdown from a remote system Disabled
SeUndockPrivilege Remove computer from docking station Disabled
SeManageVolumePrivilege Perform volume maintenance tasks Disabled
SeImpersonatePrivilege Impersonate a client after authentication Enabled
SeCreateGlobalPrivilege Create global objects Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Disabled
SeTimeZonePrivilege Change the time zone Disabled
SeCreateSymbolicLinkPrivilege Create symbolic links Disabled
C:\WINDOWS\system32>tasklist /v /fo csv | findstr /i admincmd
"cmd.exe","2344","Console","9","4,168 K","Running","ENIGMA\plong","0:00:00","Administrator: admincmd"
C:\WINDOWS\system32>\Users\plong\source\repos\Permissions\Debug\dispriv.exe 2344
Process info:
dwSize: 556
th32ProcessID: 2344
cntThreads: 2
th32ParentProcessID: 15664
pcPriClassBase: 8
szExeFile: cmd.exe
Before:
SeShutdownPrivilege Disabled
SeChangeNotifyPrivilege Enabled
SeUndockPrivilege Disabled
SeIncreaseWorkingSetPrivilege Disabled
SeTimeZonePrivilege Disabled
After:
SeShutdownPrivilege Disabled
SeChangeNotifyPrivilege Disabled
SeUndockPrivilege Disabled
SeIncreaseWorkingSetPrivilege Disabled
SeTimeZonePrivilege Disabled
C:\WINDOWS\system32>\Users\plong\source\repos\Permissions\Debug\dispriv.exe 2344
Process info:
dwSize: 556
th32ProcessID: 2344
cntThreads: 2
th32ParentProcessID: 15664
pcPriClassBase: 8
szExeFile: cmd.exe
Before:
SeShutdownPrivilege Disabled
SeChangeNotifyPrivilege Enabled
SeUndockPrivilege Disabled
SeIncreaseWorkingSetPrivilege Disabled
SeTimeZonePrivilege Disabled
After:
SeShutdownPrivilege Disabled
SeChangeNotifyPrivilege Disabled
SeUndockPrivilege Disabled
SeIncreaseWorkingSetPrivilege Disabled
SeTimeZonePrivilege Disabled
C:\WINDOWS\system32>whoami /priv
PRIVILEGES INFORMATION
----------------------
Privilege Name Description State
=============================== ========================================= ========
SeIncreaseQuotaPrivilege Adjust memory quotas for a process Disabled
SeSecurityPrivilege Manage auditing and security log Disabled
SeTakeOwnershipPrivilege Take ownership of files or other objects Disabled
SeLoadDriverPrivilege Load and unload device drivers Disabled
SeSystemProfilePrivilege Profile system performance Disabled
SeSystemtimePrivilege Change the system time Disabled
SeProfileSingleProcessPrivilege Profile single process Disabled
SeIncreaseBasePriorityPrivilege Increase scheduling priority Disabled
SeCreatePagefilePrivilege Create a pagefile Disabled
SeBackupPrivilege Back up files and directories Disabled
SeRestorePrivilege Restore files and directories Disabled
SeShutdownPrivilege Shut down the system Disabled
SeDebugPrivilege Debug programs Disabled
SeSystemEnvironmentPrivilege Modify firmware environment values Disabled
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeRemoteShutdownPrivilege Force shutdown from a remote system Disabled
SeUndockPrivilege Remove computer from docking station Disabled
SeManageVolumePrivilege Perform volume maintenance tasks Disabled
SeImpersonatePrivilege Impersonate a client after authentication Enabled
SeCreateGlobalPrivilege Create global objects Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Disabled
SeTimeZonePrivilege Change the time zone Disabled
SeCreateSymbolicLinkPrivilege Create symbolic links Disabled
C:\WINDOWS\system32>
Upvotes: 0
Views: 1745
Reputation: 7170
As the comment said, you are executing your own dispriv.exe process in an elevated cmd.exe. The first whoami /priv
lists the elevated privileges of cmd.exe. Then you disable the link token(not elevated) privilege of the dispriv.exe process. This will not affect the privileg of cmd.exe.
You need to use the token of cmd.exe, and use its own token instead of the linked token.(For access tokens, you can refer to How User Account Control works about standard user access token and administrator access token):
#include <windows.h>
#include <stdio.h>
#include <TlHelp32.h>
void print_privileges(HANDLE hToken)
{
DWORD size = 0;
if (!GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &size) && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
PTOKEN_PRIVILEGES tp = (PTOKEN_PRIVILEGES)malloc(size);
if (tp != NULL && GetTokenInformation(hToken, TokenPrivileges, tp, size, &size)) {
size_t i;
for (i = 0; i < tp->PrivilegeCount; ++i) {
char name[64] = "?";
DWORD name_size = sizeof name;
LookupPrivilegeNameA(0, &tp->Privileges[i].Luid, name, &name_size);
PRIVILEGE_SET ps = {
1, PRIVILEGE_SET_ALL_NECESSARY, {
{ { tp->Privileges[i].Luid.LowPart, tp->Privileges[i].Luid.HighPart } }
}
};
BOOL fResult;
PrivilegeCheck(hToken, &ps, &fResult);
printf("%-*s %s\n", 32, name, fResult ? "Enabled" : "Disabled");
}
}
free(tp);
}
}
int disable_all_privileges(DWORD pid)
{
int ret = 1;
const HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, TRUE, pid);
if (hProcess) {
HANDLE hToken;
if (OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
ULONG return_length;
TOKEN_LINKED_TOKEN tlk;
puts("\nBefore:");
print_privileges(hToken);
/* Disable all privileges. */
if (AdjustTokenPrivileges(hToken, TRUE, 0, 0, 0, 0) || GetLastError() != NOERROR) {
puts("\nAfter:");
print_privileges(hToken);
ret = 0;
}
CloseHandle(hToken);
}
}
return ret;
}
void print_process_info(DWORD pid)
{
const HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot != INVALID_HANDLE_VALUE) {
PROCESSENTRY32 pe32 = { pe32.dwSize = sizeof pe32 };
BOOL ok;
for (ok = Process32First(hSnapshot, &pe32); ok; ok = Process32Next(hSnapshot, &pe32))
if (pe32.th32ProcessID == pid) {
puts("Process info:");
printf("dwSize: %lu\n", pe32.dwSize);
printf("th32ProcessID: %lu\n", pe32.th32ProcessID);
printf("cntThreads: %lu\n", pe32.cntThreads);
printf("th32ParentProcessID: %lu\n", pe32.th32ParentProcessID);
printf("pcPriClassBase: %ld\n", pe32.pcPriClassBase);
wprintf(L"szExeFile: %s\n", pe32.szExeFile);
break;
}
CloseHandle(hSnapshot);
}
}
int main(int argc, char* argv[])
{
int ret = 1;
if (argc > 1) {
DWORD pid;
if (sscanf_s(argv[1], "%u", &pid) == 1) {
print_process_info(pid);
ret = disable_all_privileges(pid);
}
}
return ret;
}
Result:
C:\Users\path>whoami /priv
PRIVILEGES INFORMATION
----------------------
Privilege Name Description State
========================================= ================================================================== ========
SeMachineAccountPrivilege Add workstations to domain Disabled
SeSecurityPrivilege Manage auditing and security log Disabled
SeTakeOwnershipPrivilege Take ownership of files or other objects Disabled
SeLoadDriverPrivilege Load and unload device drivers Disabled
SeSystemProfilePrivilege Profile system performance Disabled
SeSystemtimePrivilege Change the system time Disabled
SeProfileSingleProcessPrivilege Profile single process Disabled
SeIncreaseBasePriorityPrivilege Increase scheduling priority Disabled
SeCreatePagefilePrivilege Create a pagefile Disabled
SeBackupPrivilege Back up files and directories Disabled
SeRestorePrivilege Restore files and directories Disabled
SeShutdownPrivilege Shut down the system Disabled
SeDebugPrivilege Debug programs Disabled
SeSystemEnvironmentPrivilege Modify firmware environment values Disabled
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeRemoteShutdownPrivilege Force shutdown from a remote system Disabled
SeUndockPrivilege Remove computer from docking station Disabled
SeManageVolumePrivilege Perform volume maintenance tasks Disabled
SeImpersonatePrivilege Impersonate a client after authentication Enabled
SeCreateGlobalPrivilege Create global objects Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Disabled
SeTimeZonePrivilege Change the time zone Disabled
SeCreateSymbolicLinkPrivilege Create symbolic links Disabled
SeDelegateSessionUserImpersonatePrivilege Obtain an impersonation token for another user in the same session Disabled
C:\Users\path>tasklist /v /fo csv | findstr /i "Command Prompt"
"cmd.exe","11244","Console","1","4,764 K","Running","domain\user","0:00:00","Administrator: Command Prompt"
C:\Users\path>dispriv.exe 11244
Process info:
dwSize: 296
th32ProcessID: 11244
cntThreads: 1
th32ParentProcessID: 6208
pcPriClassBase: 8
szExeFile: cmd.exe
Before:
SeMachineAccountPrivilege Disabled
SeSecurityPrivilege Disabled
SeTakeOwnershipPrivilege Disabled
SeLoadDriverPrivilege Disabled
SeSystemProfilePrivilege Disabled
SeSystemtimePrivilege Disabled
SeProfileSingleProcessPrivilege Disabled
SeIncreaseBasePriorityPrivilege Disabled
SeCreatePagefilePrivilege Disabled
SeBackupPrivilege Disabled
SeRestorePrivilege Disabled
SeShutdownPrivilege Disabled
SeDebugPrivilege Disabled
SeSystemEnvironmentPrivilege Disabled
SeChangeNotifyPrivilege Enabled
SeRemoteShutdownPrivilege Disabled
SeUndockPrivilege Disabled
SeManageVolumePrivilege Disabled
SeImpersonatePrivilege Enabled
SeCreateGlobalPrivilege Enabled
SeIncreaseWorkingSetPrivilege Disabled
SeTimeZonePrivilege Disabled
SeCreateSymbolicLinkPrivilege Disabled
SeDelegateSessionUserImpersonatePrivilege Disabled
After:
SeMachineAccountPrivilege Disabled
SeSecurityPrivilege Disabled
SeTakeOwnershipPrivilege Disabled
SeLoadDriverPrivilege Disabled
SeSystemProfilePrivilege Disabled
SeSystemtimePrivilege Disabled
SeProfileSingleProcessPrivilege Disabled
SeIncreaseBasePriorityPrivilege Disabled
SeCreatePagefilePrivilege Disabled
SeBackupPrivilege Disabled
SeRestorePrivilege Disabled
SeShutdownPrivilege Disabled
SeDebugPrivilege Disabled
SeSystemEnvironmentPrivilege Disabled
SeChangeNotifyPrivilege Disabled
SeRemoteShutdownPrivilege Disabled
SeUndockPrivilege Disabled
SeManageVolumePrivilege Disabled
SeImpersonatePrivilege Disabled
SeCreateGlobalPrivilege Disabled
SeIncreaseWorkingSetPrivilege Disabled
SeTimeZonePrivilege Disabled
SeCreateSymbolicLinkPrivilege Disabled
SeDelegateSessionUserImpersonatePrivilege Disabled
C:\Users\path>whoami /priv
PRIVILEGES INFORMATION
----------------------
Privilege Name Description State
========================================= ================================================================== ========
SeMachineAccountPrivilege Add workstations to domain Disabled
SeSecurityPrivilege Manage auditing and security log Disabled
SeTakeOwnershipPrivilege Take ownership of files or other objects Disabled
SeLoadDriverPrivilege Load and unload device drivers Disabled
SeSystemProfilePrivilege Profile system performance Disabled
SeSystemtimePrivilege Change the system time Disabled
SeProfileSingleProcessPrivilege Profile single process Disabled
SeIncreaseBasePriorityPrivilege Increase scheduling priority Disabled
SeCreatePagefilePrivilege Create a pagefile Disabled
SeBackupPrivilege Back up files and directories Disabled
SeRestorePrivilege Restore files and directories Disabled
SeShutdownPrivilege Shut down the system Disabled
SeDebugPrivilege Debug programs Disabled
SeSystemEnvironmentPrivilege Modify firmware environment values Disabled
SeChangeNotifyPrivilege Bypass traverse checking Disabled
SeRemoteShutdownPrivilege Force shutdown from a remote system Disabled
SeUndockPrivilege Remove computer from docking station Disabled
SeManageVolumePrivilege Perform volume maintenance tasks Disabled
SeImpersonatePrivilege Impersonate a client after authentication Disabled
SeCreateGlobalPrivilege Create global objects Disabled
SeIncreaseWorkingSetPrivilege Increase a process working set Disabled
SeTimeZonePrivilege Change the time zone Disabled
SeCreateSymbolicLinkPrivilege Create symbolic links Disabled
SeDelegateSessionUserImpersonatePrivilege Obtain an impersonation token for another user in the same session Disabled
C:\Users\path>
Upvotes: 1
Reputation: 15164
Take a look at the CreateRestrictedToken and CreateProcessAsUser functions.
The first allows you to create an access token that is a restricted version of an existing token (most likely obtained via GetCurrentProcessToken or GetCurrentThreadToken and the second allows you to create a process using a specified access token (rather than the current process' existing primary access token). Note that if you use a thread token you may need to use DuplicateHandle to convert an impersonation token into a primary access token.
Upvotes: 1