netfilter / nf_tables hardened exploitation¶
"Flipping Pages": bir CVE-2024-1086 nf_tables double-free'sini slab'ın dışına ve page allocator'ın içine escalate edin, bir userland page'e bir page table'ı double-allocate edin ve slab freelist hardening'ini hiç yenmeden SMAP/SMEP/KASLR/CFI'dan bağımsız data-only bir arbitrary physical read/write kazanın.
Mechanism¶
Note
Modern kernel'ler slab'ı ağır biçimde hardene eder —
CONFIG_SLAB_FREELIST_HARDENED freelist pointer'larını XOR'lar ve valide eder
(freelist_pointer_corrupted()), CONFIG_SLAB_FREELIST_RANDOM layout'u
randomize eder, hardened usercopy kopyaları bounds-check eder ve CFI indirect
call'ları kısıtlar. Notselwyn'in içgörüsü, slab'la savaşmayı bırakmak ve
bug'ı, bu metadata hardening'inin hiçbiri olmayan buddy/page allocator
üzerinde bir primitive'e çevirmektir.
Root cause (CVE-2024-1086): nft_verdict_init(), pozitif bir değeri bir drop
error olarak kabul eder. NF_DROP böyle bir error ile döndürüldüğünde,
nf_hook_slow() skb'yi free eder (kfree_skb_reason()), ama
NF_DROP_GETERR() üst bit'leri çıkarır ve NF_ACCEPT'e benzeyen bir değer
döndürür, böylece caller processing'e devam eder ve aynı skb'yi tekrar free
eder — bir double-free (örneğin crafted verdict 0xffff0000).
Escalation chain'i iki allocator invariant'ına dayanır:
- Bir slab object'in double-free'i, onun backing page'inin double-free'sine launder edilebilir. Slab'ın refcount/occupancy'sini kontrol ederek ikinci free'yi meşru bir free gibi gösterirsiniz ("allocate the page again before the 2nd free, as the free will look like a non-double-free free considering there is an actual object in the page"), böylece detection logic'i ateşlemez.
- Buddy allocator, free edilen page'i sonra ne isterse ona geri verir,
page-table allocation'ları dahil. Page table'lar (PMD/PTE), kmalloc değil,
alloc_pagestarafından allocate edilir, böylece aynı physical page aynı anda hem kontrollü bir data page hem de canlı bir page table olabilir — "Dirty Pagedirectory" / page-table-as-data primitive'i.
Kritik olarak, PTE'ler bir PMD içinde physical address ile referans verilir. SMAP yalnızca virtual access mode'u inceler; "when a PTE entry in a PMD is a userland page, it will not be detected by SMAP." MMU'nun bir page table olarak dolaştığı bir page'e PTE-shaped qword'ler yazmak böylece arbitrary physical frame'leri process'e map'ler — SMAP/SMEP'i tamamen atlayan data-only bir R/W.
Walkthrough¶
Exploit data-only ve version-independent'tır; aşağıdaki adımlar pwning.tech writeup'ını yansıtır (başarı oranı %99.4, n=1000, v6.4.16 üzerinde).
1. Double-free'i tetikleyin. Verdict'i, NF_DROP_GETERR() accept-benzeri bir
değer döndürsün diye pozitif bir error'lu bir drop'u encode eden bir nf_tables
rule ekleyin:
verdict = NF_DROP | (drop_error << 16) ; e.g. 0xffff0000
=> nf_hook_slow(): kfree_skb_reason(skb) (1st free)
=> caller sees NF_ACCEPT-like, keeps using/freeing skb (2nd free)
2. Freelist corruption'ı maskeleyin. İlk free'den hemen sonra, temiz skb
object'leri allocate edin, corrupt edilen freelist pointer'ını gizlemek için onları
free edin, sonra orijinal double-free edilmiş object'i reallocate edin. Bu, o
cache'ten bir sonraki allocation sırasında freelist_pointer_corrupted()'ın
poison'lanmış next-pointer'a takılmasını engeller.
3. Slab → page boundary. Exploit, skb head'lerinin (kmalloc) ve page-table
page'lerinin (alloc_pages) buluştuğu slab-to-buddy boundary'sinde çalışır,
stability için cross-cache attack'lerden kasıtlı olarak kaçınır. Per-CPU page
(PCP) freelist'lerini drain eder ve bir refill zorlar:
PCP draining:
free order-4 pages to the buddy freelists
trigger PCP refill -> 16 order-0 pages carved from the just-freed order-4 region
=> the double-freed page is now reissued as individual order-0 pages,
reliably collidable with PTE/PMD allocations
4. Kontrollü bir page üzerine bir page table'ı double-allocate edin. Bir PMD page ve bir PTE page'i, hâlâ userland'de map'li/kontrollü bir page ile aynı physical address'e resolve olacak şekilde alın.
map a large anon range and fault it in to force PMD/PTE allocation
arrange one PT page == a userland data page (same physical frame)
5. Dirty Pagedirectory R/W. PTE page'i user data olarak da görünürken, PTE-format entry'leri (physaddr | flags) yazın ve onları ikinci bir VMA üzerinden dereference edin:
write PTE values for userland pages in VMA 0x40000000 - 0x80000000
read/write the corresponding userland pages in VMA 0x8000000000 - 0x10000000000
=> arbitrary physical read/write (SMAP-immune: PTEs referenced by physaddr)
6. Data-only privesc. Physical memory'yi kernel data pattern'leri için tarayın
ve modprobe_path'i (ya da cred'leri) overwrite edin — bkz.
modprobe path overwrite. Physical-KASLR, 16 MiB'lık
CONFIG_PHYSICAL_START hizalaması üzerinden brute-force edilir ve çalışan kernel
get-sig ile fingerprint'lenir, böylece per-version offset gerekmez; exploit disk'e
hiç dokunmaz.
Warning
Tüm yaklaşım, page-level double-free'nin asla bir double-free olarak saptanmamasına bağlıdır: launder-allocation'larının sırası (adım 2) ve PCP drain hacmi (adım 3) timing/occupancy'ye duyarlıdır. Bir yanlış sayım, poison'lanmış bir freelist bırakır ve sessizce başarılı olmak yerine bir sonraki allocation'da panic eder.
Bu, nf_tables CVE-2024-1086 chain'inin hardened-bypass kilit taşıdır; bug'ın kendisi için nf-tables flipping-pages double-free'e, ve page-table primitive'i izole halde için dirty pagetable / page-table data-only attack ve page-level cross-cache attack'e bakın.
Detection¶
- nf_tables rule'ları yüklemek, (muhtemelen user) bir namespace'te
CAP_NET_ADMINgerektirir — unprivilegedunshare(CLONE_NEWUSER|CLONE_NEWNET)'i takip eden netlinkNFT_MSG_NEW*trafiğini izleyin. - KFENCE / KASAN /
slab_debug, double-free'yi ilk free'de slab seviyesinde yakalar. - Ani order-4 free'leri takip eden order-0 page-table allocation patlamaları, PCP-drain imzasıdır.
Mitigation¶
- CVE-2024-1086 fix'ini uygulayın (
nft_verdict_init'te verdict sanitization). - nf_tables'e giden unprivileged path'i kaldırmak için
kernel.unprivileged_userns_clone=0set edin / user namespace'leri kısıtlayın; kullanılmıyorsanf_tablesmodülünü blocklist'leyin. CONFIG_RANDOM_KMALLOC_CACHES,CONFIG_SLAB_VIRTUAL/cache isolation veinit_on_freemaliyeti artırır; ancak page-level teknik slab hardening'ini kasıtlı olarak atlar, yani onu fiilen körelten page-allocator seviyesindeki savunmalardır (örneğin SLAB_VIRTUAL, page-table protection).