Skip to content

Commit

Permalink
Add command line parser
Browse files Browse the repository at this point in the history
  • Loading branch information
llccd committed Mar 4, 2021
1 parent 5b09077 commit 5a047df
Showing 1 changed file with 151 additions and 49 deletions.
200 changes: 151 additions & 49 deletions winsu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#include <winternl.h>
#include <sddl.h>
#include <userenv.h>
#include <cstdint>
#define _NTDEF_
#include <ntsecapi.h>
#pragma comment(lib, "kernel32.lib")
Expand All @@ -27,8 +26,17 @@ typedef NTSTATUS (NTAPI* _ZwCreateToken)(
IN PTOKEN_DEFAULT_DACL DefaultDacl,
IN PTOKEN_SOURCE Source
);
typedef wchar_t* (NTAPI* _wcsstr)(wchar_t* wcs1, const wchar_t* wcs2);
typedef unsigned __int64 (NTAPI* _wcstoui64_ntdll)(const wchar_t* strSource, wchar_t** endptr, int base);
typedef unsigned long (NTAPI* _wcstoul)(const wchar_t* strSource, wchar_t** endptr, int base);

DWORD count_one(uint64_t x)
_wcsstr wcsstr_ntdll;
_wcstoui64_ntdll wcstoui64_ntdll;
_wcstoul wcstoul_ntdll;
_ZwCreateToken ZwCreateToken;


DWORD count_one(unsigned __int64 x)
{
x = (x & 0x5555555555555555) + (x >> 1 & 0x5555555555555555);
x = (x & 0x3333333333333333) + (x >> 2 & 0x3333333333333333);
Expand All @@ -39,7 +47,7 @@ DWORD count_one(uint64_t x)
return static_cast<DWORD>(x);
}

PTOKEN_PRIVILEGES generate_privilege(const uint64_t& priv)
PTOKEN_PRIVILEGES generate_privilege(const unsigned __int64& priv)
{
const DWORD privilege_count = count_one(priv);
const DWORD size = sizeof(DWORD) + sizeof(LUID_AND_ATTRIBUTES) * privilege_count;
Expand All @@ -48,7 +56,7 @@ PTOKEN_PRIVILEGES generate_privilege(const uint64_t& priv)
privileges->PrivilegeCount = privilege_count;
for (DWORD i = 0, j = 0; i < 64; ++i)
{
if (priv & static_cast<uint64_t>(1) << i)
if (priv & static_cast<unsigned __int64>(1) << i)
{
privileges->Privileges[j].Attributes = SE_PRIVILEGE_ENABLED;
privileges->Privileges[j++].Luid.LowPart = i + 1;
Expand All @@ -58,15 +66,15 @@ PTOKEN_PRIVILEGES generate_privilege(const uint64_t& priv)
return privileges;
}

PTOKEN_GROUPS generate_groups(const PSID& logon_sid)
PTOKEN_GROUPS generate_groups(const PSID& logon_sid, PSID* add_groups, const DWORD& add_count, const PSID& mandatory)
{
DWORD group_count = 12;
DWORD group_count = 12 + add_count;
if (logon_sid) group_count++;
const DWORD size = sizeof(DWORD) + sizeof(SID_AND_ATTRIBUTES) * group_count;
auto groups = static_cast<PTOKEN_GROUPS>(LocalAlloc(LPTR, size));
if (!groups) return nullptr;
groups->GroupCount = group_count;
ConvertStringSidToSidA("S-1-16-16384", &groups->Groups[0].Sid); //Mandatory Label\System Mandatory Level Label
groups->Groups[0].Sid = mandatory;
groups->Groups[0].Attributes = SE_GROUP_INTEGRITY_ENABLED | SE_GROUP_INTEGRITY;
ConvertStringSidToSidA("S-1-1-0", &groups->Groups[1].Sid); //Everyone
groups->Groups[1].Attributes = SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY;
Expand All @@ -93,10 +101,16 @@ PTOKEN_GROUPS generate_groups(const PSID& logon_sid)
//NT SERVICE\TrustedInstaller
ConvertStringSidToSidA("S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464", &groups->Groups[11].Sid);
groups->Groups[11].Attributes = SE_GROUP_ENABLED;
DWORD i;
for (i = 0; i < add_count; ++i)
{
groups->Groups[i + 12].Sid = add_groups[i];
groups->Groups[i + 12].Attributes = SE_GROUP_ENABLED;
}
if (logon_sid)
{
groups->Groups[12].Sid = logon_sid;
groups->Groups[12].Attributes = SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY |
groups->Groups[i + 12].Sid = logon_sid;
groups->Groups[i + 12].Attributes = SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY |
SE_GROUP_LOGON_ID;
}
return groups;
Expand Down Expand Up @@ -180,7 +194,7 @@ LUID get_auth_id(const PSID uid, const DWORD session_id)
return auth_id;
}

BOOL GetTokenFromPID(DWORD& ProcessId, PHANDLE TokenHandle)
BOOL get_token_pid(DWORD& ProcessId, PHANDLE TokenHandle)
{
HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, ProcessId);
if (!process) return false;
Expand All @@ -189,7 +203,7 @@ BOOL GetTokenFromPID(DWORD& ProcessId, PHANDLE TokenHandle)
return res;
}

DWORD GetLsassPid()
DWORD get_lsass_pid()
{
SC_HANDLE scm = OpenSCManagerA(nullptr, nullptr, SC_MANAGER_CONNECT);
SERVICE_STATUS_PROCESS status;
Expand All @@ -212,21 +226,35 @@ DWORD GetLsassPid()
return pid;
}

HANDLE create_token(const PSID& uid, const uint64_t& priv_present, const PSID& logon_sid, LUID authid)
BOOL load_ntdll()
{
HMODULE ntdll = LoadLibraryA("ntdll");
if (!ntdll) return false;
ZwCreateToken = reinterpret_cast<_ZwCreateToken>(GetProcAddress(ntdll, "ZwCreateToken"));
if (!ZwCreateToken) return false;
wcsstr_ntdll = reinterpret_cast<_wcsstr>(GetProcAddress(ntdll, "wcsstr"));
if (!wcsstr_ntdll) return false;
wcstoui64_ntdll = reinterpret_cast<_wcstoui64_ntdll>(GetProcAddress(ntdll, "_wcstoui64"));
if (!wcstoui64_ntdll) return false;
wcstoul_ntdll = reinterpret_cast<_wcstoul>(GetProcAddress(ntdll, "wcstoul"));
if (!wcstoul_ntdll) return false;
return true;
}

HANDLE create_token(const PSID& uid, const unsigned __int64& priv_present, const PSID& logon_sid, LUID authid,
LPCWSTR dacl, PSID* add_groups, DWORD add_count, const PSID& mandatory)
{
auto const ZwCreateToken = reinterpret_cast<_ZwCreateToken>(GetProcAddress(LoadLibraryA("ntdll"), "ZwCreateToken"));
if (!ZwCreateToken) return nullptr;
SECURITY_QUALITY_OF_SERVICE sqos = {sizeof(sqos), SecurityDelegation, SECURITY_STATIC_TRACKING, FALSE};
OBJECT_ATTRIBUTES oa = {sizeof(oa), 0, 0, 0, 0, &sqos};
LARGE_INTEGER li = {{0xFFFFFFFF, -1}};
TOKEN_USER user = {{uid, 0}};
TOKEN_SOURCE source = {{'F', 'r', 'e', 'e', 'H', 'K', 0}, {0x99996E2F, 0x51495FA9}};
TOKEN_OWNER owner = {uid};
TOKEN_PRIMARY_GROUP primary_group;
PTOKEN_GROUPS groups = generate_groups(logon_sid);
PTOKEN_GROUPS groups = generate_groups(logon_sid, add_groups, add_count, mandatory);
PTOKEN_PRIVILEGES privileges = generate_privilege(priv_present);
PSECURITY_DESCRIPTOR sd;
ConvertStringSecurityDescriptorToSecurityDescriptorA("G:BAD:(A;;GA;;;SY)(A;;GA;;;BA)", SDDL_REVISION_1, &sd,
ConvertStringSecurityDescriptorToSecurityDescriptorW(dacl, SDDL_REVISION_1, &sd,
nullptr);
TOKEN_DEFAULT_DACL default_dacl;
BOOL present = false, defaulted = false;
Expand Down Expand Up @@ -266,56 +294,130 @@ LPWSTR current_directory()
int main()
{
int argc;
LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc);
HANDLE CurrentProcessToken = INVALID_HANDLE_VALUE;
HANDLE OriginalLsassProcessToken = INVALID_HANDLE_VALUE;
HANDLE SystemToken = INVALID_HANDLE_VALUE;
DWORD session_id = -1, LsassPid = GetLsassPid();
LPWSTR current_cmdline = GetCommandLineW();
LPWSTR* argv = CommandLineToArgvW(current_cmdline, &argc);
if (!argv) return -9;
if (!load_ntdll()) return -10;
HANDLE token = INVALID_HANDLE_VALUE;
HANDLE dup_token = INVALID_HANDLE_VALUE;
DWORD session_id = -1, lsass_pid = get_lsass_pid();
DWORD ReturnLength = 0;
uint64_t priv_present = 0xFFFFFFFFE;
DWORD add_count = 0;
PSID* add_groups = nullptr;
unsigned __int64 priv_present = 0xFFFFFFFFE;
PSID uid;
if (argc > 1) ConvertStringSidToSidW(argv[1], &uid);
else ConvertStringSidToSidA("S-1-5-18", &uid);
if (LsassPid == -1) return -1;
if (!OpenProcessToken(GetCurrentProcess(), MAXIMUM_ALLOWED, &CurrentProcessToken)) return -2;
enable_all_privileges(CurrentProcessToken);
GetTokenInformation(CurrentProcessToken, TokenSessionId, &session_id, sizeof(DWORD), &ReturnLength);
LPCWSTR dacl = L"G:BAD:(A;;GA;;;SY)(A;;GA;;;BA)";
LPCWSTR cmd = L"%ComSpec% /K";
LPCWSTR user = L"S-1-5-18";
LPCWSTR mandatory_str = L"S-1-16-16384";
STARTUPINFOW startup_info = {sizeof(STARTUPINFOW)};
startup_info.lpDesktop = const_cast<LPWSTR>(L"WinSta0\\Default");
startup_info.dwFlags = STARTF_USESHOWWINDOW;
startup_info.wShowWindow = SW_SHOWDEFAULT;
DWORD creation_flags = CREATE_UNICODE_ENVIRONMENT;
BOOL wait = true;
for (int i = 1; i < argc; ++i)
{
if (!lstrcmpiW(argv[i], L"-acl"))
{
if (++i >= argc) return 1;
dacl = argv[i];
}
else if (!lstrcmpiW(argv[i], L"-d"))
{
if (++i >= argc) return 1;
startup_info.lpDesktop = argv[i];
}
else if (!lstrcmpiW(argv[i], L"-p"))
{
if (++i >= argc) return 1;
priv_present = wcstoui64_ntdll(argv[i], nullptr, 16);
}
else if (!lstrcmpiW(argv[i], L"-s"))
{
if (++i >= argc) return 1;
session_id = wcstoul_ntdll(argv[i], nullptr, 16);
}
else if (!lstrcmpiW(argv[i], L"-nw"))
{
wait = false;
}
else if (!lstrcmpiW(argv[i], L"-c"))
{
creation_flags |= CREATE_NEW_CONSOLE;
}
else if (!lstrcmpiW(argv[i], L"-m"))
{
if (++i >= argc) return 1;
if (!lstrcmpiW(argv[i], L"UT")) mandatory_str = L"S-1-16-0";
else if (!lstrcmpiW(argv[i], L"LW")) mandatory_str = L"S-1-16-4096";
else if (!lstrcmpiW(argv[i], L"ME")) mandatory_str = L"S-1-16-8192";
else if (!lstrcmpiW(argv[i], L"MP")) mandatory_str = L"S-1-16-8448";
else if (!lstrcmpiW(argv[i], L"HI")) mandatory_str = L"S-1-16-12288";
else if (!lstrcmpiW(argv[i], L"SI")) mandatory_str = L"S-1-16-16384";
else mandatory_str = argv[i];
}
else if (!lstrcmpiW(argv[i], L"-g"))
{
if (++i >= argc) return 1;
add_count = wcstoul_ntdll(argv[i], nullptr, 10);
add_groups = static_cast<PSID*>(LocalAlloc(LPTR, add_count * sizeof(PSID)));
for (DWORD j = 0; j < add_count; j++)
{
if (++i >= argc) return 1;
ConvertStringSidToSidW(argv[i], &add_groups[j]);
}
}
else if (!lstrcmpiW(argv[i], L"--"))
{
if (++i >= argc) break;
cmd = wcsstr_ntdll(current_cmdline, L"--") + 2;
while (cmd && *cmd == L' ') cmd++;
break;
}
else user = argv[i];
}
if (!ConvertStringSidToSidW(user, &uid)) return -11;
if (lsass_pid == -1) return -1;
if (!OpenProcessToken(GetCurrentProcess(), MAXIMUM_ALLOWED, &token)) return -2;
enable_all_privileges(token);
if (session_id == -1) GetTokenInformation(token, TokenSessionId, &session_id, sizeof(DWORD),
&ReturnLength);
LUID authid = get_auth_id(uid, session_id);
PSID logon_sid = get_logon_sid(CurrentProcessToken);
CloseHandle(CurrentProcessToken);
PSID logon_sid = get_logon_sid(token);
PSID mandatory;
if (!ConvertStringSidToSidW(mandatory_str, &mandatory)) return -12;
CloseHandle(token);
if (session_id == -1) return -3;
if (!GetTokenFromPID(LsassPid, &OriginalLsassProcessToken)) return -4;
BOOL res = DuplicateTokenEx(OriginalLsassProcessToken, MAXIMUM_ALLOWED, nullptr, SecurityImpersonation,
TokenImpersonation, &SystemToken);
CloseHandle(OriginalLsassProcessToken);
if (!res) return -5;
enable_all_privileges(SystemToken);
res = SetThreadToken(NULL, SystemToken);
CloseHandle(SystemToken);
if (!res) return -6;
HANDLE token = create_token(uid, priv_present, logon_sid, authid);
if (!get_token_pid(lsass_pid, &token)) return -4;
BOOL ret = DuplicateTokenEx(token, MAXIMUM_ALLOWED, nullptr, SecurityImpersonation,
TokenImpersonation, &dup_token);
CloseHandle(token);
if (!ret) return -5;
enable_all_privileges(dup_token);
ret = SetThreadToken(nullptr, dup_token);
CloseHandle(dup_token);
if (!ret) return -6;
token = create_token(uid, priv_present, logon_sid, authid, dacl, add_groups, add_count, mandatory);
LocalFree(uid);
if (!token) return -7;
SetTokenInformation(token, TokenSessionId, static_cast<PVOID>(&session_id), sizeof(DWORD));
STARTUPINFOW startup_info = {sizeof(STARTUPINFOW)};
startup_info.lpDesktop = const_cast<LPWSTR>(L"WinSta0\\Default");
startup_info.dwFlags = STARTF_USESHOWWINDOW;
startup_info.wShowWindow = SW_SHOWDEFAULT;
PROCESS_INFORMATION process_info = {0};
LPVOID lpEnvironment = nullptr;
CreateEnvironmentBlock(&lpEnvironment, token, TRUE);
LPWSTR working_directory = current_directory();
LPWSTR cmdline = expand_environment(L"%SYSTEMROOT%\\System32\\cmd.exe /K");
res = CreateProcessAsUserW(token, NULL, cmdline, NULL, NULL, false, CREATE_UNICODE_ENVIRONMENT, lpEnvironment,
LPWSTR cmdline = expand_environment(cmd);
ret = CreateProcessAsUserW(token, NULL, cmdline, NULL, NULL, false, creation_flags, lpEnvironment,
working_directory, &startup_info, &process_info);
if (res) WaitForSingleObjectEx(process_info.hThread, 0, false);
if (ret) WaitForSingleObjectEx(process_info.hThread, 0, false);
LocalFree(cmdline);
LocalFree(working_directory);
CloseHandle(token);
DestroyEnvironmentBlock(lpEnvironment);
if (!res) return -8;
LocalFree(argv);
if (!ret) return -8;
CloseHandle(process_info.hThread);
WaitForSingleObjectEx(process_info.hProcess, INFINITE, false);
if (wait) WaitForSingleObjectEx(process_info.hProcess, INFINITE, false);
CloseHandle(process_info.hProcess);
return 0;
}

0 comments on commit 5a047df

Please sign in to comment.