KASLR bruteforce¶
Kernel base'i düşük entropy'ye sahip olduğunda (x86-64'te ≈8–9 bit) ve başarısız bir tahmin sistemi crash etmediğinde, bir exploit'i her aday base'e karşı tekrar tekrar denemek — veya ortaya çıkan oops'tan sağ çıkmak — KASLR'ı bir information leak yerine tüketme yoluyla yener.
Mechanism¶
Note
Kernel ASLR, kernel image'inin fiziksel/virtual load adresini boot'ta bir kez randomize eder. x86-64'te image, üstteki 1 GiB penceresinde 0xffffffff80000000–0xffffffffc0000000, 2 MiB-hizalı olarak map'lenir — yani yalnızca 512 olası slot vardır (her 2 MiB için bir tane), yani ~9 bit entropy (LWN'in erken patch'i "e820 map'e bağlı olarak en iyi ihtimalle sekiz bit" demişti). KASLR'ın güvenliği, attacker'ın o birkaç yüz slot'tan hangisinin canlı olduğunu bilmemesine dayanır. Brute force tam olarak o varsayıma saldırır: bu kadar küçük bir arama uzayıyla her slot'u denemek hesaplama açısından önemsizdir — yoldaki tek şey yanlış bir tahminin maliyetidir.
Yanlış bir tahmin, amaçlanan kernel object'i olmayan bir adresi dereference eder. Bunun sağ kalınabilir olup olmaması brute force'un işe yarayıp yaramayacağını belirler:
- Crash-on-miss (varsayılan hardened): "İlgili adresi bulmaya yönelik bir brute force girişimi muhtemelen bir kernel oops'uyla sonuçlanır; bu, hatanın doğasına ve
panic_on_oopssysctl'inin değerine bağlı olarak bir panic'e de yol açabilir."panic_on_oops=1ile (veya kurtarılamaz state'i bozan herhangi bir miss ile) makine yeniden başlar — KASLR yeniden randomize eder — ve brute force "yüksek kernel panic oranı nedeniyle neredeyse uygulanabilir değildir." - Survivable-miss (exploit edilebilir durum): Yanlış bir tahmin yalnızca current task'ı öldürürse (panic yapmayan bir oops), attacker basitçe bir sonraki adaya karşı
fork()'lar/yeniden dener. ≤512 slot ile ortalama ~256 deneme base'i bulur. Bu, CTF kernel'larında (panic_on_oops=0) ve faulting path'in process başına temiz şekilde unwind ettiği gerçek bug'larda yaygındır.
Yani saldırılan invariant düşük entropy + sağ kalınabilir hatadır. İkisinden birini kaldır (daha fazla entropy veya miss'te ölümcül) ve brute force çöker.
Walkthrough¶
512 aday base'i numaralandır ve biri fault etmeyene kadar her birini probe et.
#include <stdint.h>
#define KBASE_MIN 0xffffffff80000000UL
#define KBASE_MAX 0xffffffffc0000000UL
#define KBASE_ALIGN 0x200000UL /* 2 MiB */
#define SLOTS ((KBASE_MAX - KBASE_MIN) / KBASE_ALIGN) /* 512 */
/* try_base() runs the exploit assuming this kernel base.
Returns 0 if the guess survived (likely correct), nonzero on miss. */
for (uint64_t i = 0; i < SLOTS; i++) {
uint64_t base = KBASE_MIN + i * KBASE_ALIGN;
pid_t pid = fork();
if (pid == 0) {
_exit(try_base(base)); /* child absorbs the oops/SIGKILL */
}
int st; waitpid(pid, &st, 0);
if (WIFEXITED(st) && WEXITSTATUS(st) == 0) {
printf("[+] kernel base = %#lx\n", base);
break;
}
}
Her deneme için fork yapmak kilit numaradır: sağ kalınabilir bir oops yalnızca child'ı öldürür, parent bir sonraki slot'a geçer. Bir hedefte arama uzayını doğrula:
# Real base (root only) — used to validate a brute-forcer offline:
$ sudo grep ' _text' /proc/kallsyms
ffffffff9b000000 T _text # observe it is 2 MiB-aligned within the window
Neden milyonlarca değil ~512 deneme
Aynı yaklaşımın umutsuz olduğu userspace ASLR (genellikle 28+ bit) ile karşılaştır.Warning
Brute force gürültülü ve kırılgandır. panic_on_oops=1 ise (birçok dağıtımda production varsayılanı ve Android/CrOS normu) tek bir miss kutuyu yeniden başlatır ve yeniden randomize eder — araman her boot'ta yeni entropy ile sıfırdan başlar, başarıyı fiilen imkânsız kılar. Ayrıca bir oops/dmesg entry'leri izi bırakır. Bir gerçek info leak varsa onu tercih et; brute force'u düşük-entropy'li, oops'tan sağ kalınabilir hedefler için sakla (birçok CTF image'i, panic_on_oops=0). Not: KASLR brute force ve side channel KASLR kırma (prefetch timing, EntryBleed) farklı tekniklerdir — ikincisi base'i tahmin-edip-fault-etmeden okur.
Detection¶
- Aynı UID'den sıkı bir döngüde
dmesg'de tekrarlanan oops/general protection fault/BUG:entry'leri güçlü bir sinyaldir. - Her biri artan adreslere karşı aynı syscall'ı çıkaran yüzlerce kısa-ömürlü child'ı
fork()'layan bir process EDR / audit için anormaldir. - Boot-time
panic_on_oopsve oops-oranı izleme (LWN makalesi "sistem izleme tekrarlanan oops'ları da yakalayabilir" der).
Mitigation¶
panic_on_oops=1(veoops=panic) set et ki her miss ölümcül olsun — ucuz survivable-miss'i yeniden randomize eden bir reboot'a çevirir.CONFIG_PANIC_ON_OOPS/ hardened config'ler; tekrarlanan oops'ları tetikleyen process'leri rate-limit'le veya öldür.- Entropy'yi artır: FGKASLR / function-granular randomization ve daha büyük KASLR pencereleri per-slot isabet olasılığını küçültür.
- Yapısal fix, sağ kalınabilir yeniden denemeleri reddetmektir — oops'tan sağ kalınabilir bir miss olmadan, düşük entropy tek başına brute force için yeterli değildir.