# Root Cause Analysis — CVE-2026-25184

## Overview

| | |
|---|---|
| CVE | CVE-2026-25184 |
| Binary | applockerfltr.sys (AppLocker Minifilter Driver) |
| Vulnerability class | CWE-362: Concurrent Execution Using Shared Resource with Improper Synchronization (Race Condition) |
| Impact | Elevation of Privilege |
| CVSS 3.1 | 7.0 (High) — AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H |
| Pre-patch version | 10.0.26100.7920 (March 2026) |
| Post-patch version | 10.0.26100.8246 (April 2026, KB5083769) |
| Feature flag | Feature_423566650 |
| Credited researcher | [Souhail Hammou (@dark_puzzle)](https://x.com/dark_puzzle) |

## Executive Summary

A TOCTOU race condition in AppLocker's minifilter driver allows a local attacker to corrupt a kernel doubly-linked list by triggering concurrent calls to `SmRegisterUninstallStringWithSessionOrigin`. The function performs a linked-list insertion (a write operation) while holding only a shared (reader) lock, allowing multiple threads to interleave the multi-pointer update and corrupt forward/backward pointers. Successful exploitation leads to use-after-free or arbitrary kernel write, enabling privilege escalation from standard user to SYSTEM.

## Root Cause

### The Vulnerable Function

`SmRegisterUninstallStringWithSessionOrigin` is called from AppLocker's registry callback (`SmpRegistryCallback`) when a process writes to an Uninstall registry key that AppLocker tracks. The function maintains a per-session doubly-linked list of "uninstall string data" entries used for session-origin tracking.

### The Bug: Write Under Shared Lock

The function's lock acquisition is fundamentally wrong for the operation it performs:

```c
// PRE-PATCH — applockerfltr.sys 10.0.26100.7920
SmRegisterUninstallStringWithSessionOrigin(longlong param_1)
{
    lVar2 = SmGetTrackSessionOriginData();
    if (lVar2 != 0) {
        SmAcquireTrackLock();       // ← SHARED lock (ERESOURCE shared mode)
        plVar3 = SmGetTrackSessionOriginDataLocked();
        if (plVar3 != NULL) {
            // Walk the linked list (read — fine under shared)
            plVar9 = (longlong *)*plVar3;
            while (plVar9 != plVar3) {
                // Compare session-origin fields
                if (*(plVar9[4]+0x20) == *(param_1+0x20) &&
                    *(plVar9[4]+0x28) == *(param_1+0x28))
                    break;
                plVar9 = (longlong *)*plVar9;
            }

            // Allocate new node (write — NOT safe under shared)
            puVar4 = SmAllocUninstallStringData();

            // INSERT into doubly-linked list (write — RACE HERE)
            *puVar4 = plVar3;       // new->flink = head
            puVar4[1] = puVar5;     // new->blink = head->blink
            *puVar5 = puVar4;       // head->blink->flink = new
            plVar3[1] = puVar4;     // head->blink = new
        }
        SmReleaseTrackLock();
    }
}
```

The ERESOURCE primitive allows unlimited concurrent shared acquisitions. This is correct for read-only traversals but catastrophically wrong for the linked-list insertion that follows. When two threads both hold the shared lock and both execute the four-pointer update, the interleaving corrupts the list:

```
Thread A reads: head->blink = X
Thread B reads: head->blink = X        (same value — stale after A's write)
Thread A writes: X->flink = nodeA; head->blink = nodeA
Thread B writes: X->flink = nodeB; head->blink = nodeB   (overwrites A's insertion)
```

Result: `nodeA` is lost from the list but may still be referenced by stale pointers from other nodes. When the list is later walked or a node is freed, the stale pointer dereferences freed memory — use-after-free.

### The Trigger Path

```
User-mode: RegSetValueExW(hKey, L"UninstallString", ...)
  ↓
Kernel: CmRegistryCallback (nt!CmRegisterCallbackEx)
  → SmpRegistryCallback
    → SmRegisterUninstallStringWithSessionOrigin
      → SmAcquireTrackLock()              ← shared lock (BUG)
      → SmGetTrackSessionOriginDataLocked()
      → SmAllocUninstallStringData()
      → [linked-list insertion]           ← non-atomic multi-pointer update
      → SmReleaseTrackLock()
```

The registry callback is invoked synchronously in the context of the thread performing the registry write. Multiple threads writing to tracked registry keys simultaneously all enter `SmRegisterUninstallStringWithSessionOrigin` concurrently under the shared lock.

### Why This Is Exploitable

1. **Fully user-triggerable**: Any standard user can write to `HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall\*\UninstallString` or similar AppLocker-monitored registry paths.
2. **Deterministic corruption**: The four-pointer linked-list update is a textbook non-atomic multi-pointer manipulation. With enough concurrent pressure, corruption is probabilistic but achievable.
3. **Kernel pool corruption**: The linked-list nodes are in kernel pool. Corrupted pointers can be turned into arbitrary kernel write via standard pool grooming techniques.
4. **Session 0 context**: AppLocker's registry callbacks run in the context of the calling thread but manipulate kernel-mode data structures. Corruption leads to SYSTEM-context code execution when the list is next walked by a privileged thread.

## The Fix

The patch introduces a Controlled Feature Rollout flag (`Feature_423566650`) that, when enabled, upgrades the lock from shared to exclusive:

```c
// POST-PATCH — applockerfltr.sys 10.0.26100.8246
SmRegisterUninstallStringWithSessionOrigin(longlong param_1)
{
    lVar2 = SmGetTrackSessionOriginData();
    if (lVar2 != 0) {
        uVar3 = Feature_423566650__private_IsEnabledDeviceUsageNoInline();
        if ((int)uVar3 == 0) {
            SmAcquireTrackLock();              // shared (kill-switch fallback)
        } else {
            SmAcquireTrackLockExclusive();     // ← EXCLUSIVE lock (production)
        }
        // ... same linked list walk and insertion, now serialized ...
        SmReleaseTrackLock();
    }
}
```

New functions added:

- **SmAcquireTrackLockExclusive**: Wrapper calling `FltAcquireResourceExclusive(DAT_140006140)` — acquires the same ERESOURCE in exclusive mode.
- **Feature_423566650 accessors**: Standard WIL CFR plumbing (`IsEnabledDeviceUsageNoInline`, `IsEnabledFallback`).

The fix is minimal and correct: exclusive lock serializes all writers, eliminating the race window entirely. The shared path is retained as a kill-switch fallback if the feature flag is disabled.

## CVSS 4.0 Vector

```
CVSS:4.0/AV:L/AC:H/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
```

| Metric | Value | Rationale |
|--------|-------|-----------|
| AV:L | Local | Requires local code execution |
| AC:H | High | Race condition requires precise thread timing |
| AT:P | Present | AppLocker must be active and monitoring the target registry paths |
| PR:L | Low | Standard user can write to HKCU Uninstall keys |
| UI:N | None | No user interaction required |
| VC:H/VI:H/VA:H | High | Kernel pool corruption → SYSTEM privileges |

## Detection

### YARA Rule

```yara
rule CVE_2026_25184_AppLocker_Race_Trigger
{
    meta:
        description = "Detects tools exploiting CVE-2026-25184 (AppLocker linked-list race)"
        author      = "OnlyFm252 / STAR Labs SG"
        date        = "2026-07-22"
        cve         = "CVE-2026-25184"
        severity    = "high"

    strings:
        $reg_path1  = "\\CurrentVersion\\Uninstall\\" wide ascii nocase
        $reg_value1 = "UninstallString" wide ascii nocase
        $api_create = "CreateThread" ascii
        $api_regset = "RegSetValueEx" ascii
        $api_ntset  = "NtSetValueKey" ascii
        $thread_pattern = { 6A 00 6A 00 (68|B8) [4] (68|B8) [4] 6A 00 6A 00 FF 15 }
        $race_loop  = /for\s*\(\s*int\s+\w+\s*=\s*0\s*;\s*\w+\s*<\s*\d{2,}\s*;/ ascii

    condition:
        uint16(0) == 0x5A4D and
        filesize < 500KB and
        $reg_path1 and
        $reg_value1 and
        ($api_create or $thread_pattern) and
        ($api_regset or $api_ntset) and
        $race_loop
}

rule CVE_2026_25184_AppLocker_Race_Generic
{
    meta:
        description = "Generic detection: multi-threaded registry spam targeting AppLocker paths"
        author      = "OnlyFm252 / STAR Labs SG"
        date        = "2026-07-22"
        cve         = "CVE-2026-25184"

    strings:
        $uninstall  = "Uninstall" wide ascii
        $applocker  = "AppLocker" wide ascii nocase
        $smartlocker = "SmartLocker" wide ascii nocase
        $multi_thread = "CreateThread" ascii
        $reg_write1 = "RegSetValueExW" ascii
        $reg_write2 = "NtSetValueKey" ascii
        $sprint     = "sprint" ascii nocase

    condition:
        uint16(0) == 0x5A4D and
        $uninstall and
        ($applocker or $smartlocker) and
        $multi_thread and
        ($reg_write1 or $reg_write2)
}
```

### Sigma Rule

```yaml
title: CVE-2026-25184 AppLocker Linked-List Race Exploitation Attempt
id: e7a3c8d1-5f92-4b1a-a6d0-3c8e9f7b2a45
status: experimental
description: >
    Detects rapid concurrent registry writes to AppLocker-monitored Uninstall
    keys, characteristic of CVE-2026-25184 exploitation (TOCTOU race in
    SmRegisterUninstallStringWithSessionOrigin).
author: OnlyFm252 / STAR Labs SG
date: 2026/07/22
references:
    - https://msrc.microsoft.com/update-guide/vulnerability/CVE-2026-25184
tags:
    - attack.privilege_escalation
    - attack.t1068
    - cve.2026.25184
logsource:
    product: windows
    category: registry_set
detection:
    selection:
        TargetObject|contains:
            - '\Software\Microsoft\Windows\CurrentVersion\Uninstall\'
        EventType: SetValue
        Details|contains:
            - 'UninstallString'
    filter_legitimate:
        Image|endswith:
            - '\msiexec.exe'
            - '\setup.exe'
            - '\installer.exe'
            - '\TiWorker.exe'
    timeframe: 5s
    condition: selection and not filter_legitimate | count() by Image > 20
level: high
falsepositives:
    - Mass software deployment tools writing many uninstall entries rapidly
    - SCCM/MECM client operations

---
title: CVE-2026-25184 Post-Exploitation — Suspicious Process After AppLocker Registry Spam
id: f8b4d9e2-6a03-4c2b-b7e1-4d9f0a8c3b56
status: experimental
description: >
    Detects a suspicious child process spawned shortly after rapid AppLocker
    registry writes, suggesting successful exploitation of CVE-2026-25184.
author: OnlyFm252 / STAR Labs SG
date: 2026/07/22
tags:
    - attack.privilege_escalation
    - attack.execution
    - attack.t1068
logsource:
    product: windows
    category: process_creation
detection:
    selection:
        ParentImage|endswith:
            - '\cmd.exe'
            - '\powershell.exe'
            - '\pwsh.exe'
        IntegrityLevel: System
        User|contains: 'SYSTEM'
    filter_normal:
        ParentImage|endswith:
            - '\services.exe'
            - '\svchost.exe'
            - '\wmiprvse.exe'
    condition: selection and not filter_normal
level: high
```

### Sysmon Configuration

```xml
<!-- CVE-2026-25184: AppLocker linked-list race detection -->

<!-- Event 12/13: Registry writes to Uninstall keys -->
<RegistryEvent onmatch="include">
    <TargetObject condition="contains">\CurrentVersion\Uninstall\</TargetObject>
    <EventType condition="is">SetValue</EventType>
</RegistryEvent>

<!-- Event 7: applockerfltr.sys minifilter loaded (baseline) -->
<ImageLoad onmatch="include">
    <ImageLoaded condition="end with">applockerfltr.sys</ImageLoaded>
</ImageLoad>

<!-- Event 1: Process creation with high thread counts (race tooling) -->
<ProcessCreate onmatch="include">
    <CommandLine condition="contains">UninstallString</CommandLine>
</ProcessCreate>

<!-- Event 8: CreateRemoteThread into AppLocker-hosting process -->
<CreateRemoteThread onmatch="include">
    <TargetImage condition="end with">\svchost.exe</TargetImage>
    <SourceImage condition="excludes">\services.exe</SourceImage>
</CreateRemoteThread>
```

## Version Matrix

| Version | File Version | Status |
|---------|-------------|--------|
| Pre-patch (March 2026) | 10.0.26100.7920 | Vulnerable |
| Post-patch (April 2026, KB5083769) | 10.0.26100.8246 | Fixed (Feature_423566650) |

## References

- [MSRC Advisory: CVE-2026-25184](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2026-25184)
- [Souhail Hammou (@dark_puzzle)](https://x.com/dark_puzzle) — credited researcher
- [MITRE CWE-362: Concurrent Execution Using Shared Resource with Improper Synchronization](https://cwe.mitre.org/data/definitions/362.html)

---
*Analysis by OnlyFm252 / STAR Labs SG — 2026-07-22*
