31 Ağustos 2013 Cumartesi

Linux Sistemlerde Bellek Taşması Koruma Mekanizmaları

Linux sistemler içerisinde bellek taşması hatalarını önlemek için birçok mekanizma bulunmaktadır. Bu koruma mekanizmalarından bazıları çekirdek seviyesinde çalışmakta, bazıları ise derleyici tarafından oluşturulan koruma mekanizmalarıdır. Bu yazıda Linux sistemler üzerinde bulunan bellek taşması (Buffer Overflow), oluşturan zararlı kodlara (exploit) karşı hazırlanan önleme mekanizmalarının bazılarına değinilecektir.

ASLR (Address Space Randomization)

Çalıştırılabilir dosyaların, her çalışma esnasında sanal adres alanında oluşturulan adres değerlerinin rasgele olarak belirlendiği bir mekanizmadır. Bu yapı, saldırganların uygulamanın sanal adres alanındaki yerlerini tespit edebilmesini ve zararlı kod çalıştırmasını oldukça güçleştirmektedir.

ASLR çalışma mekanizmasını bir örnek bir kod parçacığı üzerinde inceleyelim.



Bu kod parçacığında görüldüğü gibi "buffer" değişkeninin bulunduğu adres bilgisi ekranda gösterilir. Bu uygulama her çalıştırıldığında bu adres bilgisinin farklı olduğu görülmektedir.



Ancak sistem üzerinde ASLR koruması pasif hale getirilirse, kod içerisinde görmüş olduğumuz "buffer" değişkenine ait adres bilgisinin bir önceki örnekteki gibi değişmediği görülecektir.  Linux sistemlerde ASLR korumasını pasif hale getirmek için /proc/sys/kernel/randomize_va_space içerisindeki değerin 0 olması gerekmektedir.


Örnek programı tekrar çalıştırıldığında uygulama çıktısı aşağıdaki gibi görülmektedir.


Görüldüğü üzere ASLR koruma mekanizması kapatıldığı zaman, uygulama her çalıştırıldığında, içinde bulunan değişkenin sanal adres alanı içerisindeki adresi değişmemektedir. Bu ASLR koruma mekanizmasının aktif halde tutulması önerilmektedir.

Executable Stack Protection

Executable Stack Protection, bellek taşması saldırılarına karşı derleyici tarafında gerçekleştirilen bir koruma mekanizmasıdır. Bu koruma metodunda uygulama derlenirken, stack üzerinde herhangi bir kod çalıştırmaması için işaretlenir. Uygulamanın stack yapısında kod çalıştırma korumasının olup olmadığını anlamak için çalıştırılabilir dosyanın içeriği incelenmelidir.  Bunun için "readelf" komutu bize yardımcı olacaktır.


Readelf komut çıktısı incelendiğinde GNU_STACK değeri aşağıdaki gibi elde edilmiştir. Bu değere göre bu uygulamanın stack yapısında okuma ve yazma yapılabilir ancak çalıştırma yapılamaz durumda olduğu görülmektedir.

GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4 

GCC derleyicisi derleme esnasında varsayılan olarak çalıştırma yetkisi vermez. Bu nedenle uygulamaya ait stack içerisinde kod çalıştırma yetkisinin aktif hale getirilmesi için, "-z execstack" parametresinin kullanılması gerekmektedir.

root@bt:~$ gcc -ggdb -m32 -z execstack ornek.c -o ornek 

Bu parametre aktif hale getirildikten sonra readelf komutu çıktısı incelendiğinde, stack yapısında kod çalıştırmaya izin verildiği görülmektedir.

 GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4 

Stack Smashing Protector

“GCC Stack Smashing Protector” bellek taşması saldırılarına karşı koruma sağlayan bir mekanizmadır. Eğer bir bellek tasma saldırısı gerçekleşir ise bunu kullanıcıya anında belirtir. Çalışma yöntemi olarak, stack frame yapısı içerisine “canary” değeri eklenir ve bu değer herhangi bir şekilde değişir ise bu bellek taşması veya bozulması olarak algılanır. Bu özellik bellek tasması zafiyetlerinin yanında stack üzerinde oluşan programlamadan kaynaklanan hataların oluşmasını da engeller. “Stack-Smashing Protector” yapısı StackGuard koruma mekanizmasının genişletilmiş halidir.

Bu stack koruma mekanizmasını aktif hale getirmek için derleme sırasında gerekli olan bayrakların eklenmesi gerekmektedir. Örneğin, eğer string koruması eklenmek isteniyor ise -fstack-protector, tüm türlerdeki korumaların aktif hale getirilmesi isteniyor ise -fstack-protector-all bayrağının eklenmesi gerekmektedir. OpenBSD gibi bazı sistemlerde bu stack koruma bayrakları varsayılan olarak her derlemede kullanılmaktadır. Eğer derleme işleminde stack korumasının iptal edilmesi isteniyor ise o zaman derleme esnasında -fno-stack-protector bayrağının parametre olarak eklenmesi gerekmektedir.

Yazının başında gösterilen örnek uygulama içerinde ayrılmış bellek alanından fazla bir girdiyi stack koruması eklenmiş durumu ve stack koruması eklenmemiş durumu ile bellek taşması gerçekleştirilmeye çalışılacaktır.



Görüldüğü üzere uygulamayı derlerken stack koruması eklenmez ise, uygulama çalıştırıldığında “segmentation fault” hatası alınır. Burada uygulamaya argüman olarak göderilen “A” karakteri ile stack yapısı içerisinde ayrılmış alandan fazlasına yazmaya çalışıldı. Eğer girdiğimiz değerler içerisinde fonksiyonun stack yapısı içerisindeki geri dönüş adresi içine anlamlı bir değer girilir ise uygulama kapanmadan farklı bir yöne doğru yönlendirilebilir. Sonrasında -fstack-protection parametresi ile uygulamayı derledikten sonra çalıştırıldığında stack üzerindeki belek taşmasının tespit edildiği görülmektedir.

Fortify Source

GCC içerisinde bellek taşmalarını tanıyan ve zafiyete uğratılmadan önce önleyen “FORTIFY_SOURCE” isminde bir özellik bulunmaktadır. Bu yapı ile derleyici derleme sırasında boyutlarını tanımlayabildiği bellek alanları için bir koruma yapısı ekler. Bu bellek alanlarına örnek olarak stack üzerinde oluşturulmuş sabit boyutlu bellek(buffer) alanları veya malloc() gibi fonksiyonlar ile heap üzerinde oluşturulmuş alanlar örnek olarak gösterilebilir.

Yazının başında gösterilen  uygulama C kodunu incelenecek olursa, buffer değişkeninin boyutu 10 byte olarak belirlenmiş olduğu görülür. Bu uygulama kodunu GCC’nin FORTIFY_SOURCE özelliği aktif edilerek derlenir ise, burada GCC strcpy() fonksiyonunu çağırırken aynı zamanda kopyalanan verinin uzunluğunu kontrol eder. Değişkenin boyutu belirlendikten sonra 10 byte'tan fazla veri buffer değişkeninin içerine kopyalanmaz. Eğer 10 byte'tan fazla bir veri gönderilir ise programdan çıkılır. Eğer derleme sırasında bu buffer değişkeninde bellek taşması ihtimali görülür ise GCC tarafından uyarı mesajı verilmektedir. 


Kendi yazdığınız uygulamalarda FORTIFY_SOURCE özelliğini aktif etmek için GCC ile derleme sırasında –D_FORTIFY_SOURCE=2 argümanı ile derlenebilir. Derleme işlemi gerçekleştirildikten sonra objdump uygulaması ile yazdığımız uygulama içerisindeki kontrol mekanizması aşağıdaki komut çıktısı ile görülebilir. 


Bu komutun çıktısında herhangi bir değer görülür ise FORTIFY_SOURCE yapısının aktif olduğu söylenebilir. Eğer bir sonuç alamazsak FORTIFY_SOURCE yapısı aktif edilmemiş veya bu uygulama içerisinde risk oluşturabilecek bir kod parçacığı bulunamadığı için uygulanmamış demektir.



Hiç yorum yok:

Yorum Gönderme