
CVE-2026-42978 — Condizione di gara Use-After-Free in Windows Push Notifications (WpnService). Diff della patch, analisi della causa principale, laboratorio TOCTOU, regole di rilevamento Sysmon/ETW.
Condizione di gara nel servizio Windows Push Notifications (WpnService) che viene eseguito come NT AUTHORITY\SYSTEM. Un attaccante con accesso locale può innescare un use-after-free durante l'arresto della piattaforma e potenzialmente elevare i privilegi.
WpnService è il servizio Windows Push Notification. Viene eseguito nella sessione 0 come LocalSystem all'interno di svchost.exe -k netsvcs -p. Tutta la consegna delle notifiche — toast, tile, badge — passa attraverso di esso.
La vulnerabilità risiede in wpncore.dll, in particolare nella classe PresentationEndpointFacade. Questa classe incapsula tutte le chiamate API di notifica (consegna dei toast, gestione delle sessioni, query delle impostazioni, ecc.) e delega a PresentationEndpointImpl.
Il bug: durante l'arresto della piattaforma, l'oggetto NotificationPlatform viene distrutto. Ma i metodi della Facade non verificano se l'arresto è in corso — ottengono un puntatore alla piattaforma, la piattaforma viene liberata dal thread di arresto e la Facade usa un puntatore pendente. Classica condizione di gara use-after-free.
// 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: ToastUnblockAll vulnerabile — nessuna sincronizzazione prima dell'accesso alla piattaforma
// 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
}
}
La correzione aggiunge tre elementi:
AcquireSRWLockShared — blocco lettori-scrittori condiviso. Più chiamate API possono essere eseguite in concorrenza, ma l'arresto acquisisce un blocco esclusivo e le blocca tutte.s_platformShutdown — se l'arresto è già iniziato, esce immediatamente con E_APPLICATION_EXITING.wil::unique_storage, quindi viene rilasciato anche se viene lanciata un'eccezione.Il feature flag Feature_4097557817 serve per il rollout graduale tramite WIL (Windows Internal Library). Consente a Microsoft di abilitare la correzione gradualmente e di disabilitarla se qualcosa si rompe.
Non è un bug di una singola funzione. Lo stesso pattern blocco+guardia è stato aggiunto a 49 funzioni in wpncore.dll:
| Categoria | Funzioni |
|---|---|
| Operazioni toast | ToastUnblockAll, ToastCreateSession, ToastCloseSession, ToastRequestAllNotifications, ToastSuppress |
| Operazioni tile | TileCreateSession, TileCloseSession, TileRequestResourceForeground |
| Registrazione | RegisterApplication, UnregisterApplication, RegisterHandler, UpdateRegistration, RegisterSystemApplication |
| Impostazioni | ChangeAppSetting, QueryAppSetting, QueryGlobalSetting, RegisterSettingCallback, UnregisterSettingCallback |
| Consegna | Deliver, GetPayloadForNotificationId, Submit, PostScheduledNotification |
| Query | GetRegisteredHandler, GetRegisteredHandlersFromParent, GetSettingsFromHandler, GetAssetsFromHandler |
Ogni metodo PresentationEndpointFacade::* che tocca la piattaforma ha ricevuto la stessa correzione. I metodi PresentationEndpointImpl::* sottostanti sono invariati — il problema era solo a livello di facade.
WpnService viene eseguito come SYSTEM. Se la gara viene vinta:
NotificationPlatform liberato può essere rioccupata e riempita con dati controllati dall'attaccante (heap spray)NT AUTHORITY\SYSTEMLo sfruttamento vero e proprio — heap spray, hijacking della vtable, ottenimento dell'esecuzione di codice — è fuori dallo scopo di questa ricerca. Questo repository si concentra sulla comprensione della causa principale e sulla costruzione di strumenti di rilevamento.
La directory lab/ contiene una demo C standalone che riproduce la classe di bug senza toccare WpnService. Usa un'architettura a named pipe + memoria condivisa simile a WpnService.
Come funziona:
vulnerable_service.exe legge una lunghezza del messaggio dalla memoria condivisa, la valida, dorme per 50 ms, poi legge di nuovo la lunghezza una seconda volta (double-fetch).race_attacker.exe imposta una lunghezza sicura, attiva il servizio, poi inverte immediatamente la memoria condivisa a un valore di overflow.Esegui vulnerable_service.exe --patched per vedere la correzione: acquisizione singola (single-fetch) in una variabile locale.
Sinistra: il servizio rileva la gara (5/5). Destra: l'attaccante inverte i valori della memoria condivisa.
Richiede GCC (MinGW). Dalla directory lab/:
build.bat
Terminale 1:
vulnerable_service.exe
Terminale 2:
race_attacker.exe 5
Quindi confronta con vulnerable_service.exe --patched — stesso attacco, zero gare rilevate.
detection/etw_wpn_monitor.ps1)Script PowerShell che controlla 7 indicatori:
powershell -ExecutionPolicy Bypass .\detection\etw_wpn_monitor.ps1