Skip to content

HVCI / VBS kernel code-integrity bypass approaches

HVCI, SLAT-enforced W^X ile VTL 0 kernel'ında unsigned code'un execute edilmesini imkânsız kılar; bu yüzden attacker'lar shellcode yerine data-only exploitation'a ya da HVCI altında hâlâ yüklenen signed-but-vulnerable driver'lara (BYOVD) pivot eder — bu not defensive/kavramsal bir katalog kaydıdır.

Mechanism

Invariant: bir code page ya writable ya executable olur, ikisi birden asla değil

Virtualization-Based Security (VBS), Windows hypervisor'ını kullanarak kernel'ın kendisinin bile compromise olabileceğini varsayan izole bir root-of-trust yaratır. Bu mimari Virtual Trust Level'lara bölünür: VTL 1 secure kernel'ı (securekernel.exe) barındırır, VTL 0 ise normal Windows kernel'ıdır. Hypervisor-Protected Code Integrity (HVCI), Second Layer Address Translation (SLAT — Intel'de Extended Page Tables, EPT) üzerinden kernel memory'sine bir W^X invariant'ı dayatır.

Kilit nokta şudur: normal kernel'ın gördüğü Page Table Entry'lerin (PTE) yanında, hypervisor'ın kontrol ettiği bir Extended Page Table Entry (EPTE) katmanı vardır. EPTE, bu senaryoda root of trust'tır; permission'ını page üzerinde PTE ne derse desin zorlar. VTL 1 boot sırasında HvCallModifyVtlProtectionMask benzeri hypercall'larla EPTE protection'larını sabitler: her kernel page ya read/write ya da read/execute olur. Bir page executable yapılmadan önce code-integrity check'ini secure environment içinde geçmek zorundadır ve executable page'ler bir daha writable olamaz.

Sonuç: klasik "shellcode'u writable bir page'e yaz, sonra o page'i executable yap" akışı ölür. Attacker PTE'yi bozup page'i KRWX işaretlese bile EPTE eski permission'ı koruduğu için access violation olur. User-mode RWX code'a kernel'dan sıçrama girişimi de Mode-Based Execution Control (MBEC) / Restricted User Mode ile engellenir: kernel execute ederken tüm user-mode page'ler non-executable işaretlenir.

Walkthrough

Sadece kavramsal — kamuya açık writeup'a defender bakışı; weaponize edilmiş exploit yok

Boundary crossed olmadığı için, "bypass" aslında invariant'ı hiç ihlal etmeden etrafından dolaşmaktır. Connor McGarr'ın public "No Code Execution? No Problem" writeup'ı iki ana yaklaşımı ortaya koyar:

Yaklaşım 1 — Data-only / ROP (signed code'u reuse et):

  1. Attacker'ın elinde zaten bir arbitrary kernel read/write primitive'i var (ayrı bir bug'dan).
  2. Unsigned code execute edilemediği için, hedef kendi shellcode'unu çalıştırmak değil; var olan signed kernel code'unu (ntoskrnl gadget'ları, meşru API'ler) bir ROP chain hâlinde zincirlemektir. Bu "HVCI compliant" kalır.
  3. Kavramsal reprodüksiyon: suspended bir dummy thread yarat, onun kernel stack'ini leak et, thread'in beklediği return address'i ilk ROP gadget ile overwrite et, thread'i resume et.
  4. Chain, PsGetCurrentProcess gibi meşru API'leri çağırıp token manipülasyonu gibi bir data-only hedefe ulaşır, sonra temiz şekilde ZwTerminateThread ile döner.
  5. Kernel CFG (kCFG) indirect call target'ları kısıtlar; CFG bitmap'i de SLAT ile read-only tutulduğu için exploitation ROP'a doğru itilir. Bu yaklaşımın doğal düşmanı, backward-edge control-flow'u kilitleyen kernel CET (shadow stack)'tir.

Yaklaşım 2 — BYOVD (Bring Your Own Vulnerable Driver):

  1. HVCI, driver'ın code integrity'sini doğrular; driver'ın functionality'sinin güvenli olup olmadığını doğrulamaz.
  2. Meşru şekilde imzalı ama zafiyetli bir driver (ör. arbitrary R/W IOCTL expose eden) HVCI açıkken bile yüklenir — çünkü signature geçerlidir.
  3. Attacker bu signed driver üzerinden kernel R/W primitive'i elde eder ve tekrar Yaklaşım 1'deki data-only manipülasyonlara döner.
  4. Yani HVCI, unsigned kod barajını yükseltir ama BYOVD attack surface'ini tek başına kapatmaz; onu kapatan şey vulnerable-driver blocklist'idir.

Detection

  • VBS/HVCI durumu: Endpoint'lerde HVCI'nin gerçekten "running" olduğunu envanterle (msinfo32Virtualization-based security Services Running; ya da DeviceGuard WMI class). HVCI'nin sessizce disabled olduğu host'lar anomali sayılır.
  • BYOVD göstergeleri: Bilinen vulnerable driver'ların (LOLDrivers/Microsoft blocklist hash'leri) sc create / NtLoadDriver ile beklenmedik path'lerden (ör. %APPDATA%) yüklenmesine alarm ver.
  • Suspicious kernel data manipulation: EPROCESS token değişimi, PsCreateProcessNotifyRoutine callback array'inin toplu sıfırlanması gibi data-only pattern'ler; bunlar code injection olmadan gerçekleştiği için memory-scan yerine davranışsal telemetri gerekir.
  • Thread/stack anomalileri: Suspended thread'lerin kernel stack return address'lerinin beklenmedik biçimde değişmesi, ROP-based data-only yaklaşımın izidir (ileri EDR/hypervisor agent görünürlüğü gerektirir).
  • kCET/kCFG: nt!KeIsKernelCetEnabled ile kernel shadow stack durumunu kontrol et; kapalıysa ROP yaklaşımı daha uygulanabilir kalır.

Mitigation

  • HVCI'yi UEFI lock ile etkinleştir: Memory Integrity'yi (Windows Security → Core Isolation) aç ve mümkünse UEFI lock + "Mandatory" enforcement ile config'in sessizce zayıflatılmasını önle.
  • Microsoft Vulnerable Driver Blocklist / WDAC: BYOVD'nin gerçek karşılığı budur. Blocklist, driver'ı load stage'inde — HVCI code'u doğrulamadan önce — engeller. Windows 11 ve Server 2022 bunu default zorunlu kılar; eski sistemler DriverSiPolicy.p7b ile uygular. Ortama özgü custom WDAC deny policy'leriyle genişlet.
  • Kernel CET (shadow stack): Destekleyen donanımda etkinleştir; backward-edge ROP'u kırarak data-only reuse chain'lerini büyük ölçüde etkisizleştirir.
  • Downgrade koruması: VBS binary'lerinin (secure kernel, ci.dll) eski-vulnerable sürümlere rollback'ini önleyen revocation policy'leri uygula (bkz. VBS downgrade EoP).
  • Defense in depth: Least privilege ile admin token dağılımını daralt; arbitrary R/W bug'larının ortaya çıkardığı ilk primitive'i azaltmak için driver hardening ve attack-surface reduction uygula.

References

See also