/// \brief Starts a new process with low integrity level /// /// The newly started process is sandboxed and cannot increase its integrity level /// int StartRestricted() { BOOL ret; HANDLE token = nullptr; HANDLE newToken = nullptr; PSID integritySid = nullptr; TOKEN_MANDATORY_LABEL til = { 0 }; PROCESS_INFORMATION procInfo = { 0 }; STARTUPINFO startupInfo = { 0 }; WCHAR procCommand[MAX_PATH] = _T("QnSend.exe /restricted"); WCHAR lowIntegrityLevelSid[20] = _T("S-1-16-4096"); try { ret = OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE | TOKEN_ADJUST_DEFAULT | TOKEN_QUERY | TOKEN_ASSIGN_PRIMARY, &token); if (!ret) throw ret; ret = DuplicateTokenEx(token, 0, nullptr, SecurityImpersonation, TokenPrimary, &newToken); if (!ret) throw ret; ret = ConvertStringSidToSid(lowIntegrityLevelSid, &integritySid); if (!ret) throw ret; til.Label.Attributes = SE_GROUP_INTEGRITY; til.Label.Sid = integritySid; ret = SetTokenInformation(newToken, TokenIntegrityLevel, &til, sizeof(TOKEN_MANDATORY_LABEL) + GetLengthSid(integritySid)); if (!ret) throw ret; ret = CreateProcessAsUser(newToken, NULL, procCommand, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &procInfo); if (!ret) throw ret; } catch (...) { #pragma region Cleanup if (procInfo.hProcess != nullptr) CloseHandle(procInfo.hProcess); if (procInfo.hThread != nullptr) CloseHandle(procInfo.hThread); LocalFree(integritySid); if (newToken != nullptr) CloseHandle(newToken); if (token != nullptr) CloseHandle(token); #pragma endregion return ERROR_C; } #pragma region Cleanup if (procInfo.hProcess != nullptr) CloseHandle(procInfo.hProcess); if (procInfo.hThread != nullptr) CloseHandle(procInfo.hThread); LocalFree(integritySid); if (newToken != nullptr) CloseHandle(newToken); if (token != nullptr) CloseHandle(token); #pragma endregion return SUCCESS_C; }
HRESULT GetProcessToken(DWORD dwProcessID, LPHANDLE token, DWORD nUserNameMax, LPWSTR szwUserName, DWORD nUserDomainMax, LPWSTR szwUserDomain) { HANDLE hProcess=OpenProcess(PROCESS_DUP_HANDLE|PROCESS_QUERY_INFORMATION,TRUE,dwProcessID); if (!hProcess) throw std::runtime_error("OpenProcess failed"); HRESULT retval = S_OK; HANDLE hToken = INVALID_HANDLE_VALUE; if (!OpenProcessToken(hProcess, TOKEN_DUPLICATE | TOKEN_QUERY, &hToken)) retval = HRESULT_FROM_WIN32(GetLastError()); else { BYTE buf[MAX_PATH]; DWORD dwRead = 0; if (!GetTokenInformation(hToken, TokenUser, buf, MAX_PATH, &dwRead)) retval = HRESULT_FROM_WIN32(GetLastError()); else { TOKEN_USER *puser = reinterpret_cast<TOKEN_USER*>(buf); SID_NAME_USE eUse; if (!LookupAccountSid(NULL, puser->User.Sid, szwUserName, &nUserNameMax, szwUserDomain, &nUserDomainMax, &eUse)) retval = HRESULT_FROM_WIN32(GetLastError()); } if (FAILED(retval)) return retval; if (!DuplicateTokenEx(hToken, TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE, NULL, SecurityImpersonation, TokenPrimary,token)) retval = HRESULT_FROM_WIN32(GetLastError()); else retval = S_OK; CloseHandle(hToken); } return retval; }
HANDLE MSWindowsWatchdog::duplicateProcessToken(HANDLE process, LPSECURITY_ATTRIBUTES security) { HANDLE sourceToken; BOOL tokenRet = OpenProcessToken( process, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, &sourceToken); if (!tokenRet) { LOG((CLOG_ERR "could not open token, process handle: %d", process)); throw XArch(new XArchEvalWindows()); } LOG((CLOG_DEBUG "got token %i, duplicating", sourceToken)); HANDLE newToken; BOOL duplicateRet = DuplicateTokenEx( sourceToken, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, security, SecurityImpersonation, TokenPrimary, &newToken); if (!duplicateRet) { LOG((CLOG_ERR "could not duplicate token %i", sourceToken)); throw XArch(new XArchEvalWindows()); } LOG((CLOG_DEBUG "duplicated, new token: %i", newToken)); return newToken; }
BOOL CALLBACK kuhl_m_token_list_or_elevate_callback(HANDLE hToken, DWORD ptid, PVOID pvArg) { HANDLE hNewToken; TOKEN_STATISTICS tokenStats; DWORD szNeeded; BOOL isUserOK = TRUE; PKUHL_M_TOKEN_ELEVATE_DATA pData = (PKUHL_M_TOKEN_ELEVATE_DATA) pvArg; PWSTR name, domainName; if(ptid != GetCurrentProcessId()) { if(GetTokenInformation(hToken, TokenStatistics, &tokenStats, sizeof(TOKEN_STATISTICS), &szNeeded)) { if(pData->pUsername) { if(kull_m_token_getNameDomainFromToken(hToken, &name, &domainName, NULL, NULL)) { isUserOK = (_wcsicmp(name, pData->pUsername) == 0); LocalFree(name); LocalFree(domainName); } } else if(pData->tokenId) isUserOK = (pData->tokenId == tokenStats.TokenId.LowPart); if(isUserOK && DuplicateTokenEx(hToken, TOKEN_QUERY | TOKEN_IMPERSONATE, NULL, (tokenStats.TokenType == TokenPrimary) ? SecurityDelegation : tokenStats.ImpersonationLevel, TokenImpersonation, &hNewToken)) { if(pData->pSid) { isUserOK = FALSE; if(!CheckTokenMembership(hNewToken, pData->pSid, &isUserOK)) PRINT_ERROR_AUTO(L"CheckTokenMembership"); } if(isUserOK) { kprintf(L"%u\t", ptid); kuhl_m_token_displayAccount(hToken); if(pData->elevateIt) { if(SetThreadToken(NULL, hNewToken)) { kprintf(L" -> Impersonated !\n"); kuhl_m_token_whoami(0, NULL); isUserOK = FALSE; } else PRINT_ERROR_AUTO(L"SetThreadToken"); } } else isUserOK = TRUE; CloseHandle(hNewToken); } else isUserOK = TRUE; } } return isUserOK; }
Token Token::duplicate_impersonation() { HANDLE h; if (FALSE != DuplicateTokenEx(handle_, MAXIMUM_ALLOWED, nullptr, SecurityImpersonation, TokenImpersonation, &h)) { return std::move(Token(h)); } // TODO THROW CORRECTLY throw 1; }
HANDLE GetLoggedOnUserToken( OUT PWCHAR userName, IN DWORD cchUserName // at least UNLEN WCHARs ) { DWORD consoleSessionId; HANDLE userToken, duplicateToken; DWORD nameSize = UNLEN; consoleSessionId = WTSGetActiveConsoleSessionId(); if (0xFFFFFFFF == consoleSessionId) { LogWarning("no active console session"); return NULL; } if (!WTSQueryUserToken(consoleSessionId, &userToken)) { LogDebug("no user is logged on"); return NULL; } // create a primary token (needed for logon) if (!DuplicateTokenEx( userToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &duplicateToken)) { perror("DuplicateTokenEx"); CloseHandle(userToken); return NULL; } CloseHandle(userToken); if (!ImpersonateLoggedOnUser(duplicateToken)) { perror("ImpersonateLoggedOnUser"); CloseHandle(duplicateToken); return NULL; } if (!GetUserName(userName, &cchUserName)) { perror("GetUserName"); userName[0] = 0; } RevertToSelf(); return duplicateToken; }
BOOL GetSessionUserToken(ULONG SessionId, LPHANDLE lphUserToken) { BOOL bResult = FALSE; HANDLE hImpersonationToken = INVALID_HANDLE_VALUE; if (lphUserToken != NULL) { if (_WTSQueryUserToken (SessionId, &hImpersonationToken)) { bResult = DuplicateTokenEx(hImpersonationToken, 0, NULL, SecurityImpersonation, TokenPrimary, lphUserToken); CloseHandle(hImpersonationToken); } } return bResult; }
bool DebugToken::CreateToken() { HANDLE hProcessToken = NULL; BOOL rc = OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE, &hProcessToken); if (!rc) return false; HANDLE hToken = NULL; rc = DuplicateTokenEx( hProcessToken, TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, NULL, SecurityImpersonation, TokenImpersonation, &hToken); if (!rc) { CloseHandle(hProcessToken); return false; } TOKEN_PRIVILEGES tp; tp.PrivilegeCount = 1; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; rc = LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid); if (!rc) { CloseHandle(hToken); CloseHandle(hProcessToken); return false; } rc = AdjustTokenPrivileges( hToken, FALSE, &tp, sizeof(tp), NULL, NULL); if (!rc) { CloseHandle(hToken); CloseHandle(hProcessToken); return false; } hDebugToken = hToken; return true; }
/* * @implemented */ BOOL WINAPI DuplicateToken(IN HANDLE ExistingTokenHandle, IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, OUT PHANDLE DuplicateTokenHandle) { return DuplicateTokenEx(ExistingTokenHandle, TOKEN_IMPERSONATE | TOKEN_QUERY, NULL, ImpersonationLevel, TokenImpersonation, DuplicateTokenHandle); }
static int get_token(connection_context *c) { int res = 0; int wres; HANDLE token; if (c->runas) { credentials crd; if (!prepare_credentials(c->runas, &crd)) { hprintf(c->pipe, "error Incorrect runas credentials\n"); goto finish; } wres = LogonUser(crd.user, crd.domain, crd.password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &c->token); if (!wres) { hprintf(c->pipe, "error Cannot LogonUser(%s,%s,%s) %d\n", crd.user, crd.domain, crd.password, GetLastError()); goto finish; } res = 1; goto finish; } else if (c->system) { if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token)) { hprintf(c->pipe, "error Cannot OpenProcessToken %d\n", GetLastError()); goto finish; } } else { if (!ImpersonateNamedPipeClient(c->pipe->h)) { hprintf(c->pipe, "error Cannot ImpersonateNamedPipeClient %d\n", GetLastError()); goto finish; } if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &token)) { hprintf(c->pipe, "error Cannot OpenThreadToken %d\n", GetLastError()); goto finishRevertToSelf; } } if (!DuplicateTokenEx(token, MAXIMUM_ALLOWED, 0, c->implevel, TokenPrimary, &c->token)) { hprintf(c->pipe, "error Cannot Duplicate Token %d\n", GetLastError()); goto finishCloseToken; } res = 1; finishCloseToken: CloseHandle(token); finishRevertToSelf: if (!c->system) { if (!RevertToSelf()) { hprintf(c->pipe, "error Cannot RevertToSelf %d\n", GetLastError()); res = 0; } } finish: return res; }
void Duplicate(HANDLE& h, LPCSTR file, int line) { HANDLE hDupe = NULL; if(DuplicateTokenEx(h, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &hDupe)) { CloseHandle(h); h = hDupe; hDupe = NULL; } else { DWORD gle = GetLastError(); _ASSERT(0); Log(StrFormat(L"Error duplicating a user token (%S, %d)", file, line), GetLastError()); } }
ProcessStarterPrivate::_phandle ProcessStarterPrivate::GetCurrentUserToken() { QLibrary wts("Wtsapi32"); BOOL (__stdcall * pWTSQueryUserToken)(ULONG SessionId,PHANDLE phToken) = (BOOL(__stdcall *)(ULONG,PHANDLE)) wts.resolve("WTSQueryUserToken"); BOOL (__stdcall * pWTSEnumerateSessionsW)(HANDLE hServer,DWORD Reserved,DWORD Version, PWTS_SESSION_INFOW * ppSessionInfo,DWORD * pCount) = (BOOL(__stdcall *)(HANDLE, DWORD,DWORD,PWTS_SESSION_INFOW *, DWORD *)) wts.resolve("WTSEnumerateSessionsW"); PHANDLE currentToken = &curTok; PHANDLE primaryToken = &primTok; int dwSessionId = 0; PWTS_SESSION_INFOW pSessionInfo = 0; DWORD dwCount = 0; pWTSEnumerateSessionsW(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSessionInfo, &dwCount); for (DWORD i = 0; i < dwCount; ++i) { WTS_SESSION_INFO si = pSessionInfo[i]; if (WTSActive == si.State) { dwSessionId = si.SessionId; break; } } BOOL bRet = pWTSQueryUserToken(dwSessionId, currentToken); int errorcode = GetLastError(); if (bRet == false) { return 0; } bRet = DuplicateTokenEx(*currentToken, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, 0, SecurityImpersonation, TokenPrimary, primaryToken); errorcode = GetLastError(); if (bRet == false) { return 0; } return primaryToken; }
// gets the current user (so we can launch under their session) HANDLE CMSWindowsRelauncher::getCurrentUserToken(DWORD sessionId, LPSECURITY_ATTRIBUTES security) { HANDLE currentToken; HANDLE winlogonProcess; if (winlogonInSession(sessionId, &winlogonProcess)) { LOG((CLOG_DEBUG "session %i has winlogon.exe", sessionId)); // get the token, so we can re-launch with this token // -- do we really need all these access bits? BOOL tokenRet = OpenProcessToken( winlogonProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_ADJUST_SESSIONID | TOKEN_READ | TOKEN_WRITE, ¤tToken); if (!tokenRet) { LOG((CLOG_ERR "could not open token (error: %i)", GetLastError())); return 0; } } else { LOG((CLOG_ERR "session %i does not have winlogon.exe " "which is needed for re-launch", sessionId)); return 0; } HANDLE primaryToken; BOOL duplicateRet = DuplicateTokenEx( currentToken, MAXIMUM_ALLOWED, security, SecurityImpersonation, TokenPrimary, &primaryToken); if (!duplicateRet) { LOG((CLOG_ERR "could not duplicate token %i (error: %i)", currentToken, GetLastError())); return 0; } return primaryToken; }
scoped_handle CreateLowboxToken() { PSID package_sid_p; if (!ConvertStringSidToSid(L"S-1-15-2-1-1-1-1-1-1-1-1-1-1-1", &package_sid_p)) { printf("[ERROR] creating SID: %d\n", GetLastError()); return nullptr; } local_free_ptr package_sid(package_sid_p); HANDLE process_token_h; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &process_token_h)) { printf("[ERROR] error opening process token SID: %d\n", GetLastError()); return nullptr; } scoped_handle process_token(process_token_h); NtCreateLowBoxToken fNtCreateLowBoxToken = (NtCreateLowBoxToken)GetProcAddress(GetModuleHandle(L"ntdll"), "NtCreateLowBoxToken"); HANDLE lowbox_token_h; OBJECT_ATTRIBUTES obja = {}; obja.Length = sizeof(obja); NTSTATUS status = fNtCreateLowBoxToken(&lowbox_token_h, process_token_h, TOKEN_ALL_ACCESS, &obja, package_sid_p, 0, nullptr, 0, nullptr); if (status != 0) { printf("[ERROR] creating lowbox token: %08X\n", status); return nullptr; } scoped_handle lowbox_token(lowbox_token_h); HANDLE imp_token; if (!DuplicateTokenEx(lowbox_token_h, TOKEN_ALL_ACCESS, nullptr, SecurityImpersonation, TokenImpersonation, &imp_token)) { printf("[ERROR] duplicating lowbox: %d\n", GetLastError()); return nullptr; } return scoped_handle(imp_token); }
Q_PID CAuthHelperTest::createSimpleProcessAsUser( CAuthHelper& auth ) { # ifndef _WIN_ Q_UNUSED( auth ); return 0; #else PROCESS_INFORMATION* pid = new PROCESS_INFORMATION; try { void *pToken = NULL; if ( ! DuplicateTokenEx( auth.GetAuth()->GetTokenHandle(), MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &pToken) ) throw "DuplicateTokenEx failed"; memset(pid, 0, sizeof(PROCESS_INFORMATION)); DWORD dwCreationFlags = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT; QString args = "sleep 2"; wchar_t szCmd[512] = { 0 }; args.toWCharArray( szCmd ); QStringList params; params.append( "2" ); //QString args ;= create_commandline ( "sleep", params); //LPWSTR* szCmdline=wcsdup(L"sleep 2"); //WCHAR args[]= L"sleep 2"; if ( ! CreateProcessAsUserW( pToken,0, szCmd , 0, 0, FALSE, dwCreationFlags, 0, 0, 0, pid) ) throw "CreateProcessAsUserW() failed"; return pid; } catch (const char* err) { LOG_MESSAGE( DBG_FATAL, "error catched [%s], err=[%s]", err, Prl::GetLastErrorAsString() ); Q_UNUSED(err); return 0; } #endif }
HANDLE MSWindowsSession::getUserToken(LPSECURITY_ATTRIBUTES security) { HANDLE sourceToken; if (!WTSQueryUserToken(m_activeSessionId, &sourceToken)) { LOG((CLOG_ERR "could not get token from session %d", m_activeSessionId)); throw XArch(new XArchEvalWindows); } HANDLE newToken; if (!DuplicateTokenEx( sourceToken, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, security, SecurityImpersonation, TokenPrimary, &newToken)) { LOG((CLOG_ERR "could not duplicate token")); throw XArch(new XArchEvalWindows); } LOG((CLOG_DEBUG "duplicated, new token: %i", newToken)); return newToken; }
bool GetWinlogonHandle(LPHANDLE lphUserToken, DWORD sessionid) { BOOL bResult = FALSE; HANDLE hAccessToken = NULL; HANDLE hTokenThis = NULL; // DWORD Id = GetProcessesByName(L"winlogon.exe"); DWORD Id = Find_winlogon(sessionid); HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Id); if (hProcess) { if (OpenProcessToken(hProcess, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, &hTokenThis)) { bResult = DuplicateTokenEx(hTokenThis, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, lphUserToken); CloseHandle(hTokenThis); } CloseHandle(hProcess); } return bResult == 1; }
// checks for presence of local admin group (must have TOKEN_DUPLICATE perms on hToken) bool SecurityHelper::IsAdmin(HANDLE hToken) { // we can pretty much assume all tokens will be primary tokens in this application // and CheckTokenMembership requires an impersonation token (which is really annoying) // so we'll just duplicate any token we get into an impersonation token before continuing... bool isAdmin = false; HANDLE hImpToken; if (DuplicateTokenEx(hToken, TOKEN_QUERY, 0, SecurityIdentification, TokenImpersonation, &hImpToken)) { BOOL isMember; if (CheckTokenMembership(hImpToken, _administratorsAlias(), &isMember) && isMember) { isAdmin = true; } else LCF1(L"CheckTokenMembership failed: %d", GetLastError()); CloseHandle(hImpToken); } else LCF1(L"DuplicateTokenEx failed: %d", GetLastError()); return isAdmin; }
BOOL GetTokenFromPid(DWORD dwPid, _TOKEN_TYPE TokenType, HANDLE& hToken) { BOOL bRetCode = FALSE; BOOL bResult = FALSE; HANDLE hProcess = NULL; HANDLE hOriToken = NULL; hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwPid); if (NULL == hProcess) goto Exit0; bResult = ::OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, &hOriToken); if (!bResult) goto Exit0; bResult = DuplicateTokenEx(hOriToken, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenType, &hToken); bRetCode = TRUE; Exit0: if (hOriToken) { ::CloseHandle(hOriToken); } if (hProcess) { ::CloseHandle(hProcess); } return bRetCode; }
TStatus GetUnElevatedToken(CAutoHandle& hToken) { HWND hShellWnd = GetShellWindow(); if(hShellWnd == NULL) { SW_TSTATUS_RET(SW_ERR_WND_NOT_FOUND, L"GetShellWindow() return NULL"); } DWORD dwShellPID = 0; GetWindowThreadProcessId(hShellWnd, &dwShellPID); SW_WINBOOL_RET(dwShellPID != 0); CAutoHandle hShellProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwShellPID); SW_WINBOOL_RET(hShellProcess.IsValid()); CAutoHandle hShellProcessToken; SW_WINBOOL_RET(OpenProcessToken(hShellProcess, TOKEN_DUPLICATE, &hShellProcessToken)); const DWORD dwTokenRights = TOKEN_QUERY | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID; SW_WINBOOL_RET(DuplicateTokenEx(hShellProcessToken, dwTokenRights, NULL, SecurityImpersonation, TokenPrimary, &hToken)); SW_RETURN_SUCCESS; }
TSRM_API FILE *popen_ex(const char *command, const char *type, const char *cwd, char *env) { FILE *stream = NULL; int fno, type_len, read, mode; STARTUPINFO startup; PROCESS_INFORMATION process; SECURITY_ATTRIBUTES security; HANDLE in, out; DWORD dwCreateFlags = 0; BOOL res; process_pair *proc; char *cmd; int i; char *ptype = (char *)type; HANDLE thread_token = NULL; HANDLE token_user = NULL; BOOL asuser = TRUE; if (!type) { return NULL; } /*The following two checks can be removed once we drop XP support */ type_len = (int)strlen(type); if (type_len <1 || type_len > 2) { return NULL; } for (i=0; i < type_len; i++) { if (!(*ptype == 'r' || *ptype == 'w' || *ptype == 'b' || *ptype == 't')) { return NULL; } ptype++; } security.nLength = sizeof(SECURITY_ATTRIBUTES); security.bInheritHandle = TRUE; security.lpSecurityDescriptor = NULL; if (!type_len || !CreatePipe(&in, &out, &security, 2048L)) { return NULL; } memset(&startup, 0, sizeof(STARTUPINFO)); memset(&process, 0, sizeof(PROCESS_INFORMATION)); startup.cb = sizeof(STARTUPINFO); startup.dwFlags = STARTF_USESTDHANDLES; startup.hStdError = GetStdHandle(STD_ERROR_HANDLE); read = (type[0] == 'r') ? TRUE : FALSE; mode = ((type_len == 2) && (type[1] == 'b')) ? O_BINARY : O_TEXT; if (read) { in = dupHandle(in, FALSE); startup.hStdInput = GetStdHandle(STD_INPUT_HANDLE); startup.hStdOutput = out; } else { out = dupHandle(out, FALSE); startup.hStdInput = in; startup.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); } dwCreateFlags = NORMAL_PRIORITY_CLASS; if (strcmp(sapi_module.name, "cli") != 0) { dwCreateFlags |= CREATE_NO_WINDOW; } /* Get a token with the impersonated user. */ if(OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &thread_token)) { DuplicateTokenEx(thread_token, MAXIMUM_ALLOWED, &security, SecurityImpersonation, TokenPrimary, &token_user); } else { DWORD err = GetLastError(); if (err == ERROR_NO_TOKEN) { asuser = FALSE; } } cmd = (char*)malloc(strlen(command)+strlen(TWG(comspec))+sizeof(" /c ")+2); if (!cmd) { return NULL; } sprintf(cmd, "%s /c \"%s\"", TWG(comspec), command); if (asuser) { res = CreateProcessAsUser(token_user, NULL, cmd, &security, &security, security.bInheritHandle, dwCreateFlags, env, cwd, &startup, &process); CloseHandle(token_user); } else { res = CreateProcess(NULL, cmd, &security, &security, security.bInheritHandle, dwCreateFlags, env, cwd, &startup, &process); } free(cmd); if (!res) { return NULL; } CloseHandle(process.hThread); proc = process_get(NULL); if (read) { fno = _open_osfhandle((tsrm_intptr_t)in, _O_RDONLY | mode); CloseHandle(out); } else { fno = _open_osfhandle((tsrm_intptr_t)out, _O_WRONLY | mode); CloseHandle(in); } stream = _fdopen(fno, type); proc->prochnd = process.hProcess; proc->stream = stream; return stream; }
/* * @implemented */ BOOL WINAPI CheckTokenMembership(IN HANDLE ExistingTokenHandle, IN PSID SidToCheck, OUT PBOOL IsMember) { PISECURITY_DESCRIPTOR SecurityDescriptor = NULL; ACCESS_MASK GrantedAccess; struct { PRIVILEGE_SET PrivilegeSet; LUID_AND_ATTRIBUTES Privileges[4]; } PrivBuffer; ULONG PrivBufferSize = sizeof(PrivBuffer); GENERIC_MAPPING GenericMapping = { STANDARD_RIGHTS_READ, STANDARD_RIGHTS_WRITE, STANDARD_RIGHTS_EXECUTE, STANDARD_RIGHTS_ALL }; PACL Dacl; ULONG SidLen; HANDLE hToken = NULL; NTSTATUS Status, AccessStatus; /* doesn't return gracefully if IsMember is NULL! */ *IsMember = FALSE; SidLen = RtlLengthSid(SidToCheck); if (ExistingTokenHandle == NULL) { Status = NtOpenThreadToken(NtCurrentThread(), TOKEN_QUERY, FALSE, &hToken); if (Status == STATUS_NO_TOKEN) { /* we're not impersonating, open the primary token */ Status = NtOpenProcessToken(NtCurrentProcess(), TOKEN_QUERY | TOKEN_DUPLICATE, &hToken); if (NT_SUCCESS(Status)) { HANDLE hNewToken = FALSE; BOOL DupRet; /* duplicate the primary token to create an impersonation token */ DupRet = DuplicateTokenEx(hToken, TOKEN_QUERY | TOKEN_IMPERSONATE, NULL, SecurityImpersonation, TokenImpersonation, &hNewToken); NtClose(hToken); if (!DupRet) { WARN("Failed to duplicate the primary token!\n"); return FALSE; } hToken = hNewToken; } } if (!NT_SUCCESS(Status)) { goto Cleanup; } } else { hToken = ExistingTokenHandle; } /* create a security descriptor */ SecurityDescriptor = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(SECURITY_DESCRIPTOR) + sizeof(ACL) + SidLen + sizeof(ACCESS_ALLOWED_ACE)); if (SecurityDescriptor == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; } Status = RtlCreateSecurityDescriptor(SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION); if (!NT_SUCCESS(Status)) { goto Cleanup; } /* set the owner and group */ Status = RtlSetOwnerSecurityDescriptor(SecurityDescriptor, SidToCheck, FALSE); if (!NT_SUCCESS(Status)) { goto Cleanup; } Status = RtlSetGroupSecurityDescriptor(SecurityDescriptor, SidToCheck, FALSE); if (!NT_SUCCESS(Status)) { goto Cleanup; } /* create the DACL */ Dacl = (PACL)(SecurityDescriptor + 1); Status = RtlCreateAcl(Dacl, sizeof(ACL) + SidLen + sizeof(ACCESS_ALLOWED_ACE), ACL_REVISION); if (!NT_SUCCESS(Status)) { goto Cleanup; } Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, 0x1, SidToCheck); if (!NT_SUCCESS(Status)) { goto Cleanup; } /* assign the DACL to the security descriptor */ Status = RtlSetDaclSecurityDescriptor(SecurityDescriptor, TRUE, Dacl, FALSE); if (!NT_SUCCESS(Status)) { goto Cleanup; } /* it's time to perform the access check. Just use _some_ desired access right (same as for the ACE) and see if we're getting it granted. This indicates our SID is a member of the token. We however can't use a generic access right as those aren't mapped and return an error (STATUS_GENERIC_NOT_MAPPED). */ Status = NtAccessCheck(SecurityDescriptor, hToken, 0x1, &GenericMapping, &PrivBuffer.PrivilegeSet, &PrivBufferSize, &GrantedAccess, &AccessStatus); if (NT_SUCCESS(Status) && NT_SUCCESS(AccessStatus) && (GrantedAccess == 0x1)) { *IsMember = TRUE; } Cleanup: if (hToken != NULL && hToken != ExistingTokenHandle) { NtClose(hToken); } if (SecurityDescriptor != NULL) { RtlFreeHeap(RtlGetProcessHeap(), 0, SecurityDescriptor); } if (!NT_SUCCESS(Status)) { SetLastError(RtlNtStatusToDosError(Status)); return FALSE; } return TRUE; }
// Open a window station and a desktop in another session, grant access to those handles DWORD GrantRemoteSessionDesktopAccess( IN DWORD sessionId, IN const WCHAR *accountName, IN WCHAR *systemName ) { DWORD status = ERROR_UNIDENTIFIED_ERROR; HRESULT hresult; HANDLE token = NULL; HANDLE tokenDuplicate = NULL; WCHAR fullPath[MAX_PATH + 1] = { 0 }; WCHAR arguments[UNLEN + 1]; PROCESS_INFORMATION pi = { 0 }; STARTUPINFO si = { 0 }; DWORD currentSessionId; if (!accountName) return ERROR_INVALID_PARAMETER; if (!ProcessIdToSessionId(GetCurrentProcessId(), ¤tSessionId)) { return perror("ProcessIdToSessionId"); } if (currentSessionId == sessionId) { // We're in the same session, no need to run an additional process. LogInfo("Already running in the specified session"); status = GrantDesktopAccess(accountName, systemName); if (ERROR_SUCCESS != status) perror2(status, "GrantDesktopAccess"); return status; } if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &token)) { if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token)) { return perror("OpenProcessToken"); } } if (!DuplicateTokenEx( token, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &tokenDuplicate)) { status = perror("DuplicateTokenEx"); goto cleanup; } CloseHandle(token); token = tokenDuplicate; if (!SetTokenInformation(token, TokenSessionId, &sessionId, sizeof(sessionId))) { status = perror("SetTokenInformation"); goto cleanup; } if (!GetModuleFileName(NULL, fullPath, RTL_NUMBER_OF(fullPath) - 1)) { status = perror("GetModuleFileName"); goto cleanup; } hresult = StringCchPrintf(arguments, RTL_NUMBER_OF(arguments), L"\"%s\" -a %s", fullPath, accountName); if (FAILED(hresult)) { LogError("StringCchPrintf failed"); goto cleanup; } si.cb = sizeof(si); LogDebug("CreateProcessAsUser(%s)", arguments); if (!CreateProcessAsUser( token, fullPath, arguments, NULL, NULL, TRUE, // handles are inherited 0, NULL, NULL, &si, &pi)) { status = perror("CreateProcessAsUser"); goto cleanup; } status = WaitForSingleObject(pi.hProcess, 1000); if (WAIT_OBJECT_0 != status) { if (WAIT_TIMEOUT == status) { status = ERROR_ACCESS_DENIED; LogInfo("WaitForSingleObject timed out"); } else { status = perror("WaitForSingleObject"); } } cleanup: if (pi.hThread) CloseHandle(pi.hThread); if (pi.hProcess) CloseHandle(pi.hProcess); if (token) CloseHandle(token); return status; }
BOOL get_winlogon_handle(OUT LPHANDLE lphUserToken, DWORD mysessionID) { BOOL bResult = FALSE; HANDLE hProcess; HANDLE hAccessToken = NULL; HANDLE hTokenThis = NULL; DWORD ID_session=0; ID_session=mysessionID; DWORD Id=0; if (W2K==0) Id=Find_winlogon(ID_session); else Id=GetwinlogonPid(); // fall back to old method if Terminal services is disabled if (W2K == 0 && Id == -1) Id=GetwinlogonPid(); #ifdef _DEBUG char szText[256]; DWORD error=GetLastError(); sprintf(szText," ++++++ Find_winlogon %i %i %d\n",ID_session,Id,error); SetLastError(0); OutputDebugString(szText); #endif hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, Id ); if (hProcess) { #ifdef _DEBUG char szText[256]; DWORD error=GetLastError(); sprintf(szText," ++++++ OpenProcess %i \n",hProcess); SetLastError(0); OutputDebugString(szText); #endif OpenProcessToken(hProcess, TOKEN_ASSIGN_PRIMARY|TOKEN_ALL_ACCESS, &hTokenThis); #ifdef _DEBUG error=GetLastError(); sprintf(szText," ++++++ OpenProcessToken %i %i\n",hTokenThis,error); SetLastError(0); OutputDebugString(szText); #endif { bResult = DuplicateTokenEx(hTokenThis, TOKEN_ASSIGN_PRIMARY|TOKEN_ALL_ACCESS,NULL, SecurityImpersonation, TokenPrimary, lphUserToken); #ifdef _DEBUG error=GetLastError(); sprintf(szText," ++++++ DuplicateTokenEx %i %i %i %i\n",hTokenThis,&lphUserToken,error,bResult); SetLastError(0); OutputDebugString(szText); #endif SetTokenInformation(*lphUserToken, TokenSessionId, &ID_session, sizeof(DWORD)); #ifdef _DEBUG error=GetLastError(); sprintf(szText," ++++++ SetTokenInformation( %i %i %i\n",hTokenThis,&lphUserToken,error); SetLastError(0); OutputDebugString(szText); #endif CloseHandle(hTokenThis); } CloseHandle(hProcess); } return bResult; }
/* * sys_steal_token * ---------- * * Steals the primary token from an existing process */ DWORD request_sys_config_steal_token(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); DWORD dwResult = ERROR_SUCCESS; #ifdef _WIN32 HANDLE hToken = NULL; HANDLE hProcessHandle = NULL; HANDLE hDupToken = NULL; DWORD dwPid; do { // Get the process identifier that we're attaching to, if any. dwPid = packet_get_tlv_value_uint(packet, TLV_TYPE_PID); if (!dwPid) { dwResult = -1; break; } hProcessHandle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwPid); if (!hProcessHandle) { dwResult = GetLastError(); dprintf("[STEAL-TOKEN] Failed to open process handle for %d (%u)", dwPid, dwResult); break; } if (!OpenProcessToken(hProcessHandle, TOKEN_ALL_ACCESS, &hToken)) { dwResult = GetLastError(); dprintf("[STEAL-TOKEN] Failed to open process token for %d (%u)", dwPid, dwResult); break; } if (!ImpersonateLoggedOnUser(hToken)) { dwResult = GetLastError(); dprintf("[STEAL-TOKEN] Failed to impersonate token for %d (%u)", dwPid, dwResult); break; } if (!DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hDupToken)) { dwResult = GetLastError(); dprintf("[STEAL-TOKEN] Failed to duplicate a primary token for %d (%u)", dwPid, dwResult); break; } core_update_thread_token(remote, hDupToken); dwResult = populate_uid(response); } while (0); if (hProcessHandle) { CloseHandle(hProcessHandle); } if (hToken) { CloseHandle(hToken); } #else dwResult = ERROR_NOT_SUPPORTED; #endif // Transmit the response packet_transmit_response(dwResult, remote, response); return dwResult; }
/** * Launch a child process without elevated privilege. */ static BOOL LaunchAsNormalUser(const PRUnichar *exePath, PRUnichar *cl) { #ifdef WINCE return PR_FALSE; #else if (!pCreateProcessWithTokenW) { // IsUserAnAdmin is not present on Win9x and not exported by name on Win2k *(FARPROC *)&pIsUserAnAdmin = GetProcAddress(GetModuleHandleA("shell32.dll"), "IsUserAnAdmin"); // CreateProcessWithTokenW is not present on WinXP or earlier *(FARPROC *)&pCreateProcessWithTokenW = GetProcAddress(GetModuleHandleA("advapi32.dll"), "CreateProcessWithTokenW"); if (!pCreateProcessWithTokenW) return FALSE; } // do nothing here if we are not elevated or IsUserAnAdmin is not present. if (!pIsUserAnAdmin || pIsUserAnAdmin && !pIsUserAnAdmin()) return FALSE; // borrow the shell token to drop the privilege HWND hwndShell = FindWindowA("Progman", NULL); DWORD dwProcessId; GetWindowThreadProcessId(hwndShell, &dwProcessId); HANDLE hProcessShell = OpenProcess(MAXIMUM_ALLOWED, FALSE, dwProcessId); if (!hProcessShell) return FALSE; HANDLE hTokenShell; BOOL ok = OpenProcessToken(hProcessShell, MAXIMUM_ALLOWED, &hTokenShell); CloseHandle(hProcessShell); if (!ok) return FALSE; HANDLE hNewToken; ok = DuplicateTokenEx(hTokenShell, MAXIMUM_ALLOWED, NULL, SecurityDelegation, TokenPrimary, &hNewToken); CloseHandle(hTokenShell); if (!ok) return FALSE; STARTUPINFOW si = {sizeof(si), 0}; PROCESS_INFORMATION pi = {0}; // When launching with reduced privileges, environment inheritance // (passing NULL as lpEnvironment) doesn't work correctly. Pass our // current environment block explicitly WCHAR* myenv = GetEnvironmentStringsW(); ok = pCreateProcessWithTokenW(hNewToken, 0, // profile is already loaded exePath, cl, CREATE_UNICODE_ENVIRONMENT, myenv, // inherit my environment NULL, // use my current directory &si, &pi); if (myenv) FreeEnvironmentStringsW(myenv); CloseHandle(hNewToken); if (!ok) return FALSE; CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return TRUE; #endif }
void impersonateToGetData(PCSTR user, PCSTR domain, PCSTR password, PCSTR kdc, PSID *sid, DWORD *rid, PCSTR usingWhat) { NTSTATUS status; DWORD ret, *aRid, *usage; ANSI_STRING aUser, aKdc, aDomain, aPass, aProg; UNICODE_STRING uUser, uKdc, uDomain, uPass, uProg; SAMPR_HANDLE hServerHandle, hDomainHandle; PSID domainSid; HANDLE hToken, hNewToken; PROCESS_INFORMATION processInfos; STARTUPINFOW startupInfo; RtlZeroMemory(&startupInfo, sizeof(STARTUPINFOW)); startupInfo.cb = sizeof(STARTUPINFOW); RtlInitString(&aUser, user); RtlInitString(&aKdc, kdc); RtlInitString(&aDomain, domain); RtlInitString(&aPass, password); RtlInitString(&aProg, usingWhat ? usingWhat : "winver.exe"); if(NT_SUCCESS(RtlAnsiStringToUnicodeString(&uUser, &aUser, TRUE))) { if(NT_SUCCESS(RtlAnsiStringToUnicodeString(&uKdc, &aKdc, TRUE))) { if(NT_SUCCESS(RtlAnsiStringToUnicodeString(&uDomain, &aDomain, TRUE))) { if(NT_SUCCESS(RtlAnsiStringToUnicodeString(&uPass, &aPass, TRUE))) { if(NT_SUCCESS(RtlAnsiStringToUnicodeString(&uProg, &aProg, TRUE))) { if(CreateProcessWithLogonW(uUser.Buffer, uDomain.Buffer, uPass.Buffer, LOGON_NETCREDENTIALS_ONLY, uProg.Buffer, NULL, CREATE_SUSPENDED, NULL, NULL, &startupInfo, &processInfos)) { if(OpenProcessToken(processInfos.hProcess, TOKEN_DUPLICATE, &hToken)) { if(DuplicateTokenEx(hToken, TOKEN_QUERY | TOKEN_IMPERSONATE, NULL, SecurityDelegation, TokenImpersonation, &hNewToken)) { if(SetThreadToken(NULL, hNewToken)) { kprintf("[AUTH] Impersonation\n"); if(!(*sid && *rid)) { kprintf("[SID/RID] \'%s @ %s\' must be translated to SID/RID\n", user, domain); status = SamConnect(&uKdc, &hServerHandle, SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN, FALSE); if(NT_SUCCESS(status)) { status = SamLookupDomainInSamServer(hServerHandle, &uDomain, &domainSid); if(NT_SUCCESS(status)) { status = SamOpenDomain(hServerHandle, DOMAIN_LIST_ACCOUNTS | DOMAIN_LOOKUP, domainSid, &hDomainHandle); if(NT_SUCCESS(status)) { status = SamLookupNamesInDomain(hDomainHandle, 1, &uUser, &aRid, &usage); if(NT_SUCCESS(status)) *rid = *aRid; else PRINT_ERROR("SamLookupNamesInDomain %08x\n", status); } else PRINT_ERROR("SamOpenDomain %08x\n", status); ret = GetLengthSid(domainSid); if(*sid = (PSID) LocalAlloc(LPTR, ret)) { if(!CopySid(ret, *sid, domainSid)) { *sid = (PSID) LocalFree(*sid); PRINT_ERROR_AUTO("CopySid"); } } SamFreeMemory(domainSid); } else PRINT_ERROR("SamLookupDomainInSamServer %08x\n", status); SamCloseHandle(hServerHandle); } else PRINT_ERROR("SamConnect %08x\n", status); } RevertToSelf(); } else PRINT_ERROR_AUTO("SetThreadToken"); CloseHandle(hNewToken); } else PRINT_ERROR_AUTO("DuplicateTokenEx"); CloseHandle(hToken); } else PRINT_ERROR_AUTO("OpenProcessToken"); TerminateProcess(processInfos.hProcess, 0); CloseHandle(processInfos.hProcess); CloseHandle(processInfos.hThread); } else PRINT_ERROR_AUTO("CreateProcessWithLogonW"); RtlFreeUnicodeString(&uProg); } RtlFreeUnicodeString(&uPass); } RtlFreeUnicodeString(&uDomain); } RtlFreeUnicodeString(&uKdc); } RtlFreeUnicodeString(&uUser); } }
Result<ExitCode> ProcessAsUser::Run(const Settings& settings, ProcessTracker& processTracker) const { Trace trace(settings.GetLogLevel()); trace < L"ProcessAsUser::Attempt to log a user on to the local computer"; StringBuffer userName(settings.GetUserName()); StringBuffer domain(settings.GetDomain()); StringBuffer password(settings.GetPassword()); StringBuffer workingDirectory(settings.GetWorkingDirectory()); StringBuffer commandLine(settings.GetCommandLine()); SecurityManager securityManager; auto setPrivilegesResult = securityManager.SetPrivileges(trace, { SE_TCB_NAME, SE_ASSIGNPRIMARYTOKEN_NAME }, true); if(setPrivilegesResult.HasError()) { return setPrivilegesResult.GetError(); } auto newUserSecurityTokenHandle = Handle(L"New user security token"); unsigned long logonTypeCount = sizeof(allLogonTypes) / sizeof(allLogonTypes[0]); for (unsigned long logonTypeIndex = 0; logonTypeIndex < logonTypeCount; logonTypeIndex++) { auto logonType = allLogonTypes[logonTypeIndex]; trace < L"::LogonUser using logon type "; switch (logonType) { case LOGON32_LOGON_INTERACTIVE: trace << L"LOGON32_LOGON_INTERACTIVE"; break; case LOGON32_LOGON_NETWORK: trace << L"LOGON32_LOGON_NETWORK"; break; case LOGON32_LOGON_BATCH: trace << L"LOGON32_LOGON_BATCH"; break; case LOGON32_LOGON_SERVICE: trace << L"LOGON32_LOGON_SERVICE"; break; } if (LogonUser( userName.GetPointer(), domain.GetPointer(), password.GetPointer(), logonType, LOGON32_PROVIDER_DEFAULT, &newUserSecurityTokenHandle)) { break; } auto error = Error(L"LogonUser"); trace << L" - "; trace << error.GetDescription(); if(logonTypeIndex == logonTypeCount -1) { return error; } } trace < L"ProcessAsUser::InitializeConsoleRedirection a new security descriptor"; trace < L"::InitializeSecurityDescriptor"; SECURITY_DESCRIPTOR securityDescriptor = {}; if (!InitializeSecurityDescriptor( &securityDescriptor, SECURITY_DESCRIPTOR_REVISION)) { return Error(L"InitializeSecurityDescriptor"); } trace < L"::SetSecurityDescriptorDacl"; if (!SetSecurityDescriptorDacl( &securityDescriptor, true, nullptr, false)) { return Error(L"SetSecurityDescriptorDacl"); } trace < L"ProcessAsUser::Creates a new access primary token that duplicates new process's token"; auto primaryNewUserSecurityTokenHandle = Handle(L"Primary new user security token"); SECURITY_ATTRIBUTES processSecAttributes = {}; processSecAttributes.lpSecurityDescriptor = &securityDescriptor; processSecAttributes.nLength = sizeof(SECURITY_DESCRIPTOR); processSecAttributes.bInheritHandle = true; trace < L"::DuplicateTokenEx"; if (!DuplicateTokenEx( newUserSecurityTokenHandle, 0, // MAXIMUM_ALLOWED &processSecAttributes, SecurityImpersonation, TokenPrimary, &primaryNewUserSecurityTokenHandle)) { return Error(L"DuplicateTokenEx"); } SECURITY_ATTRIBUTES threadSecAttributes = {}; threadSecAttributes.lpSecurityDescriptor = nullptr; threadSecAttributes.nLength = 0; threadSecAttributes.bInheritHandle = false; STARTUPINFO startupInfo = {}; trace < L"ProcessTracker::InitializeConsoleRedirection"; auto error = processTracker.InitializeConsoleRedirection(processSecAttributes, startupInfo); if(error.HasError()) { return Result<ExitCode>(error.GetError()); } trace < L"::LoadUserProfile"; PROFILEINFO profileInfo = {}; profileInfo.dwSize = sizeof(PROFILEINFO); profileInfo.lpUserName = userName.GetPointer(); if (!LoadUserProfile(primaryNewUserSecurityTokenHandle, &profileInfo)) { return Error(L"LoadUserProfile"); } auto newProcessEnvironmentResult = GetEnvironment(settings, primaryNewUserSecurityTokenHandle, settings.GetInheritanceMode(), trace); if (newProcessEnvironmentResult.HasError()) { UnloadUserProfile(primaryNewUserSecurityTokenHandle, profileInfo.hProfile); return Result<ExitCode>(newProcessEnvironmentResult.GetError()); } auto setIntegrityLevelResult = securityManager.SetIntegrityLevel(settings.GetIntegrityLevel(), primaryNewUserSecurityTokenHandle, trace); if (setIntegrityLevelResult.HasError()) { return Result<ExitCode>(setIntegrityLevelResult.GetError()); } trace < L"ProcessAsUser::Create a new process and its primary thread. The new process runs in the security context of the user represented by the specified token."; PROCESS_INFORMATION processInformation = {}; startupInfo.dwFlags = STARTF_USESHOWWINDOW; startupInfo.wShowWindow = ShowModeConverter::ToShowWindowFlag(settings.GetShowMode()); auto cmdLine = settings.GetCommandLine(); trace < L"::CreateProcessAsUser"; if (!CreateProcessAsUser( primaryNewUserSecurityTokenHandle, nullptr, commandLine.GetPointer(), &processSecAttributes, &threadSecAttributes, true, CREATE_UNICODE_ENVIRONMENT, newProcessEnvironmentResult.GetResultValue().CreateEnvironment(), workingDirectory.GetPointer(), &startupInfo, &processInformation)) { auto result = Error(L"CreateProcessAsUser"); UnloadUserProfile(primaryNewUserSecurityTokenHandle, profileInfo.hProfile); return result; } // ReSharper disable CppInitializedValueIsAlwaysRewritten // ReSharper disable CppEntityAssignedButNoRead auto processHandle = Handle(L"Service Process"); processHandle = processInformation.hProcess; auto threadHandle = Handle(L"Thread"); threadHandle = processInformation.hThread; auto exitCode = processTracker.WaiteForExit(processInformation.hProcess, trace); UnloadUserProfile(primaryNewUserSecurityTokenHandle, profileInfo.hProfile); return exitCode; }
// // Assert an NT privilege for this thread. // BOOL AssertPrivilege( IN LPCSTR PrivilegeName ) { BOOL b; HANDLE hThread; HANDLE hProcess; TOKEN_PRIVILEGES tokenPrivileges, oldTokenPrivileges; DWORD oldPrivilegesLength; b = OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, TRUE, &hThread); if (!b) { if (GetLastError() != ERROR_NO_TOKEN) { return b; } b = OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE, &hProcess); if (!b) { return b; } b = DuplicateTokenEx(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_IMPERSONATE, NULL, SecurityImpersonation, TokenImpersonation, &hThread); if (!b) { CloseHandle(hProcess); return b; } b = SetThreadToken(NULL, hThread); if (!b) { CloseHandle(hProcess); CloseHandle(hThread); return b; } CloseHandle(hProcess); } ZeroMemory(&tokenPrivileges, sizeof(tokenPrivileges)); b = LookupPrivilegeValue(NULL,PrivilegeName,&tokenPrivileges.Privileges[0].Luid); if (!b) { return b; } tokenPrivileges.PrivilegeCount = 1; tokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; b = AdjustTokenPrivileges(hThread, FALSE, &tokenPrivileges, sizeof(tokenPrivileges), &oldTokenPrivileges, &oldPrivilegesLength); CloseHandle(hThread); return b; }
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); // Updates only for supported platforms if (!supported) fatalError(tr("The qTox updater is not supported on this platform.")); #ifdef Q_OS_WIN // Get a primary unelevated token of the actual user hPrimaryToken = nullptr; HANDLE hShellProcess = nullptr, hShellProcessToken = nullptr; const DWORD dwTokenRights = TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID; DWORD dwPID = 0; HWND hwnd = nullptr; DWORD dwLastErr = 0; // Enable SeIncreaseQuotaPrivilege HANDLE hProcessToken = NULL; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hProcessToken)) goto unelevateFail; TOKEN_PRIVILEGES tkp; tkp.PrivilegeCount = 1; LookupPrivilegeValueW(NULL, SE_INCREASE_QUOTA_NAME, &tkp.Privileges[0].Luid); tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; AdjustTokenPrivileges(hProcessToken, FALSE, &tkp, 0, NULL, NULL); dwLastErr = GetLastError(); CloseHandle(hProcessToken); if (ERROR_SUCCESS != dwLastErr) goto unelevateFail; // Get a primary copy of the desktop shell's token, // we're assuming the shell is running as the actual user hwnd = GetShellWindow(); if (!hwnd) goto unelevateFail; GetWindowThreadProcessId(hwnd, &dwPID); if (!dwPID) goto unelevateFail; hShellProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwPID); if (!hShellProcess) goto unelevateFail; if (!OpenProcessToken(hShellProcess, TOKEN_DUPLICATE, &hShellProcessToken)) goto unelevateFail; // Duplicate the shell's process token to get a primary token. // Based on experimentation, this is the minimal set of rights required for CreateProcessWithTokenW (contrary to current documentation). if (!DuplicateTokenEx(hShellProcessToken, dwTokenRights, NULL, SecurityImpersonation, TokenPrimary, &hPrimaryToken)) goto unelevateFail; qDebug() << "Unelevated primary access token acquired"; goto unelevateCleanup; unelevateFail: qWarning() << "Unelevate failed, couldn't get access token"; unelevateCleanup: CloseHandle(hShellProcessToken); CloseHandle(hShellProcess); #endif QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection); }