Heap Overflow Atak Nedir? Nasıl Yapılır?

 

Diyelim ki, yapılması gereken iÅŸleriniz var ve bu iÅŸlerin elinizde bir listesi var.  Bir bilgisayar gibi düşünürsek, listeye bakarak sıradaki yapılması gereken iÅŸi yaparız ve bir sonraki iÅŸ için tekrar listeye bakıp o iÅŸi yaparız.  Bilgisayar, programları bu ÅŸekilde çalıştırır. Ä°ÅŸlemci bir programı, “program counter” ismi verilen kaydediciye bakarak iÅŸler. Bu kaydediciye program komutlarının adresleri sıra sıra yerleÅŸtirilir.  Program,  yazılan komut adresleri üzerinden iÅŸlendiÄŸi için ramdeki bu adresler sabote edilerek kötü amaçlı olarak yönlendirilebilir. Exploit dediÄŸimiz programlar, hedef programların açıklarından faydalanıp program hafızasını bu ÅŸekilde sabote ederler.

Daha önceki StackOverflow Atak isimli yazımda bunlardan bahsetmiştim ama tekrar hatırlamakta fayda var.

Bir program çalıştığında program için ramden belli kalıplara sahip alanlar tahsil edilir. Bu alanlar, linux işletim sistemlerinde şu şekildedir;

Program çalışırken programa ram den  heap ve stack adı verdiğimiz iki önemli alan tahsis edilir. Exploitler bu iki bölümü sabote etmeye yoğunlaşırlar.  Stack bölümünün nasıl sabote edildiği hakkında bahsetmiştim.  Heap bölümü, programda dinamik olarak tahsis edilebilinen bir alandır. Malloc(), alloc() gibi C fonksiyonlarıyla tahsis edilir ve free() fonksiyonuyla da bu bölümler serbest bırakılarak tekrar kullanıma açılabilir.  Örnek olarak şu programa göz atalım;

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <inttypes.h>

struct Object {

        char    *name;
        void    (*operation)();
};


void secret()
{
        printf("We are in secret @ %d\n", 12);
}



int main(int argc, char **argv)
{
        struct Object *o1, *o2;
        const char *str1 = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x20\x80\x55\x55\x55\x55\x00\x00";
        const char *str2 ="\x8a\x51\x55\x55\x55\x55\x00\x00";

        o1 = malloc(sizeof(struct Object));
        o1 -> name = malloc(8);
        o2 = malloc(sizeof(struct Object));
        o2 -> name = malloc(8);

        o1->operation = 0x10;
        o2->operation = 0x10;

        strcpy(o1->name, str1);
        strcpy(o2->name, str2);

        printf("main\n!\n");
}





 

Programda object ismindeki bir struct içerisinde biri “char pointer” ve bir “function pointer” olmak üzere iki deÄŸiÅŸken tanımlanmış. Bu struct, heap bölümünde dinamik olarak oluÅŸturulup içerisine str deÄŸerleri yerleÅŸtirilmiÅŸ. Fakat dikkat ettiÄŸiniz üzere strcpy fonksiyonları herhangi bir uzunluk belirtmediÄŸinden dolayı programa str deÄŸerleri ile istenilen uzunlukta veri girilebilir durumda. Bu da bize heap bölümünü overflow edebilmek için bir olanak saÄŸlıyor.

Yukarıdaki programda malloc fonksiyonuyla ayrılan heap bölümündeki alanlar temel olarak DLMalloc algoritmasına göre yapılanıyor. malloc fonsiyonu heap bölümünden istenilen kadar alan ayırıp, ayrılan alanın adresini döndüren bir fonsiyondur.

o1 = malloc(sizeof(struct object)); komutuyla yukarıdaki tablodaki gibi, object struct’ı için 32 byte’lık alan ayrılır.  Bunun sebebi, 64 bitlik bir sistemde malloc fonksiyonunun heap’i 32 bytelık bloklar halinde tahsis etmesidir. Bu ayrılan  alanın önünde bu alanın kaç byte olduÄŸu bilgisi yukarıdaki tablodaki “size” ÅŸeklinde tanımlanmış bölüme yerleÅŸtirilir.  EÄŸer bir önceki alan aynı deÄŸiÅŸkene ait deÄŸilse yani kullanımdaysa bu alanın son biti “1” set edilir. Yani 64 bytelık bir sistemde burası 0x21 olacaktır. Çünkü 0x20, 32 byte demek, 0x01 ise bir önceki alanın baÅŸka deÄŸiÅŸken tarafından kullanıldığını ifade etmektedir.. 

Struct için bir alan ayrıldıktan sonra bu struct içerisinde, name isimli adreste tutulacak olan  bir char dizi için de 8 byte’lık bir alan, “o1->name = malloc(8);” komutuyla ayrılmış.  Bu alanı da yukarıdaki tabloda 2. satır olarak düşünebilirsiniz.

Yukarıdaki tabloda her hücrenin bir adresi vardır. char * name deÄŸiÅŸkeni 2. satırdaki ilk “free 8 byte” lık alanın adresini tutmaktadır.   Sonuç olarak yukarıdaki programda heap bölümünde aÅŸağıdaki gibi alanlar ayrılmış olur.

Teorik olarak bu alanı sabote edebilmenin en güzel yolu ikinci struct için ayrılan alandaki name isimli adresi overflow edip gerçek adresi yerine istenilen ve programın başka bir fonksiyona atlamasına yatarayacak bir adres yazmaktır.. Bu sayede programı exploit etmiş oluruz.

Yani overflow edilmiÅŸ heap ÅŸu eÅŸkilde olmuÅŸ olur;

 

Kırmızı iÅŸaretli hafıza bölgerelerine komut satırından veri yazabiliriz.  Normal ÅŸartlarda kullanıcının bu alanlardan sadece “free 8 byte” ismindeki alanlara veri giriÅŸi yapabilmesi gerekirdi. Ancak veri giriÅŸine ve bu verilerin hafızaya aktarılmasına herhangi bir kısıtlama getirilmemesinden dolayı, kullanıcı üzerine yazmaması gereken adreslere de veri yazabildi.  Bu sayede kullanıcı, programı kötü amaçlı kullanılabilecek komut adreslerine yönlendirebildi.

Aslında “o2->name” deÄŸiÅŸkeninin adresini tutan bu alana kötü amaçlı bir adres yazarak bir dahaki strcpy fonksiyonunda istediÄŸimiz bir alana istediÄŸimiz deÄŸeri yazma ÅŸansı yakalamış olduk. EÄŸer buraya “global offset table” adreslerini ezersek, program printf yada herhangi bir standart fonksiyonunu çağırarak aslında bizim istediÄŸimiz adresteki fonksiyonu çağırır.

İşin pratik kısmını kendiniz denemek isterseniz  bu programı herhangi bir C debugger(bunlardan en yaygın kullanılanı gdb dir) aracı kullanarak çalıştırabilir ve veri alanlarını kendiniz görebilirsiniz. Şimdilik İşin pratik kısmını buraya yazma gereği duymuyorum.  Çünkü gdb gibi debugger programları kullanmak ayrı bir yazının konusu olacak inşallah.

Burada yazdıklarımı , şu adresten gdb ile nasıl uygulandığını görebilirsiniz.  Bu yazı içeriği belirtilen adresten alıntılanmıştır.

 

 

Yusuf

Yusuf

Bir Mühendis.

Önerilen makaleler

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Translate »