1014 lines
36 KiB
C++
1014 lines
36 KiB
C++
/***
|
|
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
|
|
|
File: AuProcessElevation.NT.cpp
|
|
Date: 2023-12-23
|
|
Author: Reece
|
|
***/
|
|
#include <Source/RuntimeInternal.hpp>
|
|
#include "AuProcessElevation.NT.hpp"
|
|
|
|
#include <tlhelp32.h>
|
|
|
|
enum _SE_OBJECT_TYPE
|
|
{
|
|
SE_KERNEL_OBJECT = 6
|
|
};
|
|
|
|
#if !defined(POLICY_ALL_ACCESS)
|
|
#define POLICY_ALL_ACCESS 0xf0fff
|
|
#endif
|
|
|
|
namespace Aurora::Processes
|
|
{
|
|
struct SecureRunAs
|
|
{
|
|
RunAsDescriptor desc;
|
|
AuList<int> pids {};
|
|
bool bRepeat {};
|
|
SECURITY_DESCRIPTOR sd {};
|
|
|
|
void BlankMemory()
|
|
{
|
|
if (this->desc.password)
|
|
{
|
|
AuMemset(this->desc.password.value().data(),
|
|
0,
|
|
this->desc.password.value().size());
|
|
}
|
|
}
|
|
|
|
static HANDLE GetProcessTokenHandle()
|
|
{
|
|
static HANDLE gHandle = INVALID_HANDLE_VALUE;
|
|
static AuInitOnce gInitOnce;
|
|
|
|
if (pOpenProcessToken)
|
|
{
|
|
gInitOnce.Call([&]()
|
|
{
|
|
pOpenProcessToken(OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId()),
|
|
TOKEN_ALL_ACCESS, &gHandle);
|
|
});
|
|
}
|
|
|
|
return gHandle;
|
|
}
|
|
|
|
static DWORD GetTokenIntegrityLevel()
|
|
{
|
|
char buffer[1000];
|
|
TOKEN_MANDATORY_LABEL &info = *(TOKEN_MANDATORY_LABEL *)buffer;
|
|
DWORD dwLength { 1000 };
|
|
|
|
if (!pGetTokenInformation ||
|
|
!pGetSidSubAuthority ||
|
|
!pGetSidSubAuthorityCount)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if (!pGetTokenInformation(GetProcessTokenHandle(), TokenIntegrityLevel, &info, 1000, &dwLength))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
auto pSid = info.Label.Sid;
|
|
auto dwIntegrityLevel = *(pGetSidSubAuthority(pSid, (*(pGetSidSubAuthorityCount(pSid)) - 1U)));
|
|
|
|
if (dwIntegrityLevel == SECURITY_MANDATORY_LOW_RID)
|
|
{
|
|
return dwIntegrityLevel;
|
|
}
|
|
else if (dwIntegrityLevel >= SECURITY_MANDATORY_MEDIUM_RID && dwIntegrityLevel < SECURITY_MANDATORY_HIGH_RID)
|
|
{
|
|
return SECURITY_MANDATORY_MEDIUM_RID;
|
|
}
|
|
else if (dwIntegrityLevel >= SECURITY_MANDATORY_HIGH_RID)
|
|
{
|
|
return SECURITY_MANDATORY_HIGH_RID;
|
|
}
|
|
else if (dwIntegrityLevel >= SECURITY_MANDATORY_SYSTEM_RID)
|
|
{
|
|
return SECURITY_MANDATORY_SYSTEM_RID;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static bool SetTokenIntegrityLevel(HANDLE hToken,
|
|
DWORD dwIntegrity)
|
|
{
|
|
static const BYTE kSidPattern[6] { 0, 0, 0, 0, 0, 16 };
|
|
TOKEN_MANDATORY_LABEL tokenLabel {};
|
|
SID_IDENTIFIER_AUTHORITY sidAuth;
|
|
AuMemcpy(sidAuth.Value, kSidPattern, sizeof(sidAuth.Value));
|
|
|
|
if (!pSetTokenInformation ||
|
|
!pAllocateAndInitializeSid)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
PSID sid;
|
|
if (!pAllocateAndInitializeSid(&sidAuth,
|
|
1,
|
|
dwIntegrity, 0, 0, 0, 0, 0, 0, 0,
|
|
&sid))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
tokenLabel.Label.Sid = sid;
|
|
tokenLabel.Label.Attributes = SE_GROUP_INTEGRITY;
|
|
return pSetTokenInformation(hToken,
|
|
TokenIntegrityLevel,
|
|
&tokenLabel,
|
|
sizeof(TOKEN_MANDATORY_LABEL));
|
|
}
|
|
|
|
static bool IsAdmn()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
enum class EPrompt
|
|
{
|
|
eError,
|
|
eCancel,
|
|
eOK
|
|
};
|
|
|
|
static EPrompt PromptForCreds(std::wstring &wideusername,
|
|
std::wstring &widepassword,
|
|
SecureRunAs *pRunAs,
|
|
const std::wstring &wideserver)
|
|
{
|
|
LPVOID pAuthBuffer;
|
|
ULONG ulPackageLen {};
|
|
ULONG ulAuthLen {};
|
|
bool bSecond {};
|
|
CREDUI_INFOW info {};
|
|
|
|
if (!pCredUnPackAuthenticationBufferW ||
|
|
!pCredUIPromptForWindowsCredentialsW ||
|
|
!pCoTaskMemFree)
|
|
{
|
|
return EPrompt::eError;
|
|
}
|
|
|
|
info.cbSize = sizeof(info);
|
|
info.pszCaptionText = L"User Account Control";
|
|
info.pszMessageText = L"";
|
|
|
|
AuString a { "Please log in to elevate the process to " };
|
|
if (pRunAs->desc.runAs == ERunAsUser::eSpecifiedImpersonation)
|
|
{
|
|
if (pRunAs->desc.impersonate)
|
|
{
|
|
a += pRunAs->desc.impersonate.value();
|
|
}
|
|
}
|
|
else if (pRunAs->desc.runAs == ERunAsUser::eRegularUser)
|
|
{
|
|
if (wideusername.size())
|
|
{
|
|
a = fmt::format("Please log in to your account ({})", AuLocale::ConvertFromWChar(wideusername.data()));
|
|
}
|
|
else
|
|
{
|
|
a = "Please log in to your account";
|
|
}
|
|
}
|
|
else if (pRunAs->desc.runAs == ERunAsUser::eSuperUser)
|
|
{
|
|
a += "Administrator status";
|
|
}
|
|
else
|
|
{
|
|
switch (pRunAs->desc.runAs)
|
|
{
|
|
case ERunAsUser::eNTAS:
|
|
{
|
|
a += "NT Authority\\SYSTEM";
|
|
break;
|
|
}
|
|
case ERunAsUser::eNTTI:
|
|
{
|
|
a += "Trusted Installer";
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
auto tempMessageBuffer = AuLocale::ConvertFromUTF8(a);
|
|
info.pszMessageText = tempMessageBuffer.data();
|
|
|
|
HRESULT result = pCredUIPromptForWindowsCredentialsW(&info,
|
|
0,
|
|
&ulPackageLen,
|
|
{}, 0,
|
|
&pAuthBuffer, &ulAuthLen,
|
|
nullptr,
|
|
0x1);
|
|
if (result != ERROR_SUCCESS)
|
|
{
|
|
if (result == ERROR_CANCELLED)
|
|
{
|
|
return EPrompt::eCancel;
|
|
}
|
|
else
|
|
{
|
|
return EPrompt::eError;
|
|
}
|
|
}
|
|
|
|
wideusername.resize(512);
|
|
widepassword.resize(512);
|
|
DWORD dwUsernameLen = wideusername.size();
|
|
DWORD dwPasswordLen = widepassword.size();
|
|
|
|
bSecond = pCredUnPackAuthenticationBufferW(0,
|
|
pAuthBuffer, ulAuthLen,
|
|
wideusername.data(), &dwUsernameLen,
|
|
nullptr /*TODO: server*/, 0,
|
|
widepassword.data(), &dwPasswordLen);
|
|
|
|
wideusername.resize(dwUsernameLen - 1);
|
|
widepassword.resize(dwPasswordLen - 1);
|
|
|
|
AuMemset(pAuthBuffer, 0, ulAuthLen);
|
|
pCoTaskMemFree(pAuthBuffer);
|
|
|
|
if (result == ERROR_SUCCESS &&
|
|
bSecond)
|
|
{
|
|
return EPrompt::eOK;
|
|
}
|
|
else
|
|
{
|
|
return EPrompt::eError;
|
|
}
|
|
}
|
|
|
|
static std::wstring GetUsername()
|
|
{
|
|
wchar_t buffer[512];
|
|
DWORD dwLength = AuArraySize(buffer);
|
|
|
|
if (!pGetUserNameW)
|
|
{
|
|
return {};
|
|
}
|
|
|
|
if (!pGetUserNameW(buffer, &dwLength))
|
|
{
|
|
return {};
|
|
}
|
|
|
|
return { buffer, dwLength };
|
|
}
|
|
|
|
static bool GetSidOfUser(const std::wstring &username,
|
|
AuList<AuUInt8> buffer,
|
|
PSID *ppSid)
|
|
{
|
|
static const auto kDefaultSize = 32;
|
|
buffer.resize(kDefaultSize);
|
|
bool bOk {};
|
|
|
|
if (!pLookupAccountNameW)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
while (!bOk)
|
|
{
|
|
SID_NAME_USE eSidType;
|
|
AuList<wchar_t> dmain;
|
|
dmain.resize(2024);
|
|
|
|
DWORD dw = dmain.size();
|
|
DWORD cbSid = buffer.size();
|
|
|
|
if (pLookupAccountNameW(NULL,
|
|
username.c_str(),
|
|
(PSID)buffer.data(),
|
|
&cbSid,
|
|
dmain.data(),
|
|
&dw,
|
|
&eSidType))
|
|
{
|
|
bOk = true;
|
|
break;
|
|
}
|
|
|
|
auto dwErrorCode = GetLastError();
|
|
|
|
if (dwErrorCode == ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
buffer.resize(cbSid);
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (bOk)
|
|
{
|
|
*ppSid = (PSID)buffer.data();
|
|
}
|
|
|
|
return bOk;
|
|
}
|
|
|
|
static HANDLE GetToken(DWORD pid)
|
|
{
|
|
HANDLE hToken;
|
|
|
|
auto hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
|
|
if (!hProcess)
|
|
{
|
|
return {};
|
|
}
|
|
|
|
if (!pOpenProcessToken)
|
|
{
|
|
return {};
|
|
}
|
|
|
|
if (!pOpenProcessToken(hProcess, MAXIMUM_ALLOWED, &hToken))
|
|
{
|
|
hToken = {};
|
|
}
|
|
|
|
CloseHandle(hProcess);
|
|
|
|
return hToken;
|
|
}
|
|
|
|
static void GetSelfSID(std::function<void(PSID)> callback)
|
|
{
|
|
auto hToken = GetProcessTokenHandle();
|
|
|
|
if (!pGetTokenInformation)
|
|
{
|
|
return;
|
|
}
|
|
|
|
DWORD dwSize {};
|
|
if (!pGetTokenInformation(hToken, TokenUser, NULL, 0, &dwSize) &&
|
|
GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
return;
|
|
}
|
|
|
|
AuList<AuInt8> buf(dwSize, '\x00');
|
|
auto pTokenUser = (PTOKEN_USER)buf.data();
|
|
if (!pGetTokenInformation(hToken, TokenUser, pTokenUser, dwSize, &dwSize))
|
|
{
|
|
return;
|
|
}
|
|
|
|
callback(pTokenUser->User.Sid);
|
|
}
|
|
|
|
void SetRight(HANDLE hAdmin)
|
|
{
|
|
if (!pLsaOpenPolicy ||
|
|
!pLsaAddAccountRights ||
|
|
!pLsaClose ||
|
|
!pRevertToSelf)
|
|
{
|
|
return;
|
|
}
|
|
|
|
pRevertToSelf();
|
|
|
|
GetSelfSID([=](PSID pSelf)
|
|
{
|
|
if (pSetThreadToken)
|
|
{
|
|
pSetThreadToken(NULL, hAdmin);
|
|
}
|
|
|
|
LSA_OBJECT_ATTRIBUTES attr {};
|
|
LSA_HANDLE hHandle;
|
|
|
|
if (pLsaOpenPolicy(NULL, &attr, POLICY_ALL_ACCESS, &hHandle) == 0)
|
|
{
|
|
LSA_UNICODE_STRING unistr;
|
|
unistr.Buffer = (PWSTR)L"SeAssignPrimaryTokenPrivilege";
|
|
unistr.Length = 29 * 2;
|
|
unistr.MaximumLength = 29 * 2;
|
|
|
|
if (pLsaAddAccountRights(hHandle,
|
|
pSelf,
|
|
&unistr,
|
|
1) == 0)
|
|
{
|
|
this->bRepeat = true;
|
|
}
|
|
}
|
|
|
|
pLsaClose(hHandle);
|
|
});
|
|
}
|
|
|
|
static AuString GetProcessUserName(DWORD pid)
|
|
{
|
|
AuString username;
|
|
wchar_t lpName[MAX_PATH];
|
|
wchar_t lpDomain[MAX_PATH];
|
|
DWORD dwNameSize { MAX_PATH };
|
|
DWORD dwDomainSize { MAX_PATH };
|
|
SID_NAME_USE SidType;
|
|
|
|
if (!pLookupAccountSidW ||
|
|
!pOpenProcessToken ||
|
|
!pGetTokenInformation)
|
|
{
|
|
return {};
|
|
}
|
|
|
|
HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
|
|
if (!hProcess)
|
|
{
|
|
return {};
|
|
}
|
|
|
|
HANDLE hToken {};
|
|
if (!pOpenProcessToken(hProcess, TOKEN_QUERY, &hToken))
|
|
{
|
|
CloseHandle(hProcess);
|
|
return {};
|
|
}
|
|
|
|
DWORD dwSize {};
|
|
if (!pGetTokenInformation(hToken, TokenUser, NULL, 0, &dwSize) &&
|
|
GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
CloseHandle(hToken);
|
|
CloseHandle(hProcess);
|
|
return {};
|
|
}
|
|
|
|
AuList<AuInt8> buf(dwSize, '\x00');
|
|
auto pTokenUser = (PTOKEN_USER)buf.data();
|
|
if (!pGetTokenInformation(hToken, TokenUser, pTokenUser, dwSize, &dwSize))
|
|
{
|
|
CloseHandle(hToken);
|
|
CloseHandle(hProcess);
|
|
return {};
|
|
}
|
|
|
|
if (!pLookupAccountSidW(NULL, pTokenUser->User.Sid, lpName, &dwNameSize, lpDomain, &dwDomainSize, &SidType))
|
|
{
|
|
CloseHandle(hToken);
|
|
CloseHandle(hProcess);
|
|
return {};
|
|
}
|
|
|
|
username = AuLocale::ConvertFromWChar(lpDomain);
|
|
username += "/";
|
|
username += AuLocale::ConvertFromWChar(lpName);
|
|
|
|
CloseHandle(hToken);
|
|
CloseHandle(hProcess);
|
|
return username;
|
|
}
|
|
|
|
void CachePids()
|
|
{
|
|
HANDLE hProcSnap;
|
|
PROCESSENTRY32 pe32;
|
|
|
|
if (this->pids.size())
|
|
{
|
|
return;
|
|
}
|
|
|
|
hProcSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
|
pe32.dwSize = sizeof(PROCESSENTRY32);
|
|
|
|
if (!Process32First(hProcSnap, &pe32))
|
|
{
|
|
CloseHandle(hProcSnap);
|
|
return;
|
|
}
|
|
|
|
while (Process32Next(hProcSnap, &pe32))
|
|
{
|
|
if (AuToLower(GetProcessUserName(pe32.th32ProcessID)) == "nt authority/system")
|
|
{
|
|
this->pids.push_back(pe32.th32ProcessID);
|
|
}
|
|
}
|
|
|
|
CloseHandle(hProcSnap);
|
|
}
|
|
|
|
static bool EnableTokenPrivilege(HANDLE hToken,
|
|
const char *lpName)
|
|
{
|
|
LUID luidValue { };
|
|
TOKEN_PRIVILEGES tokenPrivileges;
|
|
|
|
if (!pLookupPrivilegeValueA ||
|
|
!pAdjustTokenPrivileges)
|
|
{
|
|
return {};
|
|
}
|
|
|
|
if (!pLookupPrivilegeValueA(NULL,
|
|
lpName,
|
|
&luidValue))
|
|
{
|
|
return {};
|
|
}
|
|
|
|
tokenPrivileges.PrivilegeCount = 1;
|
|
tokenPrivileges.Privileges[0].Luid = luidValue;
|
|
tokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
|
return pAdjustTokenPrivileges(hToken,
|
|
FALSE,
|
|
&tokenPrivileges,
|
|
sizeof(tokenPrivileges),
|
|
NULL,
|
|
NULL);
|
|
}
|
|
|
|
static void AddGenericElPerms(HANDLE hHandle)
|
|
{
|
|
EnableTokenPrivilege(hHandle, SE_DEBUG_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_CREATE_TOKEN_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_INCREASE_QUOTA_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_ASSIGNPRIMARYTOKEN_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_TCB_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_IMPERSONATE_NAME);
|
|
}
|
|
|
|
static void AddAllTokenPrivileges(HANDLE hHandle)
|
|
{
|
|
EnableTokenPrivilege(hHandle, SE_CREATE_TOKEN_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_ASSIGNPRIMARYTOKEN_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_LOCK_MEMORY_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_INCREASE_QUOTA_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_UNSOLICITED_INPUT_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_MACHINE_ACCOUNT_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_TCB_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_SECURITY_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_TAKE_OWNERSHIP_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_LOAD_DRIVER_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_SYSTEM_PROFILE_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_SYSTEMTIME_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_PROF_SINGLE_PROCESS_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_INC_BASE_PRIORITY_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_CREATE_PAGEFILE_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_CREATE_PERMANENT_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_BACKUP_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_RESTORE_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_SHUTDOWN_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_DEBUG_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_AUDIT_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_SYSTEM_ENVIRONMENT_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_CHANGE_NOTIFY_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_REMOTE_SHUTDOWN_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_UNDOCK_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_SYNC_AGENT_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_ENABLE_DELEGATION_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_MANAGE_VOLUME_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_IMPERSONATE_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_CREATE_GLOBAL_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_TRUSTED_CREDMAN_ACCESS_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_RELABEL_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_INC_WORKING_SET_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_TIME_ZONE_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_CREATE_SYMBOLIC_LINK_NAME);
|
|
EnableTokenPrivilege(hHandle, SE_DELEGATE_SESSION_USER_IMPERSONATE_NAME);
|
|
}
|
|
|
|
bool TrySpawn(AuFunction<bool(HANDLE)> trySpawn, HANDLE hAdminToken)
|
|
{
|
|
CachePids();
|
|
|
|
if (!pSetThreadToken ||
|
|
!pRevertToSelf)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (hAdminToken)
|
|
{
|
|
AddGenericElPerms(hAdminToken);
|
|
}
|
|
|
|
for (const auto &pid : pids)
|
|
{
|
|
HANDLE hToken = GetToken(pid);
|
|
if (!hToken)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
AddGenericElPerms(hToken);
|
|
|
|
pSetThreadToken(NULL, hToken);
|
|
|
|
auto bSuccess = trySpawn(hToken);
|
|
|
|
if (hAdminToken)
|
|
{
|
|
pSetThreadToken(NULL, hAdminToken);
|
|
}
|
|
else
|
|
{
|
|
pRevertToSelf();
|
|
}
|
|
|
|
CloseHandle(hToken);
|
|
|
|
if (bSuccess)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool GetCurrentSessionId(DWORD &dwSessionId)
|
|
{
|
|
DWORD dwLength {};
|
|
return pGetTokenInformation &&
|
|
pGetTokenInformation(GetProcessTokenHandle(),
|
|
TokenSessionId,
|
|
&dwSessionId,
|
|
sizeof(DWORD),
|
|
&dwLength);
|
|
|
|
}
|
|
|
|
BOOL Exec(LPCWSTR lpApplicationName,
|
|
LPWSTR lpCommandLine,
|
|
LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
|
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
|
BOOL bInheritHandles,
|
|
DWORD dwCreationFlags,
|
|
LPVOID lpEnvironment,
|
|
LPCWSTR lpCurrentDirectory,
|
|
LPSTARTUPINFOW lpStartupInfo,
|
|
LPPROCESS_INFORMATION lpProcessInformation)
|
|
{
|
|
DWORD dwSesssionId;
|
|
GetCurrentSessionId(dwSesssionId);
|
|
|
|
std::wstring widepassword;
|
|
std::wstring wideusername;
|
|
std::wstring wideserver;
|
|
DWORD dwResult {};
|
|
bool bResult {};
|
|
wchar_t *pWideServer {};
|
|
bool bRequiresUnprivAuth { true };
|
|
bool bUseUsualTokenLogin { false };
|
|
bool bRetToSelf { false };
|
|
bool bEsclToAdmin { false };
|
|
bool bDoAdmnTokenLookup { false };
|
|
bool bIsSpecialAccount { false };
|
|
bool bPrompting { false };
|
|
HANDLE hBestToken { INVALID_HANDLE_VALUE };
|
|
DWORD dwLoginFlags { LOGON_NETCREDENTIALS_ONLY };
|
|
|
|
dwCreationFlags |= CREATE_BREAKAWAY_FROM_JOB |
|
|
CREATE_DEFAULT_ERROR_MODE |
|
|
CREATE_NEW_CONSOLE |
|
|
CREATE_NEW_PROCESS_GROUP;
|
|
|
|
if (this->desc.bLoginWithProfile)
|
|
{
|
|
static wchar_t lpDesktop[] = L"WinSta0\\Default";
|
|
|
|
dwLoginFlags = LOGON_WITH_PROFILE;
|
|
lpStartupInfo->lpDesktop = lpDesktop;
|
|
}
|
|
|
|
|
|
if (this->desc.username)
|
|
{
|
|
wideusername = AuLocale::ConvertFromUTF8(this->desc.username.value().c_str());
|
|
AuMemset(this->desc.username.value().data(), 0xFF, this->desc.username.value().size());
|
|
}
|
|
|
|
if (this->desc.password)
|
|
{
|
|
widepassword = AuLocale::ConvertFromUTF8(this->desc.password.value().c_str());
|
|
AuMemset(this->desc.password.value().data(), 0xFF, this->desc.password.value().size());
|
|
}
|
|
|
|
if (this->desc.server)
|
|
{
|
|
wideserver = AuLocale::ConvertFromUTF8(this->desc.server.value().c_str());
|
|
}
|
|
|
|
if (widepassword.empty() ||
|
|
wideusername.empty())
|
|
{
|
|
EPrompt status;
|
|
|
|
if (wideusername.empty())
|
|
{
|
|
wideusername = GetUsername();
|
|
}
|
|
|
|
bPrompting = true;
|
|
|
|
do
|
|
{
|
|
status = PromptForCreds(wideusername, widepassword, this, wideserver);
|
|
|
|
if (status == EPrompt::eCancel)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (status == EPrompt::eError)
|
|
{
|
|
SysPushErrorGeneric("Generic logon prompt failure");
|
|
return false;
|
|
}
|
|
}
|
|
while (wideusername.empty() &&
|
|
status == EPrompt::eOK);
|
|
}
|
|
|
|
if (wideserver.empty() ||
|
|
wideserver == L"." ||
|
|
wideserver == L"localhost")
|
|
{
|
|
wideserver = L".";
|
|
pWideServer = nullptr;
|
|
}
|
|
else
|
|
{
|
|
pWideServer = wideserver.data();
|
|
}
|
|
|
|
if (IsAdmn())
|
|
{
|
|
bRequiresUnprivAuth = false;
|
|
}
|
|
|
|
if (wideusername.empty())
|
|
{
|
|
AuMemset(widepassword.data(), 0xFF, widepassword.size());
|
|
SysPushErrorPermissionError("Missing Username");
|
|
return false;
|
|
}
|
|
|
|
if (bRequiresUnprivAuth)
|
|
{
|
|
do
|
|
{
|
|
if (!pLogonUserW(wideusername.c_str(),
|
|
pWideServer,
|
|
widepassword.c_str(),
|
|
LOGON32_LOGON_NETWORK_CLEARTEXT,
|
|
LOGON32_PROVIDER_DEFAULT,
|
|
&hBestToken))
|
|
{
|
|
auto dwErrorCode = GetLastError();
|
|
|
|
if (dwErrorCode == 1327)
|
|
{
|
|
SysPushErrorPermissionError("You must have a password or modify COMPUTER\\HKLM\\SYSTEM\\CurrentControlSet\\Control\\Lsa\\LimitBlankPasswordUse=1");
|
|
return false;
|
|
}
|
|
|
|
if (dwErrorCode == 1326)
|
|
{
|
|
if (bPrompting)
|
|
{
|
|
auto status = PromptForCreds(wideusername, widepassword, this, wideserver);
|
|
|
|
if (status == EPrompt::eCancel ||
|
|
wideusername.empty())
|
|
{
|
|
AuMemset(wideusername.data(), 0xFF, wideusername.size() * sizeof(wchar_t));
|
|
AuMemset(widepassword.data(), 0xFF, widepassword.size() * sizeof(wchar_t));
|
|
return false;
|
|
}
|
|
|
|
if (status == EPrompt::eError)
|
|
{
|
|
|
|
AuMemset(wideusername.data(), 0xFF, wideusername.size() * sizeof(wchar_t));
|
|
AuMemset(widepassword.data(), 0xFF, widepassword.size() * sizeof(wchar_t));
|
|
SysPushErrorGeneric("Generic logon prompt failure");
|
|
return false;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
SysPushErrorPermissionError("Invalid username or password. This event has been logged.");
|
|
return false;
|
|
}
|
|
|
|
SysPushErrorGeneric("Unable to login");
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
if (this->desc.runAs != ERunAsUser::eRegularUser)
|
|
{
|
|
bEsclToAdmin = true;
|
|
|
|
if (this->desc.runAs != ERunAsUser::eSuperUser)
|
|
{
|
|
bDoAdmnTokenLookup = true;
|
|
bIsSpecialAccount = true;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
while (bPrompting);
|
|
}
|
|
else
|
|
{
|
|
bDoAdmnTokenLookup = true;
|
|
}
|
|
|
|
if (bEsclToAdmin)
|
|
{
|
|
if (!SetTokenIntegrityLevel(hBestToken,
|
|
GetTokenIntegrityLevel()))
|
|
{
|
|
SysPushErrorPermissionError("Unable to elevate");
|
|
return false;
|
|
}
|
|
|
|
if (pSetSecurityInfo((HANDLE)-1,
|
|
SE_KERNEL_OBJECT,
|
|
DACL_SECURITY_INFORMATION,
|
|
{}, {}, {}, {}) != ERROR_SUCCESS)
|
|
{
|
|
SysPushErrorPermissionError("Unable to elevate");
|
|
AuMemset(wideusername.data(), 0xFF, wideusername.size() * sizeof(wchar_t));
|
|
AuMemset(widepassword.data(), 0xFF, widepassword.size() * sizeof(wchar_t));
|
|
return false;
|
|
}
|
|
|
|
bRetToSelf = true;
|
|
}
|
|
|
|
DWORD dwErrorCode {};
|
|
if (bIsSpecialAccount)
|
|
{
|
|
EnableTokenPrivilege(GetProcessTokenHandle(), SE_DEBUG_NAME);
|
|
|
|
CachePids();
|
|
|
|
SetRight(hBestToken);
|
|
|
|
if (this->bRepeat)
|
|
{
|
|
CloseHandle(hBestToken);
|
|
|
|
if (!pLogonUserW(wideusername.c_str(),
|
|
pWideServer,
|
|
widepassword.c_str(),
|
|
LOGON32_LOGON_NETWORK_CLEARTEXT,
|
|
LOGON32_PROVIDER_DEFAULT,
|
|
&hBestToken))
|
|
{
|
|
AuMemset(wideusername.data(), 0xFF, wideusername.size() * sizeof(wchar_t));
|
|
AuMemset(widepassword.data(), 0xFF, widepassword.size() * sizeof(wchar_t));
|
|
return false;
|
|
}
|
|
|
|
|
|
if (!SetTokenIntegrityLevel(hBestToken,
|
|
GetTokenIntegrityLevel()))
|
|
{
|
|
SysPushErrorPermissionError("Unable to elevate");
|
|
AuMemset(wideusername.data(), 0xFF, wideusername.size() * sizeof(wchar_t));
|
|
AuMemset(widepassword.data(), 0xFF, widepassword.size() * sizeof(wchar_t));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
TrySpawn([&](HANDLE h) -> bool
|
|
{
|
|
HANDLE hToken2;
|
|
if (!pDuplicateTokenEx(h,
|
|
MAXIMUM_ALLOWED,
|
|
NULL,
|
|
SecurityImpersonation,
|
|
TokenPrimary,
|
|
&hToken2))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
(void)pSetTokenInformation(hToken2, TokenSessionId, &dwSesssionId, sizeof(dwSesssionId));
|
|
|
|
pSetThreadToken(NULL, hToken2);
|
|
AddAllTokenPrivileges(hToken2);
|
|
|
|
pSetThreadToken(NULL, hBestToken);
|
|
bResult = pCreateProcessAsUserW(hToken2,
|
|
lpApplicationName,
|
|
lpCommandLine,
|
|
0,
|
|
NULL,
|
|
TRUE,
|
|
dwCreationFlags,
|
|
lpEnvironment,
|
|
lpCurrentDirectory,
|
|
lpStartupInfo,
|
|
lpProcessInformation);
|
|
dwErrorCode = GetLastError();
|
|
CloseHandle(hToken2);
|
|
return bResult;
|
|
}, NULL);
|
|
|
|
bUseUsualTokenLogin = true;
|
|
}
|
|
|
|
|
|
if (bUseUsualTokenLogin)
|
|
{
|
|
// Moved
|
|
if (!bResult)
|
|
{
|
|
SetLastError(dwErrorCode);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pSetThreadToken(NULL, hBestToken);
|
|
AddAllTokenPrivileges(hBestToken);
|
|
bResult = pCreateProcessWithLogonW(wideusername.c_str(),
|
|
wideserver.data(),
|
|
widepassword.c_str(),
|
|
dwLoginFlags,
|
|
lpApplicationName,
|
|
lpCommandLine,
|
|
dwCreationFlags,
|
|
lpEnvironment,
|
|
lpCurrentDirectory,
|
|
lpStartupInfo,
|
|
lpProcessInformation);
|
|
}
|
|
|
|
if (bRetToSelf)
|
|
{
|
|
pRevertToSelf();
|
|
}
|
|
|
|
AuMemset(wideusername.data(), 0xFF, wideusername.size() * sizeof(wchar_t));
|
|
AuMemset(widepassword.data(), 0xFF, widepassword.size() * sizeof(wchar_t));
|
|
|
|
AuWin32CloseHandle(hBestToken);
|
|
|
|
if (!bResult)
|
|
{
|
|
SysPushErrorGeneric("Couldn't spawn elevated process");
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
void FixSharedAttrs(SECURITY_ATTRIBUTES *pAttrs)
|
|
{
|
|
if (pInitializeSecurityDescriptor &&
|
|
pSetSecurityDescriptorDacl)
|
|
{
|
|
// let everybody on the system read our shared pipes (the easiest way to fixup inter-privileged ipc)
|
|
pAttrs->lpSecurityDescriptor = &this->sd;
|
|
pInitializeSecurityDescriptor(&this->sd, SECURITY_DESCRIPTOR_REVISION);
|
|
pSetSecurityDescriptorDacl(&this->sd, TRUE, NULL, FALSE);
|
|
}
|
|
}
|
|
};
|
|
|
|
AUKN_SYM void RunAs(StartupParameters &startupParameters,
|
|
RunAsDescriptor &runAs)
|
|
{
|
|
auto pThat = AuMakeSharedThrow<SecureRunAs>();
|
|
pThat->desc = AuMove(runAs);
|
|
startupParameters.bForceNoJobParent = true;
|
|
startupParameters.ntLikeHookCreateProcessW = std::bind(&SecureRunAs::Exec, pThat,
|
|
std::placeholders::_1, std::placeholders::_2,
|
|
std::placeholders::_3, std::placeholders::_4,
|
|
std::placeholders::_5, std::placeholders::_6,
|
|
std::placeholders::_7, std::placeholders::_8,
|
|
std::placeholders::_9, std::placeholders::_10);
|
|
startupParameters.ntFixSharedHandleAttrs = std::bind(&SecureRunAs::FixSharedAttrs, pThat,
|
|
std::placeholders::_1);
|
|
|
|
}
|
|
} |