# CVE-2026-42980 — Windows Kernel WMI Integer Underflow (`WmipQuerySingleMultiple` / `WmipQueryAllDataMultiple`) → OOB Write → EoP

---

## Summary

| **Product**           | Microsoft Windows — `ntoskrnl.exe` (WMI kernel subsystem) |
|-----------------------|-----------------------------------------------------------------------|
| **Vendor**            | Microsoft Corporation |
| **Severity**          | Important (MSRC) — CVSS 7.8 High |
| **Affected Versions** | Windows 11 24H2 (and other SKUs) before the July 2026 security updates |
| **Tested Version**    | Windows 11 24H2 — ntoskrnl 10.0.26100.8737 (pre-patch, KB5095093) vs 10.0.26100.8875 (post-patch, KB5101650) |
| **Impact**            | Elevation of Privilege — unsigned-integer underflow → OOB kernel pool write → SYSTEM |
| **CVE ID**            | CVE-2026-42980 |
| **CWE**               | CWE-191 (Integer Underflow) → CWE-122 (Heap-based Buffer Overflow) (per MSRC; consequence class also mappable to CWE-787 Out-of-bounds Write) |
| **Vulnerable functions** | `nt!WmipQueryAllDataMultiple` (IOCTL `0x22812C`), `nt!WmipQuerySingleMultiple` (IOCTL `0x228130`) |
| **PoC Available**     | Yes — full LPE by G4sp4rCS; blue-team trigger/detector below derived from it |
| **Patch Available**   | Yes — July 2026 (KB5101650 on Win11 24H2) |
| **Fix**               | Saturating subtraction behind WIL flag `Feature_1045423416` |
| **Primary source**    | G4sp4rCS — *Reversing and Exploiting the Windows Kernel WMI Underflow* |

---

## CVSS 3.1 Detailed Scoring

**Base Score:** 7.8 (HIGH) — **Temporal Score:** 6.8 (per MSRC)
**Vector String:** `CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H/E:U/RL:O/RC:C` (MSRC; base metrics `AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H`)

Rationale for the base metrics (matches the MSRC assessment):

| **Metric** | **Value** | **Rationale** |
|---|---|---|
| **Attack Vector (AV)** | Local | IOCTLs to `\Device\WMIDataDevice` from a local process |
| **Attack Complexity (AC)** | Low | Deterministic window discovery at runtime; no race |
| **Privileges Required (PR)** | Low | Standard user; WMI data device is accessible without admin |
| **User Interaction (UI)** | None | — |
| **Scope (S)** | Unchanged | — |
| **C/I/A** | High | Full kernel read/write achieved → token theft → SYSTEM |

---

## Product Description

Windows Management Instrumentation (WMI) is the kernel + user-mode
infrastructure for querying system telemetry: hardware state, drivers,
performance counters, power settings, monitors, SMBIOS data, and more.
User-mode consumers go through `advapi32.dll` (`WmiOpenBlock`,
`WmiQueryAllDataW`) or talk directly to the kernel WMI data device
(`\Device\WMIDataDevice`) with `DeviceIoControl` /
`NtDeviceIoControlFile`.

Two kernel IOCTL handlers serialize **multiple** WMI data items into one
caller buffer:

- `IOCTL_WMI_QUERY_ALL_DATA_MULTIPLE` = `0x22812C` → `nt!WmipQueryAllDataMultiple`
- `IOCTL_WMI_QUERY_SINGLE_MULTIPLE` = `0x228130` → `nt!WmipQuerySingleMultiple`

Both loops keep a running 32-bit *remaining output* counter as they pack
WNODE records into the buffer.

---

## Vulnerability Summary

Both loops subtract an **8-aligned, provider-reported size** from the
remaining counter **without checking it fits**:

```c
// nt!WmipQueryAllDataMultiple — vulnerable sub @ +0x29a
AlignedSize = (QueryInfo[0] + 7) & 0xFFFFFFF8;
OutputBufferLength -= AlignedSize;            // unchecked

// nt!WmipQuerySingleMultiple — vulnerable sub @ +0x401
AlignedActualSize = (ReturnedDataSize + 7) & 0xFFFFFFF8;
OutBufferSize -= AlignedActualSize;           // unchecked
```

The exploitable mismatch in `WmipQuerySingleMultiple`:

- the **capacity gate** uses a caller-influenced estimate
  `requiredSize = (DataSize + 73) & ~7`,
- the **subtraction** uses the provider-returned actual size
  `ALIGN8(ReturnedDataSize)`.

Pick a WMI instance whose real serialized size `R` is **not** 8-aligned and
set `outLen = R`:

```
gate:      requiredSize <= R            -> accepted
subtract:  R - ALIGN8(R)                -> wraps (e.g. 0x94 - 0x98 = 0xFFFFFFFC)
```

The kernel now believes the output buffer has ~4 GB free, and the **next
WNODE item** in the same request is serialized out of bounds past the kernel
`SystemBuffer` — an OOB write with attacker-controlled bytes at
`OOB_WNODE + 0x42` (instance-data copy).

The patch replaces both subtractions with a saturating form gated by
`Feature_1045423416`: on underflow the counter clamps to `0`, the next item
fails the capacity gate, and no OOB write occurs.

---

## Prerequisites and Constraints

- Local authenticated session, standard user (no admin)
- `\Device\WMIDataDevice` openable directly, or via the WMI device interface
  GUID `{3c0d501a-140b-11d1-b40f-00a0c9223196}` (cfgmgr32 fallback)
- At least one enumerable WMI instance whose measured serialized size `R` is
  not 8-aligned ("slop") — the PoC scans a GUID dataset at runtime
  (`WmiOpenBlock` + `WmiQueryAllDataW` + a binary search of `R`), so no
  hardcoded provider is required
- No race condition; the whole trigger is one IOCTL with two items

---

## Vulnerability Details

### Reaching the bug from userspace (the "hint")

| Interface | Role |
|---|---|
| `CreateFile("\\.\GLOBALROOT\Device\WMIDataDevice")` | open the WMI data device |
| `DeviceIoControl(dev, 0x228130, in, 0xFF0, out, R)` | **the trigger** — `IOCTL_WMI_QUERY_SINGLE_MULTIPLE` with a two-item input |
| `WmiOpenBlock` / `WmiQueryAllDataW` (advapi32) | enumerate GUIDs/instances to find one with non-aligned `R` |
| `DeviceIoControl(dev, 0x228130, ..., outLen=mid)` probes | binary-search the exact `R` (watch `WNODE.Flags & 0x20` = `WF_TOO_SMALL`) |
| IOCTL `0x22812C` | alternate vulnerable path (`WmipQueryAllDataMultiple`) |

**Input layout for `0x228130`** (each 0x18-byte item becomes one WNODE):

```c
struct WMI_QSM_INPUT {          // METHOD_BUFFERED input
    ULONG ItemCount;            // +0x00  = 2
    // +0x04 pad
    WMI_QSM_ITEM Items[2];      // +0x08
};
struct WMI_QSM_ITEM {           // 0x18 bytes
    UINT64 InstanceCookieOrHandle;  // +0x00 — REAL open WMI handle for item[0]
    USHORT DataSize;                // +0x08 — instance name length
    USHORT DataFlags;               // +0x0A
    ULONG  Reserved;                // +0x0C
    UINT64 InputData;               // +0x10 — user-mode ptr to name bytes
};
```

Note: `item[0].InstanceCookieOrHandle` **must be a real open WMI GUID handle**
(`WmiOpenBlock`); with 0, `ObReferenceObjectByHandle` fails and the
vulnerable subtraction is never reached.

### Complete kernel call flow

```
User mode:
  WmiOpenBlock(guid, WMIGUID_QUERY|EXECUTE, &h)          // open instance handle
  WmiQueryAllDataW(h, ...)                               // enumerate instance names
  CreateFile("\\.\GLOBALROOT\Device\WMIDataDevice")
  DeviceIoControl(dev, 0x228130, in, 0xFF0, out, R)      // TRIGGER
      │  NtDeviceIoControlFile → I/O manager
      ▼
Kernel mode (ntoskrnl.exe):
  nt!WmipIoControl                        [device dispatch]
    switch (ioctl):
      0x22812C → nt!WmipQueryAllDataMultiple   [*** vulnerable sub @ +0x29a ***]
      0x228130 → nt!WmipQuerySingleMultiple    [*** vulnerable sub @ +0x401 ***]
          │  per item:
          │    requiredSize = (DataSize + 73) & ~7        // capacity GATE
          │    if (requiredSize > outRemaining) → WF_TOO_SMALL scratch path
          │    → nt!WmipQueryAllData / WmipQuerySetExecuteSI
          │        → nt!WmipForwardWmiIrp → WMI provider (returns actual size)
          │    alignedActualSize = (ReturnedDataSize + 7) & ~7
          │    outRemaining -= alignedActualSize          // ← WRAPS for item[0]
          │    wnodeCursor   += alignedActualSize
          │  item[1]: gate sees wrapped (huge) outRemaining → accepted
          │    memmove(wnodeCursor->InstanceData, item[1].Data, DataSize)
          │       ── OOB write past SystemBuffer, controlled bytes at +0x42 ──
          ▼
  (exploit) overwritten NP_DATA_QUEUE_ENTRY of a sprayed named pipe
```

### Why `SystemBuffer` size and pipe spray matter

`IOCTL 0x228130` is `METHOD_BUFFERED`: the kernel allocates the SystemBuffer
as `max(InputBufferLength, OutputBufferLength)`. Setting `inLen = 0xFF0`
places it in the **0x1000 pool bucket** — the same bucket as sprayed npfs
`NP_DATA_QUEUE_ENTRY` objects (`0x30` header + `0xFF0` data body). The
exploit sprays pipes to build a stable sequence of same-sized pipe data
objects, frees one entry (hole), fires the
IOCTL so the SystemBuffer lands in the hole, and the OOB WNODE write from
item[1] lands on the adjacent pipe entry's header.

Overwrite geometry (dynamic, per measured window):

```c
phase          = (alignedActualSize + 0x42) & 0xFFF;   // WNODE instance-data offset
overwriteOffset = phase ? (0x1000 - phase) : 0;
```

### The patch

Both functions get the identical saturating subtraction, gated by
`Feature_1045423416`:

```c
v = OutBufferSize - AlignedActualSize;
if (Feature_1045423416__private_IsEnabledDeviceUsageNoInline())
    v = -(unsigned int)(AlignedActualSize < OutBufferSize) & v;
OutBufferSize = v;    // underflow → 0, not 0xFFFFFFFF
```

With the counter clamped to zero, the next item's `requiredSize` check fails
and serialization stops before any OOB write.

### Patch-diff verification (ghidriff + GhidraMCP, 2026-07-20)

A full ghidriff VersionTracking diff of ntoskrnl 10.0.26100.8737 vs
10.0.26100.8875 matched **70,713 / 70,714 functions** with only **6
code-changed functions** (FSRTL oplock, Secure Boot/BCD, hotpatch and heap
churn) — **none in the WMI path**. Live decompilation of the **pre-patch**
.8737 binary via GhidraMCP confirms why: the saturating-subtraction code
above is *already compiled into both builds* — `WmipQuerySingleMultiple` @
`0x1407a4fc0` and `WmipQueryAllDataMultiple` both contain the flag check and
both branches, and both `Feature_1045423416__private_IsEnabledDeviceUsageNoInline`
(@ `0x14064a9d4`) and `..._IsEnabledFallback` (@ `0x14064aa0c`) exist
pre-patch. **KB5101650 did not add the fix; it enabled it** — the patch is a
Controlled Feature Rollout flag flip, with the flag state living in
servicing/rollout data outside what a function-level binary diff compares.
Detection and hunting should therefore key on *behavior* (the IOCTL patterns
below), not on byte signatures of a "patched" function.

---

## Exploitation Scenario (G4sp4rCS public chain)

1. **Detect build**, select EPROCESS/TOKEN/IRP offsets.
2. **Spray** named pipes filled to create 0x1000-byte `NpFr` data queue
   entries; free one (hole).
3. **Calibrate**: scan WMI GUID dataset → instance with slop
   (`R=0x94, aligned=0x98` preferred; fallback windows computed dynamically,
   e.g. `R=0x9C/aligned=0xA0` → `overwriteOff=0xF1E`).
4. **Trigger #1** (`0x228130`, two items): underflow + OOB write inflates a
   pipe entry's readable size → `PeekNamedPipe` over-read leaks npfs links at
   `+0xFD0` (flink/blink).
5. **Trigger #2**: reshape the corrupted entry as an IRP-backed queue entry →
   arbitrary kernel read via `PeekNamedPipe`.
6. Walk `IRP → ETHREAD → EPROCESS → ActiveProcessLinks → PID 4 → SYSTEM token`.
7. **Token write**: an IRP completion/write path writes the SYSTEM token into
   the current process token; repair the pipe entry; spawn `cmd.exe` as SYSTEM.

Observed candidate WMI providers (build-dependent — the PoC resolves at
runtime): `WmiMonitorConnectionParams` (guid#156), `MSNdis_CoTransmitPduErrors`
(#27), `MSPower_DeviceEnable` (#463), `MSSmBios_RawSMBiosTables` (#506),
`MS_SystemInformation` (#553), `MSDiskDriver_Performance` (#658).

---

## Trigger PoC

See [`poc/poc_cve_2026_42980.c`](/data/patch_diffs/poc/poc_cve_2026_42980.c)
(+ `poc_cve_2026_42980_wmi_guids.h` GUID dataset). Derived from G4sp4rCS's
exploit, reduced to the blue-team stages: resolve a slop instance → spray
pipes → fire the two-item `0x228130` trigger → **detect the corrupted pipe**
via `PeekNamedPipe` over-read. It does not build the arbitrary-read/token
stages.

- **Pre-patch VM:** `[!] VULNERABLE: corrupted pipe found` — kernel pool is
  corrupt at that point; run only in a snapshotted VM and reboot after.
- **Patched:** counter saturates; no corruption detected.

---

## Detection Rules

### YARA — PoC tooling

```yara
rule CVE_2026_42980_WMI_Underflow_PoC {
    meta:
        description = "Detects CVE-2026-42980 WMI underflow PoC binaries"
        author = "OnlyFm252"
        date = "2026-07-19"
        cve = "CVE-2026-42980"
        tlp = "white"
    strings:
        $dev   = "WMIDataDevice" ascii wide nocase
        $api1  = "WmiOpenBlock" ascii
        $api2  = "WmiQueryAllDataW" ascii
        $api3  = "PeekNamedPipe" ascii
        $ioctl = { 30 81 22 00 }                       // 0x00228130 little-endian
        $pipe  = "\\\\.\\pipe\\" ascii wide nocase
    condition:
        uint16(0) == 0x5A4D and filesize < 2MB and
        $dev and $ioctl and ($api1 or $api2) and ($api3 or $pipe)
}
```

### Sigma — suspicious WMI data-device access

```yaml
title: Direct WMIDataDevice Access by Non-System Process (CVE-2026-42980)
id: 4a2b6c80-4298-0cde-8ab1-202607080001
status: experimental
description: >
    Detects processes opening \Device\WMIDataDevice directly. CVE-2026-42980
    is triggered by DeviceIoControl 0x228130/0x22812C against this device;
    legitimate consumers almost always go through advapi32 WMI APIs instead.
author: OnlyFm252
date: 2026/07/19
references:
    - https://github.com/G4sp4rCS/CVE-2026-42980-POC
logsource:
    category: file_event
    product: windows
detection:
    selection:
        TargetFilename|contains: 'WMIDataDevice'
    condition: selection
falsepositives:
    - WMI management/monitoring software
level: high
tags:
    - attack.privilege_escalation
    - attack.t1068
    - cve.2026.42980
```

### Sigma — named-pipe spray + WMI correlation

```yaml
title: Mass Named Pipe Creation Followed by WMI Activity (CVE-2026-42980)
id: 5b3c7d91-4298-1def-9bc2-202607080002
status: experimental
description: >
    The CVE-2026-42980 exploit sprays a large number of same-sized pipe data
    objects for pool grooming immediately before the WMI IOCTL trigger. Alert on a
    single process creating an abnormal number of named pipes.
author: OnlyFm252
date: 2026/07/19
logsource:
    category: pipe_created
    product: windows
detection:
    selection:
        PipeName|contains: ''
    condition: selection | count(Image) by Image > 500
    timeframe: 30s
falsepositives:
    - Pipe-heavy IPC servers (rarely exceed hundreds of instances in seconds)
level: high
tags:
    - attack.privilege_escalation
    - attack.t1068
    - cve.2026.42980
```

### Sysmon configuration

```xml
<!-- Sysmon rules for CVE-2026-42980 detection -->
<RuleGroup name="CVE-2026-42980" groupRelation="or">

  <!-- Event 17: mass pipe creation (pool spray) -->
  <PipeEvent onmatch="include">
    <Rule name="PipeSpray" groupRelation="and">
      <Image condition="excludes">C:\Windows\</Image>
      <Image condition="excludes">C:\Program Files\</Image>
    </Rule>
  </PipeEvent>

  <!-- Event 8/9 raw access to WMI device is not directly logged;
       pipe telemetry + image load of advapi32 WMI usage is the proxy -->
  <ImageLoad onmatch="include">
    <Rule name="WMI_API_Load" groupRelation="and">
      <ImageLoaded condition="end with">wmipcoredll.dll</ImageLoaded>
      <Image condition="excludes">C:\Windows\</Image>
    </Rule>
  </ImageLoad>

</RuleGroup>
```

---

## Remediation

1. **Apply KB5101650** (July 2026) or later. Verify
   `ntoskrnl.exe ≥ 10.0.26100.8875`.
2. **Deploy the detections above** — direct `WMIDataDevice` opens by user
   processes and burst pipe creation are high-signal, low-noise.
3. **Restrict** `\Device\WMIDataDevice` ACLs in hardened builds if WMI
   device-interface access isn't needed by standard users.
4. **Hunt**: crash dumps (bugchecks) referencing `nt!WmipQuerySingleMultiple`
   / `nt!WmipQueryAllDataMultiple` on pre-patch builds.

---

## Timeline

| Date | Event |
|---|---|
| 2026-06-09 | Microsoft publishes CVE-2026-42980 in the June 2026 security updates (MSRC; Important, EoP) |
| 2026-07-07 | G4sp4rCS publishes full analysis + LPE exploit (repo created 2026-07-07) |
| 2026-07-14 | July 2026 Patch Tuesday — KB5101650 (Win11 24H2) enables the `Feature_1045423416` fix |
| 2026-07-19 | This analysis: blue-team package derived from the public PoC |
| 2026-07-20 | ghidriff diff completed + GhidraMCP verification: fix is a `Feature_1045423416` CFR flag flip — patched code already present in the pre-patch build |

---

## References

- [G4sp4rCS — CVE-2026-42980 writeup](https://github.com/G4sp4rCS/CVE-2026-42980-POC/blob/main/writeup-en.md)
- [G4sp4rCS — CVE-2026-42980 PoC repo](https://github.com/G4sp4rCS/CVE-2026-42980-POC)
- [MSRC — CVE-2026-42980](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2026-42980)
- [OnlyFm252 diff report — ntoskrnl_exe-kb5101650](/data/patch_diffs/ntoskrnl_exe-kb5101650.md)

---

<sub>Analysis: derived from the G4sp4rCS public writeup + PoC source review.
Local ghidriff diff of ntoskrnl-10.0.26100.8737.exe vs 10.0.26100.8875.exe
(Windows 11 24H2) completed — report in `ghidriff/CVE-2026-42980/ghidriffs/`;
70,713/70,714 functions matched, 6 code-changed (none in the WMI path).
Flag-flip verified by live GhidraMCP decompilation of the pre-patch binary:
`WmipQuerySingleMultiple` @ 0x1407a4fc0 and `WmipQueryAllDataMultiple`
already contain the saturating subtract behind
`Feature_1045423416__private_IsEnabledDeviceUsageNoInline` @ 0x14064a9d4.</sub>
