Merhabalar,
Stack tabanlı overflow zafiyetlerinin nasıl istismar edileceği ile alakalı blogumuzdan sonra bu sefer konumuz belleklerdeki ASLR korumasının nasıl aşılacağı ile ilgili olacak. ASLR’ın ne olduğuna değinip bypass yöntemleri üzerinde duralım ve bu engelin nasıl aşılacağına beraber bakalım.
ASLR (Address Space Layout Randomization)
Türkçe karşılığı olarak, Adres alanı düzeninin rastgeleleştirilmesidir. ASLR bir process’in her çalıştığında virtual memory üzerinde stack ve library adreslerini randomize edip değiştiren bir güvenlik önlemi ve mekanizmasıdır. Geçen blogumuzu okuyanlar bilirler ki, shellcode’umuzu stacke yazdıktan sonra EIP register üzerine JMP ESP gibi komutların adreslerini yazdırmıştık. Bunun nedeni programın çalışmaya devam ettiği sürede onu yönlendirip ESP üzerinden çalışmasını sağlayıp EIP register’a JMP ESP yazdırıp shellcode’umuzun bulunduğu alana JUMP (zıplama) etmesiydi. ASLR koruması, aktif kütüphanelerde veya dosyalarda tespit ettiğimiz JMP ESP komutunun adresini programı her yeniden başlattığımızda yeniden değişecektir. Bu da yazılan exploit’in bir sonraki sefer tekrar çalıştırılamamasına sebep olabilir. Bu ASLR korumasını tabi ki atlatmanın yöntemleri mevcut bunlardan bir kaçı şunlardır:
-ROP (return-oriented programming)
-Return to PLT (return to procedure linkage table)
-Brute force (kaba kuvvet)
Bu blogumuzda brute force ile ASLR korumasının atlatılmasından bahsedeceğiz. Bunu linux sistem üzerinde yapacağız. Linux işletim sisteminde aslr korumasının aktif olup olmadığını kontrol etmek için randomize_va_space dosyasını kontrol etmemiz gerekiyor.
“cat /proc/sys/kernel/randomiza_va_space”

Burada karşımıza çıkan rakamlar aslr korumasının hangi derece aktif olduğunu bize gösteriyor.
0: ASLR kapalı (güvenli değil).
1: Sadece stack, heap ve mmap alanları rastgeleleştiriliyor (orta düzey güvenlik).
2: Tüm bellek alanları rastgeleleştiriliyor (tam ASLR, en güvenli ayar).
Bu ayar, özellikle güvenlik araştırmacıları ve yazılım geliştiricileri için önemlidir. Saldırı vektörlerini test ederken ASLR’yi geçici olarak kapatabilir veya zayıf bir seviyeye ayarlayabilirsiniz. Ancak üretim ortamlarında her zaman tam ASLR kullanılması önerilir.
İlk olarak işletim sistemi üzerindeki ASLR’ın nasıl çalıştığını görüntüleyebilmemiz için yazdığımız C kodunu 32 bit de gcc derleyicisi derleyeceğiz.

Kodu derlerken –m32 argümanıyla 32 bit de derlenmesi istediğimizi belirtiyoruz. Derlerken yukarıdaki ekran görüntüsündeki hatayı alırsanız “sudo apt-get update && sudo apt-get install gcc-multilib” komutunu kullanabilir ve gerekli kütüphane paketlerini kurabilirsiniz.
Dosya derlendikten sonra “./aslr” diyerek dosyayı bir çok defa çalıştırıyoruz ve gösterici adresinin(pointer) her defasında farklı adresi gösterdiğini görebiliriz. ASLR’ın etkisini bu aşamada anlaşılır şekilde gözlemleyebiliyoruz.

Görüldüğü üzere program her çalıştırıldığında bellekteki adres değişmektedir. 32 bit işlemler ile 64 bit işlemler arasındaki bellek adreslerini karşılaştırıp gözlemleyelim. Bu sefer programı gcc derleyicisi ile 64 bit de derleyip çalıştırıyorum. (-m64)

64 bit de derlenen program her çağırıldığında bellekteki adres daha uzun ve haliyle bellekte var olan adres ya da kullanılabilecek bellek alanı daha büyük olacaktır.
Bu durumda yukarıdaki ekran görüntülerini görüp şöyle bir yorum yapılabilir. 32 bit derlemede elde edilen bellek adreslerinde ilk 2 ve son 3 rakamlar aynı. Yani 56 ile başlayıp 008 ile biten bir aralıkta bellek adresi döndürülüyor. Fakat 3. Rakam gördüğünüz üzere ya 5 ya da 6 oluyor. Burada bir basit bir hesaplama ile 32 bit derlenen bir programda var olan overflow açığını sömürebilmemiz ve aslr korumasını aşmak için brute force ile kaç ihtimalle EIPde belirtilen adresin denk düşebileceğini anlayabiliriz. Hesaplamaya şöyle bir bakalım;
İlk iki karakter (0x56) sabit.
Üçüncü karakterin sadece iki durumu var: 5 veya 6
Yani burada 1 bit rastgelelik var.
Son üç karakter (008) sabit.
Rastgelelik yalnızca 4. ve 5. karakterler üzerinde gerçekleşiyor.
Eğer 4. ve 5. karakterler sadece 256 olasılığı olan bir byte (8 bit) değerinde rastgelelik gösteriyorsa, toplam rastgelelik şu şekilde olur:
1 bit (3. karakter için) + 8 bit (4. ve 5. karakterler için) = 9 bit rastgelelik.
Bu durumda olası adres sayısı:
2^9 = 512 farklı olasılık.
Finalde hazırlayacağımız shellcode içerisinde, EIP register’a yazacağımız adres 512 farklı olasılıkla aynı adresi gösterecek. Bu da exploitimizi loop’a sokup bir süre devam eden looptan sonra EIP register üzerine yazılan adresin aynı adresi göstereceği anlamına geliyor. Exploit çalışacak ve stack alanına yazdırılan shellcode(zararlı kodlar veya her ne isterseniz) ilgili makine üzerinde çalışıyor olacak. ASLR korumasını bu yöntemle atlatabiliriz. 64 bitlik işlemlerde bu işlem çok daha uzun sürmektedir. Çünkü yukarıda bahsettiğimiz gibi 64 bit de adres aralığı çok fazla olduğundan EIP’ye yazılan adresin denk gelme şansı oldukça düşecektir. Bugünkü senaryomuzda strcpy fonksiyonu kullanan zafiyetli bir uygulama yazıp, bu uygulamada blogumuzun anlaşılabilirliğini kolaylaştırmak için bizi doğrudan shell’e düşürecek bir fonksiyon yazıp bu fonksiyonun adresini EIP ye yazacağız ve shell’e root yetkisinde erişeceğiz. Yazdığımız zafiyetli uygulamada JMP ESP gibi stack belleğe zıplamamıza yarayacak bir adres alanı bulamayacağımız için (yazdığımız programın basitliğinden ötürü ve inline assembly içermediğinden ötürü) direkt shell’e düşmemizi sağlayacak bir fonksiyon yazacağız. Burada amaç ASLR’ın brute force ile nasıl bypass edilebileceğini görmek ve mantığını kavramaktır.
Zafiyetli kodun son hali şöyledir:

Kodun derlenmesi aşamasında herhangi bir korumaya takılmaması için gcc derleyicisinde çeşitli argümanları belirtmemiz gerekiyor. Gcc derleyicisi ile programı 32 bit de ve korumalara takılmadan derlemek için şunları belirtiyoruz.
gcc –fno-stack-protector –mpreferred-stack-boundary=2 –z execstack –fno-stack-protector –g zafiyetliUygulama.c –o zafiyetliuygulama –m32
Ardından programı gdb –gnu debugger- ile açıyoruz.

Programımız bir argüman alıp strcpy ile bunu “e” dizisine kopyalıyor. “e” dizisi char türde 150 byte kapasitede çalışıyor. Var olan overflow zafiyetini tetiklemek için 150 byte’dan fazla veriyi girdi sağlayıp segmantation fault’a düşürmeye çalışalım.

170 adet A karakteri gönderdiğimizde ve info registers ile registerları kontrol ettiğimizde SIGSEGV sinyali aldığımızı (segmentation fault) gördük. 41414141 büyük “A” karakterinin hexadecimal karşılığıdır. Kaçıncı byte’dan sonra taşma oluştuğunu tespit etmek için pattern_create ile 170 byte’lik bir payload oluşturalım.



Payload’u gönderdiğimde 0x33664132 değerini görüyoruz bu bizim taşırabildiğimiz ve EIP register’a yazdığımız paternlerde var olan herhangi bir 4 byte’ın değeri. Bu değeri kopyalayıp, pattern_offset.rb de kontrol ettiğimizde EIP register’a 158 byte’dan sonra yazabildiğimizi görüyoruz. Kodumuzda hatırlarsanız fonk adında bir fonksiyon oluşturmuştuk ve buna setuid ile 0 (root idsi), system fonksiyonu ile de /bin/bash’i çalıştırmasını söylemiştik. Bu fonk fonksiyonunu çağırdığımızda bize /bin/bash shell’i açacak. Bunun için fonk fonksiyonunun adresini öğrenmemiz ve EIP ye yazmamız gerekiyor. Ardından programı loop’a sokup EIP ye yazdığımız fonk fonksiyonunun adresini brute force ile denk getirip shell’e root yetkisinde düşeceğiz.
Fonk fonksiyonumuzun adresi 0x565561ad little-endian – big-endian muhabbetinden dolayı EIP’ye bu adresi tersten yazacağız.
\xad\x61\x55\x56

Öncesinde, root kullanıcısını uygulama sahibi yapıyorum.
chown 0:0 zafiyetliUygulama
chmod +s zafiyetliUygulama
Ve son olarak loop’a sokup çalıştıracağımız payload’ımız şöyle şekilleniyor.
While true; do ./zafiyetliUygulama $(python2.7 –c ‘print “A”*158+”\xad\x61\x55\x56”’); done

Loop sonunda ASLR korumasını bypass edip /bin/bash’e düşüyoruz.
Sürçü lisan varsa affola. Saygılar.