Share
## https://sploitus.com/exploit?id=C3D90422-8858-5EAC-A8E5-588AF315EA86
# CVE-2026-42978 PoC & Research — Windows Push Notifications Use-After-Free

Race condition in Windows Push Notifications service (`WpnService`) that runs as `NT AUTHORITY\SYSTEM`. An attacker with local access can trigger a use-after-free during platform shutdown and potentially elevate privileges.

- **CVE:** [CVE-2026-42978](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2026-42978)
- **BDU:** [BDU:2026-08249](https://pm.gov.ru/vul/2026-08249)
- **Type:** CWE-362 (Race Condition), Use-After-Free
- **CVSS:** 7.8 (High)
- **Affected:** Windows 10, Windows 11, Windows Server 2016/2019/2022/2025
- **Patched:** June 10, 2026 (Patch Tuesday)
- **Status:** Fixed. This repo is for defensive research only.

## How It Works

`WpnService` is the Windows Push Notification service. It runs in session 0 as LocalSystem inside `svchost.exe -k netsvcs -p`. All notification delivery — toasts, tiles, badges — goes through it.

The vulnerability sits in `wpncore.dll`, specifically in the `PresentationEndpointFacade` class. This class wraps all notification API calls (toast delivery, session management, settings queries, etc.) and delegates to `PresentationEndpointImpl`.

The bug: during platform shutdown, the `NotificationPlatform` object gets destroyed. But the Facade methods don't check if shutdown is in progress — they grab a pointer to the platform, the platform gets freed by the shutdown thread, and the Facade uses a dangling pointer. Classic use-after-free race.

### Vulnerable code (decompiled from wpncore.dll build 26100.8521)

```c
// PresentationEndpointFacade::ToastUnblockAll โ€” VULNERABLE
long ToastUnblockAll(PresentationEndpointFacade *this) {
    // No lock. No shutdown check. Just grab the platform pointer and go.
    NotificationPlatformHandle::Get(this + 0x50);
    if (platform == NULL) Throw_Hr(...);
    // If shutdown frees the platform right here โ€” use-after-free
    return PresentationEndpointImpl::UnblockToastsForEachApp(...);
}
```


  
  
  Ghidra: vulnerable ToastUnblockAll — no synchronization before accessing the platform


### Patched code (wpncore.dll build 26100.8655)

```c
// PresentationEndpointFacade::ToastUnblockAll โ€” PATCHED
long ToastUnblockAll(PresentationEndpointFacade *this) {
    if (Feature_4097557817::IsEnabled()) {
        AcquireSRWLockShared(&Wns::s_platformLock);    // 1. shared lock
        if (Wns::s_platformShutdown)                    // 2. shutdown guard
            Throw_Hr(E_APPLICATION_EXITING);
        NotificationPlatformHandle::Get(this + 0x50);
        // ... do work ...
        ReleaseSRWLockShared(&Wns::s_platformLock);     // 3. RAII release
    } else {
        // feature flag off โ€” old behavior preserved for rollback
    }
}
```

The fix adds three things:
1. **`AcquireSRWLockShared`** — shared readers-writer lock. Multiple API calls can run concurrently, but shutdown takes an exclusive lock and blocks them all.
2. **`s_platformShutdown` check** — if shutdown already started, bail out immediately with `E_APPLICATION_EXITING`.
3. **RAII lock release** — the lock is held in a `wil::unique_storage` wrapper, so it gets released even if an exception is thrown.

The feature flag `Feature_4097557817` is for staged rollout via WIL (Windows Internal Library). It lets Microsoft enable the fix gradually and disable it if something breaks.


  
  
  Ghidra: vulnerable build (left tab) vs patched build (right tab)


### Scale of the fix

This isn't a one-function bug. The same lock+guard pattern was added to **49 functions** in `wpncore.dll`:

| Category | Functions |
|----------|-----------|
| Toast operations | `ToastUnblockAll`, `ToastCreateSession`, `ToastCloseSession`, `ToastRequestAllNotifications`, `ToastSuppress` |
| Tile operations | `TileCreateSession`, `TileCloseSession`, `TileRequestResourceForeground` |
| Registration | `RegisterApplication`, `UnregisterApplication`, `RegisterHandler`, `UpdateRegistration`, `RegisterSystemApplication` |
| Settings | `ChangeAppSetting`, `QueryAppSetting`, `QueryGlobalSetting`, `RegisterSettingCallback`, `UnregisterSettingCallback` |
| Delivery | `Deliver`, `GetPayloadForNotificationId`, `Submit`, `PostScheduledNotification` |
| Queries | `GetRegisteredHandler`, `GetRegisteredHandlersFromParent`, `GetSettingsFromHandler`, `GetAssetsFromHandler` |

Every `PresentationEndpointFacade::*` method that touches the platform got the same fix. The `PresentationEndpointImpl::*` methods underneath are unchanged — the issue was only at the facade layer.

## Impact

WpnService runs as SYSTEM. If the race is won:

1. The freed `NotificationPlatform` object's memory can be reclaimed and filled with attacker-controlled data (heap spray)
2. A subsequent virtual method call on the dangling pointer jumps to an attacker-controlled address
3. Code execution as `NT AUTHORITY\SYSTEM`

The actual exploitation — heap spray, vtable hijacking, achieving code execution — is outside the scope of this research. This repo focuses on **understanding the root cause** and **building detection**.

## TOCTOU Race Condition Lab

The `lab/` directory contains a standalone C demo that reproduces the class of bug without touching WpnService. It uses a named pipe + shared memory architecture similar to WpnService.

**How it works:**
- `vulnerable_service.exe` reads a message length from shared memory, validates it, sleeps for 50ms, then reads the length **again** (double-fetch).
- `race_attacker.exe` sets a safe length, triggers the service, then immediately flips the shared memory to an overflow value.
- If timing is right, the service reads the overflow value on the second fetch — buffer overflow.

Run `vulnerable_service.exe --patched` to see the fix: single-fetch capture into a local variable.


  
  
  Left: service detects race (5/5). Right: attacker flipping shared memory values.


### Build and run

Requires GCC (MinGW). From the `lab/` directory:

```bat
build.bat
```

Terminal 1:
```bat
vulnerable_service.exe
```

Terminal 2:
```bat
race_attacker.exe 5
```

Then compare with `vulnerable_service.exe --patched` — same attack, zero races detected.

## Detection

### ETW Monitor (`detection/etw_wpn_monitor.ps1`)

PowerShell script that checks 7 indicators:

1. WpnService state and PID
2. Crash/restart history (failed exploitation leaves crash traces)
3. Push Notifications Platform event log burst detection
4. WPN-related named pipes
5. Patch verification (checks wpncore.dll date)
6. Processes with WPN modules loaded
7. Symlink/junction audit in notification data paths

```powershell
powershell -ExecutionPolicy Bypass .\detection\etw_wpn_monitor.ps1
```


  
  
  ETW monitor: WpnService running (PID 6432), no crashes, 100 events/hour, system patched


### Sysmon Rules (`detection/sysmon_wpn_race_detect.xml`)

Six rule groups for continuous monitoring:

| Rule | What it catches |
|------|----------------|
| `WPN_EoP_ChildProcess` | svchost (netsvcs) spawning cmd/powershell/wscript |
| `WPN_PipeAccess` | Connections to WPN-related named pipes |
| `WPN_FileCreation` | File creation in notification data directories |
| `WPN_RegistryTampering` | Registry writes to PushNotifications keys |
| `WPN_ProcessAccess` | `PROCESS_ALL_ACCESS` handles to svchost |
| `WPN_ThreadInjection` | `CreateRemoteThread` into svchost |

Install:
```bat
sysmon64.exe -accepteula -i detection\sysmon_wpn_race_detect.xml
```

### Event Viewer

WpnService activity is logged in `Microsoft-Windows-PushNotifications-Platform/Operational`. Key events to watch:

- Event 1225: transport-level WPN commands
- Rapid event bursts (>20/min) — possible race spray
- Error/Critical events — possible crash from failed exploitation


  
  
  Event Viewer: PushNotifications-Platform operational log, Event ID 1225


## Patch Diffing

Key findings from diffing `wpncore.dll`:

- `.text` section grew by **18,432 bytes** (new lock/guard code across 49 functions)
- `.data` section grew by **96 bytes** (new `Wns::s_platformLock` and `Wns::s_platformShutdown` globals)
- No new imports added — `AcquireSRWLockShared`/`ReleaseSRWLockShared` were already in the import table
- New RAII destructor: `~unique_any_t` confirms lock wrapper addition

Full reports are in `reports/`.

## Related CVEs

CVE-2026-42978 is part of a cluster of 9 WPN-related vulnerabilities fixed in June 2026:

| CVE | Type | CWE |
|-----|------|-----|
| CVE-2026-42977 | EoP | Race Condition |
| **CVE-2026-42978** | **EoP** | **Race Condition** |
| CVE-2026-42979 | EoP | Race Condition |
| CVE-2026-42991 | EoP | Race Condition |
| CVE-2026-42969 | Info Disclosure | Race Condition |
| CVE-2026-42970 | Info Disclosure | Race Condition |
| CVE-2026-42973 | Info Disclosure | Race Condition |
| CVE-2026-26167 | EoP | — |
| CVE-2026-32160 | EoP | — |

## Project Structure

```
CVE-2026-42978/
โ”œโ”€โ”€ README.md
โ”œโ”€โ”€ lab/
โ”‚   โ”œโ”€โ”€ vulnerable_service.c    # mock WpnService with double-fetch bug
โ”‚   โ”œโ”€โ”€ race_attacker.c         # attacker that exploits the double-fetch
โ”‚   โ””โ”€โ”€ build.bat               # GCC build script
โ”œโ”€โ”€ detection/
โ”‚   โ”œโ”€โ”€ etw_wpn_monitor.ps1     # 7-check PowerShell detector
โ”‚   โ””โ”€โ”€ sysmon_wpn_race_detect.xml  # Sysmon rule config
โ”œโ”€โ”€ reports/
โ”‚   โ”œโ”€โ”€ PE_DIFF_REPORT.txt      # PE section/import diff results
โ”‚   โ””โ”€โ”€ FUNCTION_DIFF_REPORT.txt # function-level diff (49 changed)
โ””โ”€โ”€ img/                        # screenshots for this README
```

## Requirements

- Windows 10/11 (for running the lab and detection tools)
- GCC / MinGW (for building the C lab)
- Python 3.9+ (for diffing scripts)
- Ghidra 11+ (for headless decompilation, optional)
- Sysmon (for detection rules, optional)

## Disclaimer

This project is for **defensive security research**. The vulnerability is patched. No weaponized exploit code is included. The TOCTOU lab demonstrates the class of bug on a standalone mock service — it does not interact with WpnService or any system component.

Make sure your Windows is up to date. If `etw_wpn_monitor.ps1` reports your system as unpatched — install the June 2026 cumulative update immediately.

## Contributing

If you have something to add — better detection rules, sploit PoC, a Ghidra Version Tracking session, YARA signatures, or analysis of the related CVEs in this cluster — PRs are welcome.

Ideas for contributions:
- Sigma rules for the SIEM side of detection
- Deeper analysis of CVE-2026-42977/42979/42991 (same WPN race family)
- WinDbg-based heap analysis of the use-after-free
- Improved ETW monitor with real-time ALPC burst detection
- Windows Defender ASR rule recommendations

Open an issue if you have questions or want to discuss the research.

## License

MIT