Token-stealing shellcode + SMEP bypass (x64)¶
Klasik Windows x64 kernel post-exploitation ikilisi: bir user-mode payload'ın ring 0'da çalışabilmesi için CR4'teki SMEP bit'ini temizleyen bir ROP stub'ı ve SYSTEM process token'ını mevcut process'in token'ı üzerine kopyalayan bir token-stealing payload'u.
Mechanism¶
Note
Burada kavramsal olarak birbirinden bağımsız iki sınır aşılır. SMEP (Supervisor Mode
Execution Prevention), CPU'nun ring 0'dayken user-mode page'leri execute etmesini yasaklar;
CR4'ün 20. bit'i tarafından yönetilir. Bir exploit'in planı "bir kernel control-flow
hijack'ını bir user-mode shellcode buffer'ına yönlendirmek" ise, SMEP fetch'i bir fault ile
bloklar. Bypass, önce bit 20'si temizlenmiş bir CR4 değeri yükleyip onu geri yazan
(mov cr4, rcx) kernel .text gadget'larından oluşturulmuş ufak bir ROP chain'i
çalıştırmaktır; ardından user payload execute olur. Token-stealing payload'u sonra
privilege sınırını aşar: her process'in EPROCESS'i bir Token (bir _EX_FAST_REF) tutar;
SYSTEM process'inin token'ını mevcut process'e kopyalamak onu SYSTEM yapar. Hiçbir adım bir
memory-safety bug'ı değildir — bunlar, ayrı bir control-flow veya write primitive'ini paraya
çeviren finisher'dır.
Walkthrough¶
Connor McGarr'ın "Panic! At The Kernel"ından (Windows 10 x64) kavramsal yeniden inşa. Offset'ler versiyona özgüdür ve turnkey bir chain olarak değil, yalnızca isimlendirilmiş field'lar olarak gösterilir.
SMEP-disable ROP (şekil):
pop rcx ; ret ; rcx = CR4 value with bit 20 (SMEP) cleared
mov cr4, rcx ; ret ; commit -> SMEP off
<user-mode shellcode> ; now fetchable from ring 0
CR4 değeri, bit 20'si mask'lenmiş canlı değerdir (örn. ...1506f8 -> ...506f8); gadget'lar
kernel'de bulunan koddan gelmelidir. Data-only bir rota tercih edildiğinde disable SMEP via CR4
ROP ve ilgili page table entry overwrite for SMEP/NX
bypass'e bak.
Token-stealing payload (mantıksal adımlar):
- Mevcut thread'i al:
gs:[0x188]'i oku ->_KTHREAD. (gs:[0x188]= x64 KPCR'ınPrcb.CurrentThreadpointer'ı; Windows 10 x64 için standart kabul edilir ama build'e göre teyit et — WinDbgdt nt!_KPCRile resolve edilir.) - Mevcut process'in
_EPROCESS'ine ilerle. ActiveProcessLinks(doubly linked list) üzerinde,UniqueProcessId4'e (SYSTEM process'i) eşit olana kadarUniqueProcessId'leri karşılaştırarak yürü.- SYSTEM'in
Token'ını oku, düşük_EX_FAST_REFreference-count bit'lerini mask'le (& ~0xF, yani bit 0-3'ü temizle; aşağıdaki asm'de bu, 64-bit'te eşdeğeri olanand rcx, 0xfffffffffffffff0olarak görünür). - O token'ı mevcut process'in
Tokenfield'ına yaz; temizce user mode'a dön.
; conceptual, named fields only
mov rax, gs:[0x188] ; _KTHREAD
mov rax, [rax + KTHREAD.Process] ; _EPROCESS (current)
; ... walk EPROCESS.ActiveProcessLinks until UniqueProcessId == 4 ...
mov rcx, [system + EPROCESS.Token]
and rcx, 0xfffffffffffffff0
mov [current + EPROCESS.Token], rcx
Offset'ler burada neden bilinçli olarak soyutlandı
KTHREAD.Process, EPROCESS.UniqueProcessId, ActiveProcessLinks ve EPROCESS.Token
offset'leri Windows build'leri arasında değişir; belirli bir versiyon için kamuya açık
writeup'a danış. Bu giriş onları symbol olarak tutar. Bkz. EPROCESS token stealing
ve Win10 2004 EPROCESS offset changes.
Her iki stub'a ulaşmak için gereken control-flow, ayrı bir bug tarafından, çoğunlukla bir kernel ROP stack pivot üzerinden sağlanır.
Detection¶
- Davranışsal: token'ı aniden SYSTEM token'ına eşit olan SYSTEM olmayan bir process
(meşru bir
DuplicateTokenEx/impersonation çağrısı olmadan token duplication) — ETW/EDR token-context auditing ve integrity-level sıçramaları üzerinden tespit edilebilir. - Crash/telemetri:
CR4'e beklenmedik write'lar veya ardından recovery gelen ring-0 execution fault'ları anormaldir; HVCI/PatchGuard ihlalleri bugcheck'e yol açabilir. - Memory forensics: parent'ının privilege soyağacıyla eşleşmeyen bir process'in
EPROCESS.Token'ı; yakalanan shellcode'da birActiveProcessLinkstraversal deseni.
Mitigation¶
- HVCI / VBS: Hypervisor-enforced code integrity, kernel içinde unsigned/user page'lerin execute edilmesini engeller ve SMEP durumundan bağımsız olarak "user shellcode'a atla" modelini yener.
- kCFG / kCET: Kernel Control Flow Guard ve donanımsal shadow stack'ler indirect call/return'leri kısıtlar ve CR4'ü flip eden ROP'u kırar. Bkz. supervisor-mode execution prevention.
- PatchGuard / KDP: Kernel Data Protection ve PatchGuard kritik yapılara yapılan tampering'i tespit eder; CR4 manipülasyonu ve token swap'leri daha kırılgan ve gözlemlenebilir hale gelir.
- Kök bug'ı patch'li tut — finisher yalnızca ayrı bir güvenlik açığı üzerinden erişilebilir.