Created
August 3, 2024 00:08
-
-
Save rbmm/4115931d728b23aa8c6adaf1b76863b3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
HRESULT GetLastErrorEx(ULONG dwError = GetLastError()) | |
{ | |
NTSTATUS status = RtlGetLastNtStatus(); | |
return dwError == RtlNtStatusToDosErrorNoTeb(status) ? HRESULT_FROM_NT(status) : HRESULT_FROM_WIN32(dwError); | |
} | |
NTSTATUS GetLogonSid(_In_ ULONG SessionId, _Out_ PSID_AND_ATTRIBUTES LogonSid) | |
{ | |
HANDLE hToken; | |
if (WTSQueryUserToken(SessionId, &hToken)) | |
{ | |
NTSTATUS status; | |
union { | |
PVOID buf; | |
PTOKEN_GROUPS ptg; | |
}; | |
PVOID stack = alloca(guz); | |
ULONG cb = 0, rcb = 0x100; | |
do | |
{ | |
if (cb < rcb) | |
{ | |
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack); | |
} | |
status = NtQueryInformationToken(hToken, TokenGroups, buf, cb, &rcb); | |
} while (STATUS_BUFFER_TOO_SMALL == status); | |
NtClose(hToken); | |
if (0 > status) | |
{ | |
return status; | |
} | |
if (ULONG GroupCount = ptg->GroupCount) | |
{ | |
PSID_AND_ATTRIBUTES Groups = ptg->Groups; | |
do | |
{ | |
if (Groups->Attributes & SE_GROUP_LOGON_ID) | |
{ | |
PSID Sid = Groups->Sid; | |
if (SECURITY_LOGON_IDS_RID_COUNT == *RtlSubAuthorityCountSid(Sid) && | |
SECURITY_LOGON_IDS_RID == *RtlSubAuthoritySid(Sid, 0)) | |
{ | |
LogonSid->Attributes = Groups->Attributes; | |
return RtlCopySid(SECURITY_SID_SIZE(SECURITY_LOGON_IDS_RID_COUNT), LogonSid->Sid, Sid); | |
} | |
} | |
} while (Groups++,--GroupCount); | |
} | |
return STATUS_NO_SUCH_GROUP; | |
} | |
return GetLastErrorEx(); | |
} | |
NTSTATUS GetUserToken(_Out_ HANDLE* phToken, _In_ PCWSTR LogonDomainName, _In_ PCWSTR UserName, _In_ PCWSTR Password) | |
{ | |
LONG SessionId = WTSGetActiveConsoleSessionId(); | |
if (0 >= SessionId) | |
{ | |
return STATUS_NO_SUCH_LOGON_SESSION; | |
} | |
NTSTATUS status; | |
UCHAR Sid[SECURITY_SID_SIZE(SECURITY_LOGON_IDS_RID_COUNT)]; | |
TOKEN_GROUPS LocalGroups = { 1, { Sid } }; | |
if (0 <= (status = GetLogonSid(SessionId, LocalGroups.Groups))) | |
{ | |
LSA_STRING PackageName; | |
HANDLE LsaHandle; | |
if (0 <= (status = LsaConnectUntrusted(&LsaHandle))) | |
{ | |
ULONG AuthenticationInformationLength = 0; | |
PKERB_INTERACTIVE_LOGON pkil = 0; | |
union { | |
PWSTR buf = 0; | |
PVOID pv; | |
PBYTE pb; | |
}; | |
int len = 0; | |
status = STATUS_INTERNAL_ERROR; | |
while (0 < (len = _snwprintf(buf, len, L"%s%c%s%c%s", LogonDomainName, 0, UserName, 0, Password))) | |
{ | |
if (buf) | |
{ | |
pkil->MessageType = KerbInteractiveLogon; | |
RtlInitUnicodeString(&pkil->LogonDomainName, buf); | |
pb += pkil->LogonDomainName.Length + sizeof(WCHAR); | |
RtlInitUnicodeString(&pkil->UserName, buf); | |
pb += pkil->UserName.Length + sizeof(WCHAR); | |
RtlInitUnicodeString(&pkil->Password, buf); | |
pb += pkil->Password.Length + sizeof(WCHAR); | |
(ULONG_PTR&)pkil->LogonDomainName.Buffer -= (ULONG_PTR)pkil; | |
(ULONG_PTR&)pkil->UserName.Buffer -= (ULONG_PTR)pkil; | |
(ULONG_PTR&)pkil->Password.Buffer -= (ULONG_PTR)pkil; | |
status = STATUS_SUCCESS; | |
break; | |
} | |
pkil = (PKERB_INTERACTIVE_LOGON)alloca( | |
AuthenticationInformationLength = sizeof(KERB_INTERACTIVE_LOGON) + ++len * sizeof(WCHAR)); | |
pv = pkil + 1; | |
} | |
ULONG AuthenticationPackage; | |
RtlInitString(&PackageName, NEGOSSP_NAME_A); | |
if (0 <= status && | |
0 <= (status = LsaLookupAuthenticationPackage(LsaHandle, &PackageName, &AuthenticationPackage))) | |
{ | |
RtlInitString(&PackageName, "OriginName"); | |
TOKEN_SOURCE ts = {"1234567", {0x12345678, 0x90abcdef }}; | |
void* ProfileBuffer; | |
ULONG ProfileBufferLength; | |
LUID LogonId; | |
QUOTA_LIMITS ql; | |
NTSTATUS subStatus; | |
HANDLE hToken; | |
if (0 <= (status = LsaLogonUser(LsaHandle, &PackageName, Interactive, AuthenticationPackage, | |
pkil, AuthenticationInformationLength, &LocalGroups, &ts, | |
&ProfileBuffer, &ProfileBufferLength, &LogonId, &hToken, &ql, &subStatus))) | |
{ | |
LsaFreeReturnBuffer(ProfileBuffer); | |
TOKEN_LINKED_TOKEN hLinkToken; | |
switch (status = NtQueryInformationToken(hToken, TokenLinkedToken, &hLinkToken, sizeof(hLinkToken), &ProfileBufferLength)) | |
{ | |
case STATUS_SUCCESS: | |
NtClose(hToken); | |
hToken = hLinkToken.LinkedToken; | |
case STATUS_NO_SUCH_LOGON_SESSION: | |
status = NtSetInformationToken(hToken, TokenSessionId, &SessionId, sizeof(SessionId)); | |
break; | |
} | |
if (0 > status) | |
{ | |
NtClose(hToken); | |
} | |
else | |
{ | |
*phToken = hToken; | |
} | |
} | |
else | |
{ | |
if (0 > subStatus) | |
{ | |
status = subStatus; | |
} | |
} | |
} | |
LsaDeregisterLogonProcess(LsaHandle); | |
} | |
} | |
return status; | |
} | |
NTSTATUS StartProcessAsUser(_In_ PCWSTR LogonDomainName, | |
_In_ PCWSTR UserName, | |
_In_ PCWSTR Password, | |
_In_ PCWSTR lpApplicationName, | |
_Inout_opt_ PWSTR lpCommandLine = 0) | |
{ | |
HANDLE hToken; | |
NTSTATUS status = GetUserToken(&hToken, LogonDomainName, UserName, Password); | |
if (0 <= status) | |
{ | |
PROCESS_INFORMATION pi; | |
STARTUPINFOW si = { sizeof(si) }; | |
si.lpDesktop = const_cast<PWSTR>(L"Winsta0\\Default"); | |
if (CreateProcessAsUserW(hToken, lpApplicationName, lpCommandLine, 0, 0, 0, 0, 0, 0, &si, &pi)) | |
{ | |
NtClose(pi.hThread); | |
NtClose(pi.hProcess); | |
} | |
NtClose(hToken); | |
return GetLastErrorEx(); | |
} | |
return status; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment