Skip to content
Siber Vatan

Binary Exploitation ve Exploit Geliştirme ​

Nejdet Yılmaz · @nejdett

Can Polat Zorkun · @Polat174

Yusuf Dalmış · @yusufdalmis

Zafiyet, bir yazılımın beklenmeyen veya yetkisiz davranış üretmesine yol açabilen zayıflıktır. Zafiyet analizi bu zayıflığın nedenini ve etkisini belirler. Binary exploitation ise derlenmiş programlardaki hataların, özellikle bellek bozulmalarının program akışını nasıl değiştirebildiğini inceler. Bu yazıda stack taşması üzerinden çökme keşfi, offset tespiti, adres seçimi ve payload yerleşimi ele alınır.

Binary exploitation için temel bellek kavramları ​

Stack, fonksiyon çağrıları sırasında kullanılan ve son giren verinin ilk çıkarıldığı LIFO düzenine sahip bellek yapısıdır. Klasik x86 fonksiyon çerçevesinde yerel değişkenler, kaydedilmiş çerçeve işaretçisi ve dönüş adresi bulunabilir. Dönüş adresi, fonksiyon tamamlandığında yürütmenin devam edeceği noktayı belirler.

Buffer overflow, bir arabelleğe ayrılan kapasiteden fazla veri yazılmasıdır. Taşma stack üzerinde oluşabileceği gibi dinamik olarak ayrılan heap alanında da gerçekleşebilir. Komşu verinin bozulması her zaman kod yürütme sağlamaz; etkilenen verinin programdaki rolü önemlidir.

Format string zafiyeti, kullanıcı girdisinin printf gibi bir fonksiyonda biçimlendirme dizgesi olarak kullanılmasıyla oluşabilir ve bellek okuma veya yazmaya yol açabilir. Use after free ise serbest bırakılmış bir bellek alanına yeniden erişilmesidir. ROP, mevcut çalıştırılabilir kod içindeki kısa komut parçalarını bir zincirde yeniden kullanan tekniktir.

Exploit ile payload arasındaki fark ​

Exploit, zafiyeti tetikleyen ve istenmeyen davranışı oluşturan yöntem veya koddur. Payload ise bu davranışın sonucunda gerçekleştirilecek işlemdir. Komut satırı açmak bir payload örneğidir; her exploit’in sonucu shell erişimi değildir.

Klasik stack taşması örneğinde tetikleyici girdi, doldurma verisi olan padding, değiştirilmek istenen dönüş adresi ve payload birlikte değerlendirilir. Shellcode, hedef mimariye uygun ham makine kodundan oluşan bir payload türüdür.

Çökme keşfi ve tekrarlanabilir girdi ​

Exploit geliştirmede önce hatanın tekrarlanabilirliği incelenir. Fuzzing araçları büyük, beklenmedik veya hatalı biçimlendirilmiş girdilerle çökme noktaları arar. Ardından debugger veya bellek dökümü üzerinden hata anındaki komutlar, yazmaçlar ve bellek alanları değerlendirilir.

GDB ve EDB bu inceleme için kullanılan debugger’lardır. Pwntools, Python ile payload hazırlama ve süreç iletişimini kolaylaştırır. Radare2 ve IDA Pro ikili dosyanın çalışma mantığını incelemeye; ROPgadget ve Ropper ise mevcut kod parçalarını bulmaya yardımcı olur.

İlk aşamada çökme, aynı girdinin aynı koşullarda yeniden denenmesiyle doğrulanır. Girdinin uzunluğu ve içeriği kaydedilir; hatanın kopyalama sırasında mı yoksa fonksiyon dönüşünde mi oluştuğu incelenir. Aynı girişin farklı noktalarda hata vermesi, bellek adresleri veya çalışma koşulları gibi ek etkenlere işaret edebilir.

Buffer overflow örneğinde ilk inceleme ​

Aşağıdaki fonksiyon, uzunluğunu kontrol etmeden girdiyi 64 baytlık bir buffer’a kopyalar. strcpy hedef alanın boyutunu bilmediğinden, sonlandırıcı sıfır bayt dahil kopyalanan veri bu alanı aşabilir.

c
#include <string.h>

void vulnerable_function(char *input) {
    char buffer[64];
    strcpy(buffer, input);
}

64 baytlık buffer için sonlandırıcı sıfır bayt da ayrılan alana sığmalıdır. Girdinin uzamasıyla strcpy komşu belleğe yazabilir. Bu noktada asıl soru yalnızca programın çöküp çökmediği değil, buffer dışındaki hangi verinin etkilendiğidir. Yerel bir değişkenin bozulmasıyla dönüş adresinin bozulması farklı sonuçlar doğurur.

Laboratuvar derlemesinde -fno-stack-protector stack canary eklenmesini kapatır, -z execstack yürütülebilir stack ister, -no-pie ise PIE üretimini kapatır. Bunlar işletim sisteminin ASLR ayarını kapatmaz. Bellek davranışının yorumlanması, hangi korumaların etkin olduğunun bilinmesini gerektirir.

EDB kaydında uygulama segmentation fault ile durur ve 0x63413563 adresinin eşlenmediği bildirilir. Bu, uygulamanın geçerli olmayan bir bellek konumuna erişmeye çalıştığını gösterir. Hatanın kaynağını belirlemek için durulan komut, yazmaç değerleri ve stack birlikte incelenir. Hata penceresindeki adresin bir giriş desenine benzemesi, kontrol akışının ele geçirildiğini tek başına kanıtlamaz.

EDB debugger üzerinde çökme kaydı

Şekil 1 — EDB üzerinde çökme kaydı.

Offset tespiti ve register kontrolü ​

Offset, girdinin başlangıcı ile hedeflenen bellek konumu arasındaki bayt uzaklığıdır. Yalnızca A karakterlerinden oluşan bir girdi, hangi bölümün kontrol verisine ulaştığını ayırt etmeyi zorlaştırır. Benzersiz desen kullanıldığında ise çökme kaydındaki değer, desen içindeki belirli bir konumla eşleştirilebilir.

Metasploit’in msf-pattern_create aracı bu desenin üretilmesini, msf-pattern_offset ise gözlenen değerin desen içindeki konumunun bulunmasını sağlar. Girdi uzunluğu ile offset farklı kavramlardır: Uzunluk gönderilen toplam veriyi, offset belirli bir konuma kadar olan uzaklığı ifade eder.

Görselde msf-pattern_offset, 0x63413563 için “Exact match at offset 76” sonucunu verir. Desendeki ilgili değer, başlangıçtan 76 bayt uzaklıktadır. Bu sonuç sonraki doğrulama için bir konum bilgisi sağlar; dönüş adresine olan uzaklık olarak kullanılabilmesi için bu değerin debugger’da hangi bellek alanından geldiği belirlenmelidir.

76 baytlık offset eşleşmesi

Şekil 2 — Desen içinde 76 baytlık offset eşleşmesi.

64 bayt buffer + 4 bayt saved EBP = 68 bayt hesabı, sadeleştirilmiş bir 32 bit stack yerleşimidir. Derleyici hizalaması ve fonksiyon çerçevesindeki ek veriler nedeniyle gerçek programda farklı bir uzaklık görülebilir. Bu laboratuvar kaydındaki 76 baytlık eşleşme, buffer boyutundan otomatik offset çıkarılamayacağını gösterir.

Register kontrolü aşamasında, belirlenen konuma gönderilen ayırt edilebilir verinin gerçekten hedef kontrol alanına ulaşıp ulaşmadığı incelenir. 32 bit bir dönüş adresi için dört baytın doğru konumu etkilemesi önemlidir. Desen eşleşmesi, hedef alanı belirlemek için kullanılır; kontrol akışının değiştiği ayrıca doğrulanır.

Adres tespiti ve bellek korumaları ​

Kontrol akışının etkilenebildiği belirlendikten sonra yürütmenin yönlendirileceği adres seçilir. Bu adres, enjekte edilen kodun bulunduğu alan veya uygulama içindeki uygun bir komut dizisi olabilir. Adresin geçerli olması, gerekli bellek izinlerine sahip olması ve ilgili çalıştırmada doğru konumu göstermesi gerekir.

ASLR, stack, heap ve kütüphane gibi bellek bölgelerinin konumlarını rastgeleleştirerek sabit adreslere güvenmeyi zorlaştırır. DEP ve NX, çalıştırılamaz işaretlenen sayfalarda kod yürütülmesini engeller. Bu nedenle stack üzerinde bir payload bulunması, onun yürütülebileceği anlamına gelmez.

Stack canary, korunan fonksiyonlarda dönüş öncesinde denetlenen bir değerdir. Taşma bu değeri bozarsa program sonlandırılabilir. Bellek korumaları farklı aşamaları etkiler: Canary bozulmayı yakalamaya, ASLR adres tahminini zorlaştırmaya, NX ise belirli sayfalarda yürütmeyi engellemeye yöneliktir.

Mevcut kodu yeniden kullanan ROP zincirleri, doğrudan shellcode yürütmeden işlev gerçekleştirebilir. Ancak uygun gadget adreslerinin bilinmesi ve diğer korumaların değerlendirilmesi gerekir. ROP veya ret2plt tek başına ASLR için genel bir çözüm değildir.

Payload yerleşimi ​

Klasik 32 bit örnekte payload; ölçülen offset kadar padding, dört baytlık dönüş adresi ve shellcode şeklinde düzenlenebilir. Padding hedef konuma ulaşmayı, dönüş adresi kontrol akışını yönlendirmeyi, shellcode ise amaçlanan işlemi gerçekleştirmeyi sağlar. Bu düzen, hedef programın bellek yerleşimine göre değişir.

Payload’un boyutu ve baytları, uygulamanın giriş işleme biçimine de uymalıdır. Örneğin strcpy içinden aktarılan bir veride sıfır bayt dizenin sonunu belirtir ve devamındaki baytların kopyalanmasını durdurabilir. Eksik taşınan bir payload, doğru offset seçilmiş olsa bile beklenen davranışı üretmeyebilir.

Bu nedenle yerleşim yalnızca uzun bir girdi hazırlamak değildir. Verinin hedef konuma ulaşması, seçilen adresin geçerli olması ve yürütülecek kodun uygun koşullarda bulunması birlikte kontrol edilir. Aşamalar ayrı incelendiğinde, başarısızlığın offset’ten mi, adresten mi yoksa bellek izinlerinden mi kaynaklandığı daha anlaşılır hale gelir.

Shell çıktısı ve uygulama sonucu ​

Terminal görüntüsünde exploit.py çalıştırıldıktan sonra “Girdi kopyalandı!” mesajı ve komut satırı görülür. whoami komutu root yanıtını, pwd ise /home/kali/Desktop/altay dizinini verir. Bu kayıt, son aşamadaki terminal etkileşimini gösterir. Betiğin içeriği ve başlangıç yetkileri görünmediğinden yalnızca bu görüntü üzerinden tüm exploit yapısı veya bir yetki yükseltme sonucu çıkarılamaz.

Shell üzerinde whoami ve pwd çıktıları

Şekil 3 — Betiğin ardından görülen shell çıktısı.

Üç görsel farklı sorulara karşılık gelir: EDB kaydı hatanın oluştuğunu, desen araması ilgili değerin 76 bayttaki konumunu, terminal kaydı ise komutların yanıtlandığını gösterir. Bu bulgular arasında bağlantı kurulurken çökme, kontrol verisinin etkilenmesi ve payload’un çalışması ayrı aşamalar olarak değerlendirilir. Böylece elde edilen sonuç, gözlemlerin desteklediği kapsamda açıklanır.

Kaynaklar ​