Advisory July 8, 2025 By Chen Le Qi 3 min read
CVE: CVE-2025-49660
Affected Versions: Windows 11
CVSS3.1: 7.8 (High) — CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
| Product | Windows Event Tracing (ETW) |
|---|---|
| Vendor | Microsoft |
| Severity | High — a local attacker may exploit this to elevate privileges to SYSTEM |
| Affected Versions | Windows 11 |
| Tested Versions | Windows 11 23H2 (Build 22631.4660) |
| CVE Identifier | CVE-2025-49660 |
| CVE Description | Insufficient checks in Event Tracing for Windows (ETW) in Microsoft Windows 11 may allow an unprivileged attacker to execute code as SYSTEM |
| CWE Classification(s) | CWE-190: Integer Overflow or Wraparound; CWE-416: Use After Free |
Base Score: 7.8 (High)
Vector String: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
| Metric | Value |
|---|---|
| Attack Vector (AV) | Local |
| Attack Complexity (AC) | Low |
| Privileges Required (PR) | Low |
| User Interaction (UI) | None |
| Scope (S) | Unchanged |
| Confidentiality (C) | High |
| Integrity (I) | High |
| Availability (A) | High |
Event Tracing for Windows (ETW) is a high-performance kernel-level tracing facility built into Windows. It provides user-mode applications and kernel-mode drivers with a mechanism to raise and log events, and is widely used for diagnostics, performance monitoring, and security tooling. ETW is implemented in ntoskrnl.exe and exposed to userspace through syscalls including NtTraceControl().
In ETW, Providers are responsible for emitting trace events. Internally, a provider is represented by a single _ETW_GUID_ENTRY object and one or more _ETW_REG_ENTRY objects — a new _ETW_REG_ENTRY is created for each call to EventRegister(). While the usermode API caps registrations at 0x800, there is no such limit when invoking NtTraceControl() directly with function code 0xF.
Traits can be set on a RegEntry object via EventSetInformation() or directly via NtTraceControl() with function code 0x1E, handled by EtwpSetProviderTraitsCommon(), which inserts the trait as a node into the global red-black tree EtwpProviderTraitsUmTree. Each node has the following layout:
struct _ETW_TRAIT_NODE
{
_RTL_BALANCED_NODE Node;
DWORD RefCount;
BYTE X[1]; // Actual trait data
};
When inserting a trait, EtwpSetProviderTraitsCommon() checks whether an identical trait already exists in the tree. If so, it reuses the existing node and increments its reference count:
while ( 1 )
{
res = TraitsCompare(TraitsBufKernel, curNode);
if ( res <= 0 )
{
if ( res >= 0 )
{
++curNode->RefCount; /* no overflow check */
FromExisting = 1;
traitsBufKernel = curNode;
goto BindToRegEntry;
}
The reference counter is a 32-bit integer and there is no overflow check — unlike other ETW reference counting functions such as EtwpReferenceGuidEntry(). When the counter wraps from 0xFFFFFFFF back to 0, the next decrement in EtwpReleaseProviderTraitsReference() will treat the counter as 1 and prematurely free the trait node while other RegEntry objects still hold references to it:
TraitEntry = (cstmEtwTraitBufKernel *)_InterlockedExchange64(
(volatile __int64 *)&RegHandle->Traits, 0LL);
if ( TraitEntry )
{
ExAcquireFastMutex(lock);
if ( TraitEntry->RefCount-- == 1 )
{
RtlRbRemoveNode(Tree, (unsigned __int64)TraitEntry);
}
else
{
TraitEntry = 0LL;
}
ExReleaseFastMutex(lock);
if ( TraitEntry )
ExFreePoolWithTag(TraitEntry, 0); /* use-after-free */
}
Closing a handle to a RegEntry triggers the decrement, making this a reliable and controllable primitive. Each RegEntry consumes a handle, so approximately 0x1000000 references can be accumulated per process. Wrapping the counter fully requires approximately 256 processes, achievable in under 30 minutes on a system with sufficient RAM.
A similar reference count overflow in ETW was previously reported by Project Zero (issue 42451732).
The recommended mitigation is to introduce integer overflow checks in all reference counting functions, consistent with the existing guard in EtwpReferenceGuidEntry().
Chen Le Qi of STAR Labs SG Pte. Ltd.