Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to set a token for another process?

There is SetThreadToken() function but no such function as "SetProcessToken()".

Is there a way to set a token for another process? How to write "SetProcessToken()"?

like image 584
lpaul7 Avatar asked Dec 03 '22 09:12

lpaul7


1 Answers

Yes, you can, using the undocumented NtSetInformationProcess function, however once the process has started running the process token is locked and can no longer be modified. You must therefore start the process with the CREATE_SUSPENDED creation flag, set the process token, then resume the process using ResumeThread(). In order to set the process token the caller must have and enable the SeAssignPrimaryTokenPrivilege privilege.

Code such as the following should be sufficient:

// A few required typedefs

typedef enum _PROCESS_INFORMATION_CLASS
{
    ProcessBasicInformation,
    ProcessQuotaLimits,
    ProcessIoCounters,
    ProcessVmCounters,
    ProcessTimes,
    ProcessBasePriority,
    ProcessRaisePriority,
    ProcessDebugPort,
    ProcessExceptionPort,
    ProcessAccessToken,
    ProcessLdtInformation,
    ProcessLdtSize,
    ProcessDefaultHardErrorMode,
    ProcessIoPortHandlers,
    ProcessPooledUsageAndLimits,
    ProcessWorkingSetWatch,
    ProcessUserModeIOPL,
    ProcessEnableAlignmentFaultFixup,
    ProcessPriorityClass,
    ProcessWx86Information,
    ProcessHandleCount,
    ProcessAffinityMask,
    ProcessPriorityBoost,
    MaxProcessInfoClass
} PROCESS_INFORMATION_CLASS, *PPROCESS_INFORMATION_CLASS;

typedef struct _PROCESS_ACCESS_TOKEN
{
    HANDLE Token;
    HANDLE Thread;
} PROCESS_ACCESS_TOKEN, *PPROCESS_ACCESS_TOKEN;

typedef NTSTATUS (NTAPI * NtSetInformationProcess) (HANDLE processHandle, PROCESS_INFORMATION_CLASS infoClass, PVOID info, ULONG infoLength);


// Assume we have a handle to an existing process: targetProcessHandle, started in a suspended state, and a new token: newToken to assign to this process.

// First we must enable SeAssignPrimaryTokenPrivilege.
// Note: The user under which this runs must already hold the privilege, this only enables it (it is initially disabled by default).
LUID luid;
LookupPrivilegeValue(0, SE_ASSIGNPRIMARYTOKEN_NAME, &luid);
TOKEN_PRIVILEGES privs;
privs.PrivilegeCount = 1;
privs.Privileges[0].Luid = luid;
privs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

HANDLE myToken;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &myToken))
{
    wprintf("Unable to open own process token to enable permissions\n");
    return FALSE;
}
if (!AdjustTokenPrivileges(myToken, FALSE, &privs, sizeof(TOKEN_PRIVILEGES), 0, 0))
{
    wprintf("Error setting token privileges: 0x%08x\n", GetLastError());
    CloseHandle(myToken);
    return FALSE;
}
// Even if AdjustTokenPrivileges returns TRUE, it may not have succeeded, check last error top confirm
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
{
    wprintf("Unable to enable a required privilege\n");
    CloseHandle(myToken);
    return FALSE;
}
CloseHandle(myToken);

PROCESS_ACCESS_TOKEN tokenInfo;
tokenInfo.Token = newToken;
tokenInfo.Thread = 0;

// Get a handle to ntdll
HMODULE ntdll = LoadLibrary(L"ntdll.dll");

// And a pointer to the NtSetInformationProcess function
NtSetInformationProcess setInfo = (NtSetInformationProcess)GetProcAddress(ntdll,"NtSetInformationProcess");
NTSTATUS setInfoResult = setInfo(targetProcessHandle, ProcessAccessToken, &tokenInfo, sizeof(PROCESS_ACCESS_TOKEN));
if (setInfoResult < 0)
{
    wprintf(L"Error setting token: 0x%08x\n", setInfoResult);
    return FALSE;
}

FreeLibrary(ntdll);

// You can now resume the target process' main thread here using ResumeThread().

return TRUE;
like image 177
Iridium Avatar answered Dec 30 '22 01:12

Iridium