Kernel Race Condition Exploitation via Object Manager Slow Paths
Tip
AWS Hacking’i öğrenin ve pratik yapın:
HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın:HackTricks Training GCP Red Team Expert (GRTE)
Azure Hacking’i öğrenin ve pratik yapın:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna veya telegram grubuna katılın ya da Twitter’da bizi takip edin 🐦 @hacktricks_live.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.
Neden race penceresini genişletmek önemli
Birçok Windows kernel LPE’si klasik şablonu check_state(); NtOpenX("name"); privileged_action(); izler. Modern donanımda soğuk bir NtOpenEvent/NtOpenSection kısa bir ismi ~2 µs civarında çözer; bu da güvenli işlem gerçekleşmeden önce kontrol edilen durumu değiştirmek için neredeyse hiç zaman bırakmaz. Adım 2’de Object Manager Namespace (OMNS) aramasını kasıtlı olarak onlarca mikrosaniye sürecek şekilde yavaşlatmak, saldırganın binlerce denemeye gerek duymadan aksi takdirde kararsız olan race’leri tutarlı şekilde kazanmak için yeterli zamanı kazanmasını sağlar.
Object Manager lookup içyapısı kısaca
- OMNS structure –
\BaseNamedObjects\Foogibi isimler dizin-dizin çözülür. Her bileşen kernel’in bir Object Directory bulmasına/açmasına ve Unicode dizelerini karşılaştırmasına neden olur. Sembolik linkler (ör. sürücü harfleri) yol boyunca takip edilebilir. - UNICODE_STRING limit – OM yolları
UNICODE_STRINGiçinde taşınır ve bununLengthalanı 16-bit bir değerdir. Mutlak limit 65 535 byte (32 767 UTF-16 kod noktasıdır).\BaseNamedObjects\gibi öneklerle, saldırgan hâlâ ≈32 000 karakter üzerinde kontrol sahibidir. - Attacker prerequisites – Her kullanıcı
\BaseNamedObjectsgibi yazılabilir dizinlerin altına nesneler oluşturabilir. Zafiyetli kod içerideki bir ismi kullandığında veya oraya yönlenen bir sembolik linki takip ettiğinde, saldırgan özel ayrıcalık gerektirmeden lookup performansını kontrol eder.
Slowdown primitive #1 – Tek maksimum bileşen
Bir bileşeni çözmenin maliyeti uzunluğuyla yaklaşık olarak lineerdir çünkü kernel ebeveyn dizindeki her girişe karşı Unicode karşılaştırması yapmak zorundadır. 32 kB uzunluğunda bir isimle bir event oluşturmak, NtOpenEvent gecikmesini Windows 11 24H2 (Snapdragon X Elite testbed) üzerinde ~2 µs’den ~35 µs’ye hemen artırır.
std::wstring path;
while (path.size() <= 32000) {
auto result = RunTest(L"\\BaseNamedObjects\\A" + path, 1000);
printf("%zu,%f\n", path.size(), result);
path += std::wstring(500, 'A');
}
Pratik notlar
- İsimlendirilmiş herhangi bir kernel nesnesi (events, sections, semaphores…) kullanarak uzunluk sınırına ulaşabilirsiniz.
- Symbolic links veya reparse points, kısa bir “victim” adını bu dev bileşene yönlendirebilir; böylece yavaşlama şeffaf şekilde uygulanır.
- Çünkü her şey user-writable namespaces içinde bulunduğundan, payload standart bir user integrity level’dan çalışır.
Slowdown primitive #2 – Derin özyinelemeli dizinler
Daha agresif bir varyant, binlerce dizinden oluşan bir zincir (\BaseNamedObjects\A\A\...\X) ayırır. Her atlama dizin çözümleme mantığını (ACL checks, hash lookups, reference counting) tetikler; bu yüzden seviye başına gecikme tek bir string karşılaştırmasından daha yüksektir. Yaklaşık 16 000 seviye ile (aynı UNICODE_STRING boyutu ile sınırlı), ampirik zamanlamalar uzun tek bileşenlerle elde edilen 35 µs eşiğini aşar.
ScopedHandle base_dir = OpenDirectory(L"\\BaseNamedObjects");
HANDLE last_dir = base_dir.get();
std::vector<ScopedHandle> dirs;
for (int i = 0; i < 16000; i++) {
dirs.emplace_back(CreateDirectory(L"A", last_dir));
last_dir = dirs.back().get();
if ((i % 500) == 0) {
auto result = RunTest(GetName(last_dir) + L"\\X", iterations);
printf("%d,%f\n", i + 1, result);
}
}
İpuçları:
- Parent dizini tekrar eden öğeleri reddetmeye başlıyorsa, seviye başına karakteri (
A/B/C/...) değiştirin. - İstismar sonrası ad alanını kirletmemek için zinciri temiz şekilde silebilmek adına bir handle dizisi tutun.
Slowdown primitive #3 – Shadow directories, hash collisions & symlink reparses (minutes instead of microseconds)
Object directories destekler shadow directories (fallback lookups) ve girişler için kova tabanlı hash tablolarını. Her ikisini ve 64-bileşenli symbolic-link reparse limitini kötüye kullanarak, UNICODE_STRING uzunluğunu aşmadan yavaşlamayı katlayabilirsiniz:
\BaseNamedObjectsaltında iki dizin oluşturun, örneğinA(shadow) veA\A(target). İkincisini birincisini shadow directory olarak kullanarak oluşturun (NtCreateDirectoryObjectEx), böyleceAiçindeki eksik aramalarA\A’ya düşer.- Her dizini aynı hash kovasına düşen binlerce çakışan isim ile doldurun (ör. son basamakları değiştirirken aynı
RtlHashUnicodeStringdeğerini koruyarak). Aramalar artık tek bir dizin içinde O(n) lineer taramalara dönüşür. - Yaklaşık ~63 uzunluğunda bir object manager symbolic links zinciri oluşturun; bunlar tekrar tekrar uzun
A\A\…sonekine reparse olur ve reparse bütçesini tüketir. Her reparse, ayrıştırmayı baştan başlatarak çakışma maliyetini katlar. - Son bileşenin (
...\\0) aranması, her dizinde 16 000 çakışma olduğunda Windows 11’de artık dakikalar sürer; bu da tek seferlik kernel LPE’leri için pratikte garanti bir yarış kazanımı sağlar.
ScopedHandle shadow = CreateDirectory(L"\\BaseNamedObjects\\A");
ScopedHandle target = CreateDirectoryEx(L"A", shadow.get(), shadow.get());
CreateCollidingEntries(shadow, 16000, dirs);
CreateCollidingEntries(target, 16000, dirs);
CreateSymlinkChain(shadow, LongSuffix(L"\\A", 16000), 63);
printf("%f\n", RunTest(LongSuffix(L"\\A", 16000) + L"\\0", 1));
Neden önemli: Dakikalar süren bir yavaşlama, one-shot race-based LPE’leri deterministik exploit’lere dönüştürür.
2025 retest notes & ready-made tooling
- James Forshaw, Windows 11 24H2 (ARM64) üzerinde güncellenmiş zamanlamalarla tekniği yeniden yayımladı. Baseline open’lar ~2 µs civarında kalıyor; 32 kB bir bileşen bunu ~35 µs’ye çıkarıyor ve shadow-dir + collision + 63-reparse zincirleri hâlâ ~3 dakika seviyelerine ulaşıyor; bu, primitive’lerin mevcut build’lerde yaşadığını doğruluyor. Source code ve perf harness yenilenmiş Project Zero gönderisinde mevcut.
- Kurulumu halka açık
symboliclink-testing-toolspaketini kullanarak scriptleyebilirsiniz: shadow/hedef çiftini spawn etmek içinCreateObjectDirectory.exeve 63-hop zincirini çıkarmak için döngü içindeNativeSymlink.exe. Bu, elle yazılmışNtCreate*wrapper’larından kaçınır ve ACL’leri tutarlı tutar.
Yarış penceresini ölçme
Hedef donanımda pencerenin ne kadar genişlediğini ölçmek için exploit’inizin içine hızlı bir harness gömün. Aşağıdaki snippet hedef objeyi iterations kere açar ve QueryPerformanceCounter kullanarak her açma başına ortalama maliyeti döndürür.
static double RunTest(const std::wstring name, int iterations,
std::wstring create_name = L"", HANDLE root = nullptr) {
if (create_name.empty()) {
create_name = name;
}
ScopedHandle event_handle = CreateEvent(create_name, root);
ObjectAttributes obja(name);
std::vector<ScopedHandle> handles;
Timer timer;
for (int i = 0; i < iterations; ++i) {
HANDLE open_handle;
Check(NtOpenEvent(&open_handle, MAXIMUM_ALLOWED, &obja));
handles.emplace_back(open_handle);
}
return timer.GetTime(iterations);
}
Sonuçlar doğrudan sizin race orchestration stratejinize yansır (ör. kaç worker thread gerektiği, sleep aralıkları, paylaşılan durumu ne kadar erken flip etmeniz gerektiği).
İstismar iş akışı
- Zafiyetli open çağrısını bulun – Semboller, ETW, hypervisor tracing veya reversing aracılığıyla kernel yolunu izleyin; saldırgan tarafından kontrol edilen bir ismi veya kullanıcı tarafından yazılabilir bir dizindeki sembolik link’i dolaşan bir
NtOpen*/ObOpenObjectByNameçağrısı bulana kadar. - O ismi bir slow path ile değiştirin
\BaseNamedObjectsaltında (veya başka bir yazılabilir OM root altında) uzun bir bileşen ya da dizin zinciri oluşturun.- Kernel’in beklediği ismin artık slow path’e çözülmesini sağlayacak bir sembolik link oluşturun. Hedefi ellemeden, zafiyetli sürücünün dizin aramasını kendi yapınıza yönlendirebilirsiniz.
- Race’i tetikleyin
- Thread A (kurban) zafiyetli kodu çalıştırır ve slow lookup içinde bloklanır.
- Thread B (saldırgan) Thread A meşgulken guarded state’i değiştirir (ör. bir file handle takas eder, sembolik link’i yeniden yazar, object security’yi değiştirir).
- Thread A devam edip ayrıcalıklı işlemi gerçekleştirdiğinde, eski durumu görür ve saldırgan kontrollü işlemi yapar.
- Temizlik – Şüpheli artefakt bırakmamak veya meşru IPC kullanıcılarını bozmemek için dizin zincirini ve sembolik linkleri silin.
Operasyonel hususlar
- Primitifleri birleştirin –
UNICODE_STRINGboyutunu tüketene dek, dizin zincirinde seviye başına uzun bir isim kullanarak daha yüksek gecikme elde edebilirsiniz. - Tek-seferlik (one-shot) buglar – Genişleyen pencere (mikrosaniyelerden dakikalara) CPU affinity pinning veya hypervisor-assisted preemption ile eşleştirildiğinde “single trigger” bugları gerçekçi kılar.
- Yan etkiler – Yavaşlama yalnızca kötü amaçlı yolu etkiler, bu yüzden genel sistem performansı etkilenmez; savunucular ancak namespace büyümesini izlerlerse fark ederler.
- Temizlik – Oluşturduğunuz her dizin/objeye ait handle’ları saklayın ki sonra
NtMakeTemporaryObject/NtCloseçağırabilesiniz. Aksi halde sınırı olmayan dizin zincirleri yeniden başlatmalar arasında kalıcı olabilir. - Dosya sistemi yarışları – Eğer zafiyetli yol nihayetinde NTFS üzerinden çözümleniyorsa, OM slowdown çalışırken backing file üzerinde bir Oplock (ör. aynı toolkit’ten
SetOpLock.exe) istiflemesi yaparak tüketiciyi ek milisaniyelerce dondurabilirsiniz; OM grafını değiştirmeden.
Savunma notları
- Named object’lara dayanan kernel kodu, open’dan sonra güvenlik açısından hassas durumu yeniden doğrulamalı veya kontrol öncesi bir referans almalıdır (TOCTOU boşluğunu kapatmak için).
- User-controlled isimleri dereference etmeden önce OM yol derinliği/uzunluğu için üst sınırlar uygulayın. Aşırı uzun isimleri reddetmek saldırganları mikro-saniye penceresine geri zorlar.
- Nesne yöneticisi namespace büyümesini (ETW
Microsoft-Windows-Kernel-Object) enstrümante ederek\BaseNamedObjectsaltında binlerce bileşenli şüpheli zincirleri tespit edin.
References
- Project Zero – Windows Exploitation Techniques: Winning Race Conditions with Path Lookups
- googleprojectzero/symboliclink-testing-tools
Tip
AWS Hacking’i öğrenin ve pratik yapın:
HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın:HackTricks Training GCP Red Team Expert (GRTE)
Azure Hacking’i öğrenin ve pratik yapın:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna veya telegram grubuna katılın ya da Twitter’da bizi takip edin 🐦 @hacktricks_live.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.


