Yusuf Bülbül

An Engineer

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>

  

struct internet {
  int priority;
  char *name;
};

void winner()
{
  printf("and we have a winner @ %d\n", time(NULL));
}

int main(int argc, char **argv)
{
  struct internet *i1, *i2, *i3;

  i1 = malloc(sizeof(struct internet));
  i1->priority = 1;
  i1->name = malloc(8);

  i2 = malloc(sizeof(struct internet));
  i2->priority = 2;
  i2->name = malloc(8);

  strcpy(i1->name, argv[1]);
  strcpy(i2->name, argv[2]);

  printf("and that's a wrap folks!\n");
}

 

Programda internet ismindeki bir struct içerisinde biri int diğeri char pointer olmak üzere iki değişken tanımlanmış. Bu struct, heap bölümünde dinamik olarak oluşturulup içerisine komut satırından girilen değerler yerleştirilmiş. Fakat dikkat ettiğiniz üzere strcpy fonksiyonları herhangi bir uzunluk belirtmediğinden dolayı programa komut satırından 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.

free size int priority char * name
free size free 4 byte Free 4 byte 

i1 = malloc(sizeof(struct internet)); komutuyla yukarıdaki tablodaki gibi, internet struct’ının içerisindeki int için 4 byte ve char pointer için de 4 byte olmak üzere 8 byte’lık bir alan ayrılır. Bu ayrılan iki alanın önünde bu alanın kaç byte olduğu bilgisi yukarıdaki tablodaki “size” şeklinde tanımlanmış bölüme yerleştirilir.  Yukarıdaki free bölümüne ise bu alanın kullanılıp kullanılmayacağı yani free edilip edilmediği ile ilgili veri yerleştirilir.  Yukarıdaki tabloda her bir hücreyi 4 byte olarak düşünebilirsiniz. 

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, “i1->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 4 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.

Address
0x01230 free 0x10 int id = 1 name = 0x01248
0x01240 free 0x10 free 4 byte Free 4 byte
0x01250 free 0x10 int id = 2 name = 0x01268
0x01260 free 0x10 free 4 byte Free 4 byte

Teorik olarak bu alanı sabote edebilmenin en güzel yolu ikinci struct için ayrılan alandaki name isimli adresi overflow edip gerçek 0x01268 adresi yerine istenilen ve programın normelde çalıştırmayacağı bir adresdeki komutun adresi yazmaktır. Bu sayede programı exploit etmiş oluruz.

Yani overflow edilmiş heap şu eşkilde olmuş olur;

Address
0x01230 free 0x11 1 char * name
0x01240 free 0x11 free 4 byte Free 4 byte
0x01250 free 0x11 2 kötü amaçlı adres
0x01260 free 0x11 free 4 byte Free 4 byte

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 4 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.

İş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.

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir