Skip to content

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):

  1. Mevcut thread'i al: gs:[0x188]'i oku -> _KTHREAD. (gs:[0x188] = x64 KPCR'ın Prcb.CurrentThread pointer'ı; Windows 10 x64 için standart kabul edilir ama build'e göre teyit et — WinDbg dt nt!_KPCR ile resolve edilir.)
  2. Mevcut process'in _EPROCESS'ine ilerle.
  3. ActiveProcessLinks (doubly linked list) üzerinde, UniqueProcessId 4'e (SYSTEM process'i) eşit olana kadar UniqueProcessId'leri karşılaştırarak yürü.
  4. SYSTEM'in Token'ını oku, düşük _EX_FAST_REF reference-count bit'lerini mask'le (& ~0xF, yani bit 0-3'ü temizle; aşağıdaki asm'de bu, 64-bit'te eşdeğeri olan and rcx, 0xfffffffffffffff0 olarak görünür).
  5. O token'ı mevcut process'in Token field'ı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 bir ActiveProcessLinks traversal 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.

References