[+] AuProcesses::RunAs
This commit is contained in:
parent
662dbac0c1
commit
f404e8960f
@ -14,5 +14,6 @@
|
||||
#include "StartupParameters.hpp"
|
||||
#include "Spawn.hpp"
|
||||
#include "OutputOf.hpp"
|
||||
#include "RunAs.hpp"
|
||||
|
||||
#include "Open.hpp"
|
54
Include/Aurora/Processes/RunAs.hpp
Normal file
54
Include/Aurora/Processes/RunAs.hpp
Normal file
@ -0,0 +1,54 @@
|
||||
/***
|
||||
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: RunAs.hpp
|
||||
Date: 2023-12-23
|
||||
Author: Reece
|
||||
***/
|
||||
#pragma once
|
||||
|
||||
namespace Aurora::Processes
|
||||
{
|
||||
AUE_DEFINE(ERunAsUser, (
|
||||
eRegularUser, //
|
||||
eSpecifiedImpersonation, // Privileged impersonation using admin creds and stated alternative uid/username (*)
|
||||
eSuperUser, // Privileged status (root, standard run-as-admin privileges, etc)
|
||||
eNTAS, // NT Authority/SYSTEM (*)
|
||||
eNTTI // Trusted Installer (*)
|
||||
));
|
||||
// (*) These APIs are somewhat spicey
|
||||
|
||||
// Warning: In the default configurations of Windows, spawning processes with shared handles and such as elevated processes is generally not supported.
|
||||
// The Aurora Runtime is importing APIs that'll probably make old anti-virus engines mald after sometime. However, it isn't some magic le epic uac bypass.
|
||||
// You still need to have privileged credentials to hand. This should be noted bc retards on reddit and orange site are probably going to complain
|
||||
// "hurhur this is malware. look, its editing policies and impersonating the UAC logon prompt in process. ooOoOO spooky."
|
||||
// In reality, we're just trying to emulate the behaviour of consent.exe in-process for the likes of:
|
||||
// * non-service level installers with temporary the local-sys-admin-says-its-ok permissions
|
||||
// * remote daemon administration (build-bot daemons with admin credits in a toml file, running as local or network users, perhaps)
|
||||
// * ssh-like servers
|
||||
// * initially not-administrator processes temporarily elevating themselves to remove or re-enable kernel level drivers (drivers such as: reverse engineering tools, vidya gaym anticheats, debuggers, etc)
|
||||
// These APIs will be of use for live-installers where installing for global-users is optional and the base requirements don't require escalation.
|
||||
// Asking for creds in process after a software demo is playable is far nicer UX, than having to wait for 10 hours for Windows to spawn a consent.exe process, just to end up losing stdin/out/err redirection.
|
||||
|
||||
struct RunAsDescriptor
|
||||
{
|
||||
AU_COPY_MOVE_DEF(RunAsDescriptor);
|
||||
|
||||
ERunAsUser runAs = ERunAsUser::eRegularUser;
|
||||
AuOptional<int> numericUserId;
|
||||
AuOptional<AuString> username;
|
||||
AuOptional<AuString> password;
|
||||
AuOptional<AuString> server;
|
||||
AuOptional<AuString> impersonate;
|
||||
AuOptional<int> impersonateNumericUserId;
|
||||
bool bLoginWithProfile {};
|
||||
|
||||
// if this structure is partially completed;
|
||||
// a dialog may be shown if running under a desktop GUI (polkit, credui, etc),
|
||||
// or a command-line based command (AuConsole) may be requested.
|
||||
};
|
||||
|
||||
AUKN_SYM void RunAs(StartupParameters &startupParameters,
|
||||
RunAsDescriptor &runAs); // SECURITY @ Try to enforce moving of AuOptional<AuString> password; to hopefully purge it out of memory asap @
|
||||
} // SECURITY @ Noting that AuOptional<AuString> password isn't memory safe. We should probably try to memset it after use and during move @
|
||||
// REGRESSION: make runAs move-only again
|
@ -81,6 +81,7 @@ namespace Aurora::Processes
|
||||
LPCWSTR,
|
||||
LPSTARTUPINFOW,
|
||||
LPPROCESS_INFORMATION> ntLikeHookCreateProcessW;
|
||||
AuConsumer<_SECURITY_ATTRIBUTES *> ntFixSharedHandleAttrs;
|
||||
#else
|
||||
AuSupplierConsumer<int,
|
||||
void *,
|
||||
@ -93,10 +94,14 @@ namespace Aurora::Processes
|
||||
void *,
|
||||
void *,
|
||||
void *> ntLikeHookCreateProcessW;
|
||||
AuConsumer<void *> ntFixSharedHandleAttrs;
|
||||
#endif
|
||||
bool bForceNoJobParent {};
|
||||
#endif
|
||||
#if defined(AURORA_IS_POSIX_DERIVED)
|
||||
AuVoidFunc posixApplySandboxCOW;
|
||||
AuVoidFunc posixPCA;
|
||||
AuVoidFunc posixPCB;
|
||||
#endif
|
||||
};
|
||||
}
|
@ -168,6 +168,7 @@ namespace Aurora
|
||||
ADD_LOAD_LIB(User32);
|
||||
ADD_LOAD_LIB(SetupAPI);
|
||||
ADD_LOAD_LIB(Router);
|
||||
ADD_LOAD_LIB(CredUI);
|
||||
|
||||
#define ADD_GET_PROC(name, proc) \
|
||||
if (!IsBlocked(#proc)) \
|
||||
@ -333,6 +334,30 @@ namespace Aurora
|
||||
ADD_GET_PROC(AdvancedApi, SetNamedSecurityInfoW)
|
||||
ADD_GET_PROC(AdvancedApi, FreeSid)
|
||||
|
||||
// privilege escalation
|
||||
ADD_GET_PROC(AdvancedApi, CreateProcessWithLogonW);
|
||||
ADD_GET_PROC(AdvancedApi, CreateProcessAsUserW);
|
||||
ADD_GET_PROC(AdvancedApi, AdjustTokenPrivileges);
|
||||
ADD_GET_PROC(AdvancedApi, RevertToSelf);
|
||||
ADD_GET_PROC(AdvancedApi, SetTokenInformation);
|
||||
ADD_GET_PROC(AdvancedApi, GetSidSubAuthorityCount);
|
||||
ADD_GET_PROC(AdvancedApi, GetSidSubAuthority);
|
||||
ADD_GET_PROC(AdvancedApi, LogonUserW);
|
||||
ADD_GET_PROC(AdvancedApi, OpenProcessToken);
|
||||
ADD_GET_PROC(AdvancedApi, SetThreadToken);
|
||||
ADD_GET_PROC(AdvancedApi, SetSecurityInfo);
|
||||
ADD_GET_PROC(AdvancedApi, GetUserNameW);
|
||||
ADD_GET_PROC(AdvancedApi, DuplicateTokenEx);
|
||||
ADD_GET_PROC(AdvancedApi, LookupAccountSidW);
|
||||
ADD_GET_PROC(AdvancedApi, GetTokenInformation);
|
||||
ADD_GET_PROC(AdvancedApi, SetSecurityDescriptorDacl);
|
||||
ADD_GET_PROC(AdvancedApi, InitializeSecurityDescriptor);
|
||||
ADD_GET_PROC(AdvancedApi, LookupAccountNameW);
|
||||
ADD_GET_PROC(AdvancedApi, LookupPrivilegeValueA);
|
||||
ADD_GET_PROC(AdvancedApi, LsaOpenPolicy);
|
||||
ADD_GET_PROC(AdvancedApi, LsaClose);
|
||||
ADD_GET_PROC(AdvancedApi, LsaAddAccountRights);
|
||||
|
||||
ADD_GET_PROC_INTERNAL_MAP(AdvancedApi, RtlGenRandom, SystemFunction036)
|
||||
|
||||
ADD_GET_PROC(BCrypt, BCryptGenRandom)
|
||||
@ -373,6 +398,8 @@ namespace Aurora
|
||||
ADD_GET_PROC(Router, WNetOpenEnumW);
|
||||
ADD_GET_PROC(Router, WNetGetUniversalNameW);
|
||||
|
||||
ADD_GET_PROC(CredUI, CredUIPromptForWindowsCredentialsW);
|
||||
ADD_GET_PROC(CredUI, CredUnPackAuthenticationBufferW);
|
||||
|
||||
if (pNtCreateKeyedEvent &&
|
||||
Threading::Primitives::gKeyedEventHandle == INVALID_HANDLE_VALUE)
|
||||
|
@ -23,9 +23,11 @@ struct _SP_DEVINFO_DATA;
|
||||
struct _SP_DEVICE_INTERFACE_DATA;
|
||||
struct _SP_DEVICE_INTERFACE_DETAIL_DATA_W;
|
||||
struct _NETRESOURCEW;
|
||||
enum _TOKEN_INFORMATION_CLASS;
|
||||
enum _SE_OBJECT_TYPE;
|
||||
enum _MINIDUMP_TYPE;
|
||||
enum _OBJECT_WAIT_TYPE;
|
||||
enum _SE_OBJECT_TYPE;
|
||||
|
||||
//#if defined(AURORA_COMPILER_MSVC)
|
||||
struct _IP_ADAPTER_ADDRESSES_LH;
|
||||
@ -42,6 +44,21 @@ enum _OBJECT_WAIT_TYPE;
|
||||
#endif
|
||||
//#endif
|
||||
|
||||
|
||||
typedef UNICODE_STRING LSA_UNICODE_STRING, *PLSA_UNICODE_STRING;
|
||||
typedef STRING LSA_STRING, *PLSA_STRING;
|
||||
typedef OBJECT_ATTRIBUTES LSA_OBJECT_ATTRIBUTES, *PLSA_OBJECT_ATTRIBUTES;
|
||||
typedef PVOID LSA_HANDLE, *PLSA_HANDLE;
|
||||
|
||||
struct CREDUI_INFOW
|
||||
{
|
||||
DWORD cbSize;
|
||||
HWND hwndParent;
|
||||
PCWSTR pszMessageText;
|
||||
PCWSTR pszCaptionText;
|
||||
HBITMAP hbmBanner;
|
||||
};
|
||||
|
||||
namespace Aurora
|
||||
{
|
||||
void InitNTAddresses();
|
||||
@ -64,6 +81,7 @@ namespace Aurora
|
||||
static const wchar_t *kUser32DllName { L"User32.dll" };
|
||||
static const wchar_t *kSetupAPIDllName { L"SETUPAPI.dll" };
|
||||
static const wchar_t *kRouterDllName { L"MPR.dll" };
|
||||
static const wchar_t *kCredUIDllName { L"credui.dll" };
|
||||
|
||||
struct WIN32_MEMORY_RANGE_ENTRY2
|
||||
{
|
||||
@ -665,6 +683,172 @@ namespace Aurora
|
||||
VOID * pSid
|
||||
);
|
||||
|
||||
// Advanced API
|
||||
// The proper dodgy APIs that'll probably get us hit by AV-engines
|
||||
// The follow APIs are used for in-process privilege escalation
|
||||
|
||||
inline BOOL(__stdcall *pCreateProcessWithLogonW)(
|
||||
LPCWSTR lpUsername,
|
||||
LPCWSTR lpDomain,
|
||||
LPCWSTR lpPassword,
|
||||
DWORD dwLogonFlags,
|
||||
LPCWSTR lpApplicationName,
|
||||
LPWSTR lpCommandLine,
|
||||
DWORD dwCreationFlags,
|
||||
LPVOID lpEnvironment,
|
||||
LPCWSTR lpCurrentDirectory,
|
||||
LPSTARTUPINFOW lpStartupInfo,
|
||||
LPPROCESS_INFORMATION lpProcessInformation
|
||||
);
|
||||
|
||||
inline BOOL(__stdcall *pCreateProcessAsUserW)(
|
||||
HANDLE hToken,
|
||||
LPCWSTR lpApplicationName,
|
||||
LPWSTR lpCommandLine,
|
||||
LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
||||
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
||||
BOOL bInheritHandles,
|
||||
DWORD dwCreationFlags,
|
||||
LPVOID lpEnvironment,
|
||||
LPCWSTR lpCurrentDirectory,
|
||||
LPSTARTUPINFOW lpStartupInfo,
|
||||
LPPROCESS_INFORMATION lpProcessInformation
|
||||
);
|
||||
|
||||
inline BOOL(__stdcall *pAdjustTokenPrivileges)(
|
||||
HANDLE TokenHandle,
|
||||
BOOL DisableAllPrivileges,
|
||||
PTOKEN_PRIVILEGES NewState,
|
||||
DWORD BufferLength,
|
||||
PTOKEN_PRIVILEGES PreviousState,
|
||||
PDWORD ReturnLength
|
||||
);
|
||||
|
||||
inline BOOL(__stdcall *pRevertToSelf)();
|
||||
|
||||
inline BOOL(__stdcall *pSetTokenInformation)(
|
||||
HANDLE TokenHandle,
|
||||
_TOKEN_INFORMATION_CLASS TokenInformationClass,
|
||||
LPVOID TokenInformation,
|
||||
DWORD TokenInformationLength
|
||||
);
|
||||
|
||||
inline PUCHAR(__stdcall *pGetSidSubAuthorityCount)(PSID pSid);
|
||||
|
||||
inline BOOL(__stdcall *pLookupPrivilegeValueA)(
|
||||
LPCSTR lpSystemName,
|
||||
LPCSTR lpName,
|
||||
PLUID lpLuid
|
||||
);
|
||||
|
||||
inline PDWORD(__stdcall *pGetSidSubAuthority)(
|
||||
PSID pSid,
|
||||
DWORD nSubAuthority
|
||||
);
|
||||
|
||||
inline PDWORD(__stdcall *pLogonUserW)(
|
||||
LPCWSTR lpszUsername,
|
||||
LPCWSTR lpszDomain,
|
||||
LPCWSTR lpszPassword,
|
||||
DWORD dwLogonType,
|
||||
DWORD dwLogonProvider,
|
||||
PHANDLE phToken
|
||||
);
|
||||
|
||||
inline PDWORD(__stdcall *pOpenProcessToken)(
|
||||
HANDLE ProcessHandle,
|
||||
DWORD DesiredAccess,
|
||||
PHANDLE TokenHandle
|
||||
);
|
||||
|
||||
inline BOOL(__stdcall *pSetThreadToken)(
|
||||
PHANDLE Thread,
|
||||
HANDLE Token
|
||||
);
|
||||
|
||||
inline DWORD(__stdcall *pSetSecurityInfo)(
|
||||
HANDLE handle,
|
||||
_SE_OBJECT_TYPE ObjectType,
|
||||
SECURITY_INFORMATION SecurityInfo,
|
||||
PSID psidOwner,
|
||||
PSID psidGroup,
|
||||
PACL pDacl,
|
||||
PACL pSacl
|
||||
);
|
||||
|
||||
inline BOOL(__stdcall *pGetUserNameW)(
|
||||
LPWSTR lpBuffer,
|
||||
LPDWORD pcbBuffer
|
||||
);
|
||||
|
||||
inline BOOL(__stdcall *pDuplicateTokenEx)(
|
||||
HANDLE hExistingToken,
|
||||
DWORD dwDesiredAccess,
|
||||
LPSECURITY_ATTRIBUTES lpTokenAttributes,
|
||||
SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
|
||||
TOKEN_TYPE TokenType,
|
||||
PHANDLE phNewToken
|
||||
);
|
||||
|
||||
inline BOOL(__stdcall *pLookupAccountSidW)(
|
||||
LPCWSTR lpSystemName,
|
||||
PSID Sid,
|
||||
LPWSTR Name,
|
||||
LPDWORD cchName,
|
||||
LPWSTR ReferencedDomainName,
|
||||
LPDWORD cchReferencedDomainName,
|
||||
PSID_NAME_USE peUse
|
||||
);
|
||||
|
||||
inline BOOL(__stdcall *pGetTokenInformation)(
|
||||
HANDLE TokenHandle,
|
||||
TOKEN_INFORMATION_CLASS TokenInformationClass,
|
||||
LPVOID TokenInformation,
|
||||
DWORD TokenInformationLength,
|
||||
PDWORD ReturnLength
|
||||
);
|
||||
|
||||
inline BOOL(__stdcall *pSetSecurityDescriptorDacl)(
|
||||
PSECURITY_DESCRIPTOR pSecurityDescriptor,
|
||||
BOOL bDaclPresent,
|
||||
PACL pDacl,
|
||||
BOOL bDaclDefaulted
|
||||
);
|
||||
|
||||
inline BOOL(__stdcall *pInitializeSecurityDescriptor)(
|
||||
PSECURITY_DESCRIPTOR pSecurityDescriptor,
|
||||
DWORD dwRevision
|
||||
);
|
||||
|
||||
inline NTSTATUS(__stdcall *pLsaOpenPolicy)(
|
||||
PLSA_UNICODE_STRING SystemName,
|
||||
PLSA_OBJECT_ATTRIBUTES ObjectAttributes,
|
||||
ACCESS_MASK DesiredAccess,
|
||||
PLSA_HANDLE PolicyHandle
|
||||
);
|
||||
|
||||
inline NTSTATUS(__stdcall *pLsaClose)(
|
||||
LSA_HANDLE ObjectHandle
|
||||
);
|
||||
|
||||
inline NTSTATUS(__stdcall *pLsaAddAccountRights)(
|
||||
LSA_HANDLE PolicyHandle,
|
||||
PSID AccountSid,
|
||||
PLSA_UNICODE_STRING UserRights,
|
||||
ULONG CountOfRights
|
||||
);
|
||||
|
||||
inline NTSTATUS(__stdcall *pLookupAccountNameW)(
|
||||
LPCWSTR lpSystemName,
|
||||
LPCWSTR lpAccountName,
|
||||
PSID Sid,
|
||||
LPDWORD cbSid,
|
||||
LPWSTR ReferencedDomainName,
|
||||
LPDWORD cchReferencedDomainName,
|
||||
PSID_NAME_USE peUse
|
||||
);
|
||||
|
||||
|
||||
// USER32 - the shit microsoft will probably try to phase out and remove over time
|
||||
// [then give up and write a win32 emulator in a memelang, probably]
|
||||
|
||||
@ -973,6 +1157,33 @@ namespace Aurora
|
||||
LPINT lpAddressLength
|
||||
);
|
||||
|
||||
// credui
|
||||
|
||||
inline INT(__stdcall *pCredUIPromptForWindowsCredentialsW)(
|
||||
void * pUiInfo,
|
||||
DWORD dwAuthError,
|
||||
ULONG * pulAuthPackage,
|
||||
LPCVOID pvInAuthBuffer,
|
||||
ULONG ulInAuthBufferSize,
|
||||
LPVOID * ppvOutAuthBuffer,
|
||||
ULONG * pulOutAuthBufferSize,
|
||||
BOOL * pfSave,
|
||||
DWORD dwFlags
|
||||
);
|
||||
|
||||
inline BOOL(__stdcall *pCredUnPackAuthenticationBufferW)(
|
||||
DWORD dwFlags,
|
||||
PVOID pAuthBuffer,
|
||||
DWORD cbAuthBuffer,
|
||||
LPWSTR pszUserName,
|
||||
DWORD * pcchMaxUserName,
|
||||
LPWSTR pszDomainName,
|
||||
DWORD * pcchMaxDomainName,
|
||||
LPWSTR pszPassword,
|
||||
DWORD * pcchMaxPassword
|
||||
);
|
||||
|
||||
|
||||
inline bool gUseNativeWaitMutex {};
|
||||
inline bool gUseNativeWaitCondvar {};
|
||||
inline bool gUseNativeWaitSemapahore {};
|
||||
|
@ -235,6 +235,12 @@ namespace Aurora::Processes
|
||||
return WriteFile(this->pipeStdInWrite_, in.ptr, size, &size, NULL) && size == in.length;
|
||||
}
|
||||
|
||||
void ProcessImpl::RestLeakyMem()
|
||||
{
|
||||
AuResetMember(this->startup_.ntLikeHookCreateProcessW);
|
||||
AuResetMember(this->startup_.ntFixSharedHandleAttrs);
|
||||
}
|
||||
|
||||
bool ProcessImpl::Init()
|
||||
{
|
||||
SECURITY_ATTRIBUTES saAttr {};
|
||||
@ -260,6 +266,11 @@ namespace Aurora::Processes
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->startup_.ntFixSharedHandleAttrs)
|
||||
{
|
||||
this->startup_.ntFixSharedHandleAttrs(&saAttr);
|
||||
}
|
||||
|
||||
this->exitCode_ = 0x10110100;
|
||||
if (this->startup_.fwdOut == EStreamForward::eAsyncPipe)
|
||||
{
|
||||
@ -637,8 +648,7 @@ namespace Aurora::Processes
|
||||
uCreateFlags |= CREATE_UNICODE_ENVIRONMENT;
|
||||
}
|
||||
|
||||
BOOL result {};
|
||||
|
||||
DWORD result;
|
||||
if (auto &func = this->startup_.ntLikeHookCreateProcessW)
|
||||
{
|
||||
result = func(Locale::ConvertFromUTF8(this->startup_.process).c_str(),
|
||||
@ -667,10 +677,12 @@ namespace Aurora::Processes
|
||||
&this->processInfo_);
|
||||
}
|
||||
|
||||
this->RestLeakyMem();
|
||||
|
||||
if (!result)
|
||||
{
|
||||
DWORD wr = GetLastError();
|
||||
SysPushErrorGen("CreateProcess failed");
|
||||
SysPushErrorGen("CreateProcess failed: {}", wr);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -712,7 +724,8 @@ namespace Aurora::Processes
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->type_ == ESpawnType::eSpawnChildProcessWorker)
|
||||
if (this->type_ == ESpawnType::eSpawnChildProcessWorker &&
|
||||
!this->startup_.bForceNoJobParent)
|
||||
{
|
||||
#if defined(AURORA_PLATFORM_WIN32)
|
||||
AssignJobWorker(this->processInfo_.hProcess);
|
||||
@ -790,6 +803,7 @@ namespace Aurora::Processes
|
||||
|
||||
if (!hi->Init())
|
||||
{
|
||||
hi->RestLeakyMem();
|
||||
delete hi;
|
||||
return {};
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ namespace Aurora::Processes
|
||||
bool Start() override;
|
||||
|
||||
bool Init();
|
||||
|
||||
void RestLeakyMem();
|
||||
void RelOtherHandles();
|
||||
|
||||
private:
|
||||
|
18
Source/Processes/AuProcessElevation.Linux.cpp
Normal file
18
Source/Processes/AuProcessElevation.Linux.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
/***
|
||||
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: AuProcessElevation.Linux.cpp
|
||||
Date: 2023-12-26
|
||||
Author: Reece
|
||||
***/
|
||||
#include <Source/RuntimeInternal.hpp>
|
||||
#include "AuProcessElevation.Linux.hpp"
|
||||
|
||||
namespace Aurora::Processes
|
||||
{
|
||||
AUKN_SYM void RunAs(StartupParameters &startupParameters,
|
||||
RunAsDescriptor &runAs)
|
||||
{
|
||||
// ...
|
||||
}
|
||||
}
|
13
Source/Processes/AuProcessElevation.Linux.hpp
Normal file
13
Source/Processes/AuProcessElevation.Linux.hpp
Normal file
@ -0,0 +1,13 @@
|
||||
/***
|
||||
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: AuProcessElevation.Linux.hpp
|
||||
Date: 2023-12-26
|
||||
Author: Reece
|
||||
***/
|
||||
#pragma once
|
||||
|
||||
namespace Aurora::Processes
|
||||
{
|
||||
|
||||
}
|
997
Source/Processes/AuProcessElevation.NT.cpp
Normal file
997
Source/Processes/AuProcessElevation.NT.cpp
Normal file
@ -0,0 +1,997 @@
|
||||
/***
|
||||
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());
|
||||
}
|
||||
|
||||
if (this->desc.password)
|
||||
{
|
||||
widepassword = AuLocale::ConvertFromUTF8(this->desc.password.value().c_str());
|
||||
}
|
||||
|
||||
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())
|
||||
{
|
||||
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())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (status == EPrompt::eError)
|
||||
{
|
||||
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");
|
||||
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))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (!SetTokenIntegrityLevel(hBestToken,
|
||||
GetTokenIntegrityLevel()))
|
||||
{
|
||||
SysPushErrorPermissionError("Unable to elevate");
|
||||
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();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
}
|
13
Source/Processes/AuProcessElevation.NT.hpp
Normal file
13
Source/Processes/AuProcessElevation.NT.hpp
Normal file
@ -0,0 +1,13 @@
|
||||
/***
|
||||
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: AuProcessElevation.NT.hpp
|
||||
Date: 2023-12-23
|
||||
Author: Reece
|
||||
***/
|
||||
#pragma once
|
||||
|
||||
namespace Aurora::Processes
|
||||
{
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user