Selamlar. Normalde blogu komple ingilizce olarak devam ettirme kararı almış olsam da bazı konuları Türkçe devam ettireceğim.
Bugün biraz ROP nedir, ROP gadgetlar ne işe yarar bunlara değineceğiz ve örnek bir ret2libc atak senaryosu göstereceğiz. Fazla oyalanmadan başlayalım!
Linux:
echo 0 > /proc/sys/kernel/randomize_va_space
Windows:
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management]
MoveImages=dword:00000000
Buffer overflow, temelde programın bellekte kendine ayrılmış veri alanına, alması gerekenden daha fazla miktarda veri girişi olması durumunda programın kendine ayrılmış bellek alanından taşması ve bu taşmayı kullanarak kod çalıştırmaya yol açan bir zafiyettir.
Fakat bu senaryo her zaman anlatıldığı kadar kolay gerçekleşmeyebiliyor. Çünkü buffer overflow zafiyetlerini önlemek amacıyla geliştirilmiş bir takım güvenlik önlemlerimiz var.
Bu yazıda üstünde duracağımız ve önemli güvenlik önlemlerinden biri de bir çoğunuzun DEP(Data Execution Protection) olarak da bildiği NX (Non-executable) stack.
Bu güvenlik önleminin temel prensibi programa ayrılmış olan data segmentlerini non-executable yani yürütülemez olarak işaretleyip ve bu alanlara müdahaleyi engellemesidir.
Dolayısıyla siz bir buffer overflow zafiyeti bulsanız bile programınızın veri alanı non-executable işaretlendiği için dışarıdan kod enjekte edemiyor/ exploitation yapamıyorsunuz.
Tam bu noktada da ROP devreye giriyor!
push 0x12345678 # Stacke 0x12345678 değerini push eder.
ret # Stackte en üstte yazan (0x12345678) değerini EIP'e set eder ve program bu adresten yürütülmeye devam eder.
bu bilgiyi yazının ilerleyen vakitlerinde ve binary exploitation ile uğraşırken sıkça kullanacağız. Aklımızın bir köşesinde dursun. Şimdi lab üzerinden devam edelim.
Basit bir C kodumuz var. Bu kodda hiç çağrılmamış bir rop() fonksiyonu ve değişkene 100 bytelik yer ayırıp argv[1] den aldığı veriyi değişkenin içine strcpy fonksiyonu ile kopyalayan runner_func fonksiyonumuz var.
Kodumuzu derliyor ve gdb'ye atıyoruz. Ben bu yazı boyunca gdb-peda kullanacağım. Labı tekrardan uygulayacak arkadaşlar < https://github.com/longld/peda > bu adresten kurulum yapabilirler.
gcc -m32 -fno-stack-protector -z execstack rop.c -o rop
Programımızı çalıştırıp b main ile main fonksiyonuna breakpoint attıktan sonra p rop komutu ile rop() fonksiyonumuzun adresini kontrol ediyoruz (0x565561ad).
(Payload oluşturmak - yardımcı araçları kullanmak için https://projects.jason-rush.com/tools/buffer-overflow-eip-offset-string-generator/ adresini kullanabilirsiniz.)
112 sonucunu aldık. Yani 112 byte'dan sonra yazdığımız her şey EIP'e (instruction pointerimize) etki edecek. p exit diyerek exit komutumuzun da adresini alalım.
Payloadımızı oluştururken programın crash vermeden işlemleri sırasıyla yapması için şu şekilde bir ROP chain oluşturacağız;
112 * A + rop() address + exit address
./rop "$(python2 -c 'print "A"*112 + "\xad\x61\x55\x56" + "\xc0\x71\xdb\xf7"')"
Gördüğünüz gibi programda bulunan fakat çağrılmamış bir fonksiyonu çağırmayı başardık.
b main komutunu kullanarak main fonksiyonumuza breakpoint atıyor ve programımızı başlatıyoruz. Atak senaryomuza başlamadan önce programa dahil edilmiş libraryleri ldd aracılığı ile kontrol edelim.
Resimde gördüğümüz gibi standart libraryimiz olan libc programımıza include edilmiş gözüküyor. Atak senaryomuzu gerçekleştirmek / shell alabilmemiz için bu kütüphaneyi kullanacağız.
Kütüphanemizle alakalı bilgileri, ilgili adreslerimizi edindik. Bir önceki örnekten ne kadar uzunlukta bir payload göndermemiz gerektiğini ve EIP adresini bildiğimiz için bu işlemleri tekrarlamıyorum.
find komutu ile kontrol ettiğimiz libc kütüphanesindeki /bin/sh 'nin adresini bu noktada kullanacağız. JUNK (108 * A padding) + BBBB (4 byte EBP padding) + "system" call + "exit" call + address of "/bin/sh" we found in libc
./rop `python2 -c 'print "A"*112 + "\xb0\x4c\xdc\xf7" + "\xc0\x71\xdb\xf7" +"\xf5\x60\xf3\xf7"'`
g0t shell! Dışarıdan herhangi bir shellcode göndermeden sadece programın kendi içindeki kütüphanelerini kullanarak shell aldık. Biraz detaylandırmak gerekirse;
ROP chainlerde dikkat edilmesi gereken en önemli husus ROP gadgetlerinin zincirde doğru yerlerde olmasıdır.
İşte exit çağrısı burada ufak ama güzel bir önlem taşıyor.