- Linux çekirdeğindeki
nf_tablesiçin CVE-2024-1086, Netfilter verdict girdi doğrulama hatası nedeniylesk_buffdouble-free durumu oluşturuyor ve koşullar uygunsa yerel yetki yükseltmeye yol açabiliyor - Saldırı akışı,
NF_DROPişleme sırasında serbest bırakılan skb’ninNF_ACCEPTgibi işlemeye devam etmesini sağlayarak aynı nesnenin sonraki yolda yeniden serbest bırakılması üzerine kurulu - PoC; KernelCTF mitigation, Debian, Ubuntu ve vanilla çekirdeklerde doğrulandı ve en az v5.14.21~v6.6.14 aralığı kconfig’e bağlı olarak etkileniyor; düzeltme 2024 Şubat’ta stable branch’lere dağıtıldı
- Temel teknik Dirty Pagedirectory; PTE ve PMD sayfalarını aynı fiziksel sayfaya çift tahsis ederek, yalnızca kullanıcı alanı okuma/yazmasıyla rastgele fiziksel adreslere erişen veri odaklı bir KSMA yöntemi
- Fiziksel KASLR keşfi,
modprobe_pathatlatması, fileless execution ve namespace’ten çıkış için dosya tanımlayıcı zincirleme de birleştirilerek, çekirdek bellek yönetimi ile ağ alt sistemini birlikte hedefleyen pratik bir LPE örneği ortaya çıkıyor
Açığın koşulları ve etki alanı
nf_tableshatası CVE-2024-1086 olarak kaydedildi; Linux çekirdeği Netfilter verdict işleme yolunda pozitif drop error değerlerine izin veren girdi doğrulama hatası temel sorun- Exploit için şu koşullar gerekli
nf_tablesetkin olmalı- Ayrıcalıksız kullanıcı namespace etkin olmalı
- Debian ve Ubuntu gibi büyük dağıtımlarda bu ayarın varsayılan olarak açık olması saldırının ön koşulu
- Testlere göre stable branch
linux-5.15.y,linux-6.1.y,linux-6.6.yetkileniyor velinux-6.7.1de muhtemelen etkilenebilir - Hata düzeltmesi 2024 Şubat’ta stable branch’lere dağıtıldı
- PoC kaynak kodu CVE-2024-1086 PoC repository adresinde yayımlandı
Double-free’nin oluştuğu kod akışı
- Netfilter verdict, paketin drop edileceğini, kabul edileceğini ya da queue’ya gönderileceğini belirleyen değer
- Açığa yol açan akış,
nft_verdict_init()fonksiyonunun kullanıcıdan gelen verdict değerini yeterince kısıtlamaması veNF_DROPgibi görünen ama drop error değeri pozitif olan bir değerin ayarlanabilmesiyle başlıyor nf_hook_slow(), verdict’in düşük bitlerine bakıp bunuNF_DROPolarak yorumladığındakfree_skb_reason()ile skb’yi önce serbest bırakıyor- Sonrasında
NF_DROP_GETERR()sonucuNF_ACCEPTile eşleşen bir değer döndürürse, çağıran taraf paketin kabul edildiğini sanıp işlemeye devam ediyor - Bunun sonucunda daha önce serbest bırakılmış skb sonraki akışta tekrar serbest bırakılıyor ve double-free primitive oluşuyor
Bozulan nesneler ve paket işleme yöntemi
- Double-free,
skbuff_head_cacheiçindekistruct sk_buffilesk_buff->headnesnelerini etkiliyor sk_buff->headgerçek paket içeriğini taşıyor ve IPv4 paket boyutuna görekmalloc-256ile buddy allocator’ın order 4 sayfaları arasında tahsis edilebiliyor- PoC, slab allocator yerine buddy allocator yoluna girmek için büyük IP paketleri kullanacak şekilde tasarlandı
- IPv4 fragmentation queue, skb’nin ikinci kez serbest bırakılmasını geciktirmek ya da istenen anda tetiklemek için kullanılıyor
- Paket yolunda bozulmuş skb alanları kullanılırsa kernel panic oluşabileceğinden, TCP/UDP stack’lerinden kaçınılıp belirli IP fragment hata yolları kullanılıyor
Test kapsamı ve başarı oranı
- Vanilla çekirdek, KernelCTF, Debian ve Ubuntu ortamlarında çeşitli çekirdek sürümleri ve yapılandırmalar test edildi
- Başarılı örnekler arasında şu ortamlar yer alıyor
- Linux v5.14.21, v5.15.148, v5.16.20, v5.17.15, v5.18.19, v5.19.17, v6.0.19
- KernelCTF Mitigation v3 altında Linux v6.1.55
- Debian Bookworm 6.1.0-17 altında Linux v6.1.69
- KernelCTF LTS altında Linux v6.1.72
- Ubuntu Jammy v6.2.0-37
- Linux v6.2.16, v6.3.13
- Başarısız örnekler arasında v5.4.270, v5.10.209, v6.4.16, Ubuntu Jammy v6.5.0-15, v6.5.13, v6.6.14, v6.7.1 bulunuyor
- v6.4.0 sonrasındaki bazı başarısızlıklar,
CONFIG_INIT_ON_ALLOC_DEFAULT_ON=ynedeniyle bad_page() tespiti ile ilişkilendirildi - v6.4.16 ortamında başarı oranı %99,4’tü; bazı durumlarda %93,0’a düştü ve örneklem sayısı her ikisinde de n=1000’di
Düzeltme yöntemi
- İlk önerilen düzeltme, Netfilter stack’in ortasında breaking change yaratabilirdi
- Netfilter maintainer tarafından yapılan düzeltme, kullanıcı girdisinden gelen verdict değerlerini API seviyesinde daha sıkı kısıtlıyor
- Patch, userland girdilerinde DROP/QUEUE verdict parametrelerini reddediyor
- CVE açıklamasına göre
nft_verdict_init(), hook verdict içindeki drop error için pozitif değerlere izin veriyordu venf_hook_slow()daNF_DROPileNF_ACCEPTçakıştığında double free oluşturabiliyordu - Düzeltme patch’i [PATCH nf] netfilter: nf_tables: reject QUEUE/DROP verdict parameters. bağlantısında görülebilir
Dirty Pagedirectory ve rastgele fiziksel bellek erişimi
- PoC’nin merkezindeki teknik Dirty Pagedirectory; mevcut Dirty Pagetable tekniğinin bir varyantı
- Temel fikir, PTE sayfası ile PMD sayfasını aynı fiziksel sayfaya çift tahsis etmek
- Bir sanal adres alanına PTE değeri gibi görünen veri yazıldığında, başka bir sanal adres alanı bunu sayfa tablosu girdisi olarak yorumlayıp belirtilen fiziksel sayfayı map ediyor
- Bu yöntem, yalnızca kullanıcı alanı adres okuma/yazmasıyla rastgele fiziksel adresleri ve izin bayraklarını ayarlayarak erişim sağlayan bir kernel-space mirroring attack olarak çalışıyor
- Virtual KASLR, KPTI, SMAP, SMEP ve
CONFIG_STATIC_USERMODEHELPERgibi önlemleri atlatmak için kullanılıyor
Sayfa tahsis ediciyi manipüle etme
- Çekirdek sayfa tahsisi süreçlerinde slab allocator, buddy allocator ve PCP allocator rol oynuyor
- skb head büyük boyutlarda buddy allocator’ın order 4 sayfalarını kullanırken, PTE/PMD sayfaları order 0 sayfaları kullanıyor; bu yüzden doğrudan hizalanmıyorlar
- Bunu çözmek için iki farklı page conversion yöntemi kullanılıyor
- PCP list draining: order 4 sayfaları buddy freelist’e koyup PCP order 0 freelist’ini boşaltarak buddy allocator’ın yeniden order 0 sayfalarla doldurmasını sağlamak
- Race condition: ikinci free sırasında yarış durumundan yararlanıp order 4 sayfayı order 0 freelist’e sokmak
- PCP list draining daha basit, daha kararlı ve daha hızlı yöntem
- Race condition yaklaşımı ilk KernelCTF exploit’inde kullanıldı ancak QEMU VM gibi serial TTY gecikmesinin yüksek olduğu ortamlara bağımlı olduğundan artık geçersiz sayılıyor
KernelCTF mitigation atlatması
- KernelCTF mitigation ortamında aktif olarak aşılması gereken başlıca önlem,
sk_bufffreelist corruption check idi skbuff_head_cache->offset == 0x70olduğundan freelist next pointer,skb->lenile çakışıyor- İlk skb serbest bırakıldıktan sonra
skb->len, freelist pointer’ın bir kısmıyla üzerine yazılıyor ve ardından paket parse edilirken bu değer değişirse corruption check tetiklenebiliyor - Tespiti aşmak için, bozulmuş skb’nin üstüne normal bir skb daha serbest bırakılarak freelist head’in üzerine yazılıyor
- KernelCTF geliştiricileri, free anında da freelist head next pointer’ını denetlemenin bu atlatmayı hafifletebileceğini düşünüyor
TLB flush ve fiziksel KASLR keşfi
- Dirty Pagedirectory ile sayfa tabloları beklenmedik biçimde değiştirildiğinde CPU’nun TLB önbelleğinde eski dönüşüm bilgileri kalabiliyor
- Kullanıcı alanında
fork()sonrası çocuğunmunmap()yapıp uykuya geçmesiyle TLB flush gerçekleştiriliyor - Bu yöntemin AMD CPU’larda ve QEMU VM’de %100 çalıştığı doğrulandı
- Fiziksel KASLR keşfi, çekirdeğin fiziksel base adresinin
CONFIG_PHYSICAL_STARTveyaCONFIG_PHYSICAL_ALIGNile hizalı olmasından yararlanarak arama alanını daraltıyor - 8GiB fiziksel bellek ve 16MiB hizalama varsayılırsa 512 aday kalıyor; get-sig betiğiyle çekirdek base signature’ı üretilip doğrulanıyor
modprobe_path ve root shell elde etme
- Rastgele fiziksel bellek okuma/yazma elde edildikten sonra PoC, çekirdek base sonrasındaki yaklaşık 80MiB aralığı tarayarak
modprobe_pathdeğerini buluyor - Genel yapılandırmalarda
"/sbin/modprobe"ve null padding deseni aranıyor; ardından/proc/sys/kernel/modprobeyansımasına bakılarak gerçek değişken doğrulanıyor CONFIG_STATIC_USERMODEHELPERetkinse hedef olarak"/sbin/usermode-helper"dizgesi kullanılıyor- Root shell almak için
modprobe_pathveya static usermode helper dizgesi,/proc/<pid>/fd/<fd>biçimindeki memfd yolu ile üzerine yazılıyor - Yetki yükseltme betiği, exploit’in dosya tanımlayıcılarını shell’in stdin/stdout’una bağlayacak şekilde tasarlandığından hem yerel terminalde hem de reverse shell’de çalışıyor
Fileless execution ve PoC yapısı
- PoC, diske dosya yazmayan fileless execution desteği sunuyor
- Hedefte Perl varsa
memfd_create()kullanılarak exploit ikilisi belleğe yüklenip/proc/$$/fd/<fd>üzerinden çalıştırılabiliyor - Derleme bağımlılıkları
libnftnl-devvelibmnl-dev - KernelCTF için statik build, glibc statik linkleme ve QEMU AVX512 opcode sorunlarından kaçınmak amacıyla
musl-gccile yapıldı - Exploit kaynak kodu birden çok dosyaya ayrılmış durumda ve bağımsız çalıştırılabilir ikili hedeflendiğinden, hata durumlarında error code döndürmek yerine crash/exit yaklaşımı seçilmiş
Kararlılık ve sınırlamalar
- Exploit sürecinin pagetable durumu kararsız hale gelebileceğinden, başarı ya da başarısızlık sonrasında child process sonlandırılmayıp sleep durumunda bırakılarak çekirdekteki kararsızlık azaltılıyor
- Ağ etkinliği, skb freelist üzerinde gürültü oluşturabildiği için kararlılığı etkileyebiliyor
- SSH veya reverse shell ortamlarında, double-free anı civarında stdout çıktısı azaltılarak ağ kaynaklı skb tahsis/serbest bırakmaları en aza indiriliyor
- Bazı donanım testlerinde sistem birkaç saniye sonra çöktü; WiFi frame’lerinin de skb kullandığı düşünüldüğünden WiFi etkinliğinin etkili olmuş olabileceği belirtiliyor
- WiFi adaptörü BIOS’ta devre dışı bırakıldığında ilgili ortamda exploit düzgün çalışıyor
Araştırma sürecinden çıkan sonuçlar
- PoC; geniş uyumluluk, yüksek kararlılık ve gizli çalıştırma hedefleri doğrultusunda iyileştirildi
- 2 aylık geliştirme süresine ek olarak kararlılık ve uyumluluk iyileştirmeleri için 2 ay daha harcandı
- Exploit’in kendisi slab allocator davranışına büyük ölçüde bağımlı değil; IPv4 alt sistemi ve sanal bellek gibi yaygın olarak etkin özellikleri merkeze alıyor
- İlk hata ayrıcalıksız user namespace ve nftables gerektirse de Dirty Pagedirectory ve PCP draining gibi teknikler başka gerçek exploit’lerde de kullanılabilir
- Bu çalışma, Linux çekirdeğinin networking subsystem’i ile memory management subsystem’ini birlikte derinlemesine hedef alan bir örnek olarak öne çıkıyor
1 yorum
Hacker News yorumları
Bugün CVE-2024-1086 için kavram kanıtlama niteliğinde bir exploit yayımlandı; Debian ve Ubuntu gibi dağıtımlarda çalışıyor
Etkilenen sürümler Linux çekirdeği v5.14~v6.6; v6.4~v6.6 desteği ise
CONFIG_INIT_ON_ALLOC_DEFAULT_ONçekirdek ayarına bağlı olarak değişiyorBu hata 2024 Şubat'ta yamalandı, bu yüzden Linux cihazlarını güncellemek gerekiyor
https://github.com/Notselwyn/CVE-2024-1086/blob/main/src/mai...
modprobe_pathyöntemi kullanıldığı ve dosyasız yöntem yüzünden neden pid brute-force da eklendiği merak ediliyorÖrneğin çekirdek
.textbölümünü kısa bir shellcode ile yamalayıp root olmak ve namespace'ten çıkmak gibi bir yolun neden seçilmediği soruluyorYalnız, yamalı dallar
v5.15.149>,v6.1.76>,v6.6.15>hariç tutulmuşYamaya şu ifade eklenmiş: “This reverts commit e0abdadcc6e1. [...] Its not clear to me why this commit was made.”
Bu commit'in arka plan geçmişini araştıran biri olup olmadığı soruluyor
[1] https://lore.kernel.org/all/20240120215012.129529-1-fw@strle...
Eski netdev listesine bakılmış ama bir şey bulunamamış; yama doğrudan commit'i atan Pablo Neira Ayuso'ya gönderilmiş de olabilir
İlk yazar, artık kaçınılan bir isim hâline gelmiş Patrick McHardy idi; Pablo hatırlamazsa ya da e-postalarda bulamazsa, tam kullanım senaryosunun temel bir araştırmayla ortaya çıkarılması zor görünüyor
netfilter: nf_tables: accept QUEUE/DROP verdict parameters; yani kullanıcı alanınınQUEUEveDROPkararları için kuyruk numarası veya errno kodu belirleyebilmesini sağlıyorBu yazı, güvenlik yazımı açısından da çok etkileyici
Güvenlik blogu yazarken her zaman “ne kadar arka plan bilgisi ve ön bilgi varsayılmalı” sorusu zorlayıcı oluyor; erişilebilir ama aynı zamanda yazılabilir bir denge kurmak kolay değil
Hedef okuru önceden belirleyip yeterli arka plan açıklaması sunması çok iyi olmuş; her yıl karşılaştığım aday araştırmacılara rehber materyal olarak vermek için yer imlerine ekledim
Bu exploit, ayrıcalıksız kullanıcı namespace erişimine dayanıyor:
sysctl kernel.unprivileged_userns_clone = 1Debian/Ubuntu ve Arch Linux çekirdeklerinde varsayılan bu; sudo olmadan Docker komutları çalıştırmak gibi bir ihtiyacınız yoksa kapatmak daha iyi olabilir
Electron uygulamalarında veya 1Password gibi yazılımlarda kullanılan Chrome sandbox da bununla ilişkili; sandbox yardımcı ikilisi setuid programı olarak da çalışabiliyor
Proton'un da ileride kullanıcı namespace kullanmaya başlaması şaşırtıcı olmaz; bu yüzden genel masaüstü Linux'ta kapatmamak daha iyi olabilir
Sunucularda ya da özel olarak sertleştirilmiş Linux sistemlerinde ise kapatmak çoğu durumda kötü bir fikir değildir
Sorun, container'ların “öylesine çalışması” için ağ tarafında çok sayıda hack gerektirmesi ve Docker'ın temel satış vaadinin de buna yakın biçimde bu tehlikeli hack'leri sizin yerinize üstlenmesi
Sonuçta her container çözümü bu hack'leri kabul etmek zorunda kalıyor; normal namespace işlevleri erişimi azaltsa bile çekirdek, ağ hack'leri yüzünden kapıyı yeniden açmış oluyor
Ayrıcalıksız kullanıcı namespace'lerin neden varsayılan olarak açık olduğunu anlamıyorum
“Ayrıcalıksız” bir namespace içinde çalışsa bile, kullanıcılara varsayılan olarak iptables ya da mount gibi şeyleri çalıştırma yeteneği vermenin gerekçesi sorgulanıyor
Örneğin Chrome, süreç sandbox'ını uygulamak için namespace kullanır; ancak ayrıcalıksız namespace olmasa da çalışabilmesi için setuid-root bir ikili kurar
setuid-root ikilisinin kendisi bir güvenlik riski olduğundan, uzun vadede Chrome'un böyle bir ikili kurmak zorunda kalmaması daha arzu edilir
Ama bunun için ayrıcalıksız kullanıcı namespace'lerin yaygın biçimde sunulması gerekir; bu tür hatalar da o geleceği geciktiriyor
Ayrıca Chrome gibi namespace tabanlı sandbox kuran programlar genellikle seccomp da kullanır; böylece sandbox içindeki kodun namespace gibi sıra dışı çekirdek özelliklerini kullanması engellenir
Tek kullanıcılı masaüstlerinde kullanıcı ile root arasındaki ayrımı çok güçlü uygulamanın getirisi sınırlıdır ve ilginç olan çoğu şeye zaten kullanıcı hesabından erişilebilir
Buna karşılık Chrome benzeri sandbox'lar masaüstü güvenliği için kritiktir; bu yüzden tek kullanıcılı masaüstlerinde ayrıcalıksız kullanıcı namespace'leri açık tutmanın genel güvenliği artırdığı düşünülür
Çok kullanıcılı sistemler ise elbette bambaşka bir hikâye
Sadece bu tür hatalar hiç olmasaydı, ayrıcalıksız kullanıcı ad alanları harika bir güvenlik özelliği olurdu
Örneğin Flatpak çalıştırmanın, uygulama yalıtımı için ana makinedeki setuid ikililerine ihtiyaç duymaması iyi olurdu
Varsayılanların çoğu güvenli değil ve teknik bilgiyle ek sertleştirme çalışması gerektiriyor
Sorunu ortaya çıkaran commit: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/lin...
İç içe geçmiş
switch/caseiçinde varsayılan yoldareturnbulunması, ama sonrasında fall-through bekleyen yapının garip göründüğü söyleniyorhttps://lwn.net/Articles/882397/
https://bugs.launchpad.net/bugs/cve/2024-1086
Linux çekirdeğinin
netfilter: nf_tablesbileşenindeki use-after-free açığı, yerel ayrıcalık yükseltmeye imkân veriyornft_verdict_init()işlevi, hook verdict içinde drop error için pozitif değerlere izin veriyor; bunun sonucundanf_hook_slow(),NF_ACCEPTgibi görünen bir drop error ileNF_DROPişlerken bir double-free açığı oluşabiliyorf342de4e2f33e0e39165d8639387aa6c19dff660sonrasına yükseltme yapılması öneriliyorASLR gibi modern azaltma teknikleri varken bu tür exploit'lerin nasıl mümkün olduğu merak ediliyor
Üniversitede, belirli bir Ubuntu sürümünde çalıştırılacak birkaç ikili dosya verilip use-after-free veya buffer overflow gibi hataları bulup exploit etme ödevi yapmış biri, bunun gerçekten çok zor olduğunu söylüyor
Hem açığı bulmak zordu hem de o açıkla işe yarar bir şey yapan doğru shellcode'u yazmak daha da zordu
Daha zor aşamalarda ASLR, stack canary gibi azaltmalar da açıktı ve kontrollü bir öğrenci ortamında bile neredeyse imkânsız hissettiriyordu
Sonuçta 1) exploit edilebilir bir açık bulmak ve 2) programı sadece çökertmeden faydalı bir iş yapan doğru ikili payload'u üretmek gerekiyor; gerçek dünyada bunun daha da zor olması gerektiği düşünülünce bunun nasıl yapılabildiği sorgulanıyor
[0] https://web.stanford.edu/class/archive/cs/cs107/cs107.1194/a...
Başka derslerle birlikte yürüttüğü için tek bir hataya ayırabildiği süre muhtemelen birkaç saat ile birkaç gün arasındaydı
Zerodium, tipik bir Linux yerel ayrıcalık yükseltme için 50 bin dolar ödüyor; bu da yetkin exploit geliştirici maliyetiyle kabaca 200 insan-saat satın alabilecek bir miktar
Yani uzmanlar, acemi bir öğrenciden 10-100 kat daha fazla zaman harcıyor olabilir
Bunu ilk kez ahşap atölyesine giren biriyle bir marangozun, çömlekçiliğe yeni başlayan biriyle bir ustanın ya da yeni bir ressamla profesyonel bir sanatçının farkı gibi düşünmek mümkün
Üstüne bir de 10-100 kat daha fazla zaman ekleniyor
[1] https://zerodium.com/program.html
Son korumaların çoğunu aşabilen “klasik” teknikler var; bunlar yoksa da yeni saldırılar veya bypass yöntemleri çıkabiliyor
Örneğin heap korumalarını aşmak için how2heap'e bakılabilir[0]; KASLR bypass exploit örnekleri de oldu[1]; bu exploit'in ise dirty pagetable tekniğini kullandığı görülüyor[2]
Yapı, azaltmaların eklenmesi ve araştırmacıların bunları aşması arasında süren bir kedi-fare oyunu gibi işliyor
[0] https://github.com/shellphish/how2heap
[1] https://www.willsroot.io/2022/12/entrybleed.html
[2] https://pwning.tech/nftables/#452-the-technique
Böyle bir şeyi bulmak için son gruptan tek bir kişi bile yeterli
Günümüzde bu işler gerçekten zor; azaltmalar kapalı olsa bile açık bulmak ve exploit yazmak hâlâ kolay değil
Yine de bu tür açıkları arayan birçok kişi ekip hâlinde çalışıyor; fuzzing'i paralelleştiriyor, bilgi birikimlerini ve başka exploit'leri birleştirip zincirleyebiliyor
Bazı araştırmacıların uzmanlığı ve yeteneği şaşırtıcı düzeyde; bu alanda yıllar hatta on yıllar boyunca biriken deneyim muazzam değer taşıyor
Ama bugün bulunan önemli açıkların iyi finanse edilen ekipler veya devlet destekli aktörler tarafından keşfedildiği düşünülürse, büyük insan gücü ve kaynakla mevcut azaltmaların aşılabilmesi daha anlaşılır geliyor
Ubuntu'ya göre tüm LTS sürümleri etkileniyor ve düzeltme şu anda yamalanmış çekirdeklerde mevcut: https://ubuntu.com/security/CVE-2024-1086
Focal için
5.4.0-174.193, Jammy için5.15.0-101.111, Mantic için6.5.0-26.26sürümünde düzeltildiGenişletilmiş destek kullanılıyorsa Xenial ve Bionic de buna dahil
Güvenlik açığı bulunan bir Debian sisteminde denedim; yetki yükseltme gerçekleşmedi ama ikinci çalıştırmada tüm sistem dondu
İlk çalıştırma da sadece başarısız oldu, yani yine de yamaya zaman ayırmaya fazlasıyla değer
Mevcut çekirdek yapılandırması
/boot/configveya/proc/config.gzgibi dosyalardan kontrol edilebilir