Arabellek Nedir? Arabellek (buffer), farklı hızlarda çalışan donanım aygıtları veya program işlemleri tarafından ortak olarak kullanılan veri depolama alanını ifade eder. Bu alan, bir aygıtın veya işlemin, diğer aygıtlar veya işlemler tarafından müdahale edilmeden düzgün bir şekilde çalışabilmesi için gereklidir.
Aynı zamanda, program içerisinde belirli bir bellek kesimine ayrılmış olan arabellek, işlenen verilerin geçici olarak saklandığı bir bellek bölgesini temsil eder. Örneğin, video uygulamalarında, anlık gecikmeleri dengelemek ve önceden yüklenmiş video verilerini muhafaza etmek amacıyla arabellekler kullanılır.
Bir bilgisayar sisteminde, her bir uygulama genellikle kendi ayrılmış arabelleğini genel bellek havuzundan tahsis eder veya bu arabelleği havuza geri iade edebilir. Örneğin, yazıcı ve diğer çevresel cihazlar, gelen veya giden verileri geçici olarak depolamak için sabit arabellekler sağlarlar.
Bir arabelleğin etkili olabilmesi için boyutu ve verilerin içine ve dışına taşınma algoritmaları, arabelleği tasarlayan kişi tarafından özenle planlanmalıdır.
Aşağıdaki kod örneği, C programlama dilinde arabelleklerin nasıl tanımlandığını göstermektedir. "/" ve "/" işaretleri yorumları temsil ederken, "char" ve "long" C diline ait veri tipleridir. GELENbuff, verileri okumak için ayrılmış 1000 baytlık bir arabelleği gösterir:
İşletim sistemi seviyesinde bir işlem aşağıdaki şekilde çalışır:
Stack (Yığın): Yerel değişkenler devreye girdiğinde kullanılan bir bellek alanıdır. Stack içerisinde yer alan boş alanlar, değişkenler tanımlandıkça bu değişkenlere ayrılır ve stack işlevlerinin geri dönüş değerlerini depolamak için de kullanılır.
Heap (Öbek): Dinamik bellek yönetimi için kullanılan bir alandır ve genellikle belirli çağrılarla devreye sokulur.
Data (Veri): Sistem genelinde ve statik değişkenler bu bölümde yer alır ve ana işlevler devreye girmeden önce tüm değerleri atanmış ve ayarlanmış olur.
Text (Metin): Derlenmiş kodun tutulduğu alandır.
Bir işlev veya fonksiyon çağırıldığında, çeşitli işlemler gerçekleşir, program çalışır ve veri akışı oluşur; daha sonra bu işlemler bellekte bulunan belirli bir konum ile sürekli iletişim kurarak çeşitli değerler döndürür. Programlar, belirlenen parametrelere veri girdisi yapıldıktan sonra, yani işlevler görevlerini tamamladıktan sonra yığının (stack) yukarı doğru itilmesiyle, böylece yığın (stack) üzerindeki parametrelerle birlikte işlevin başka bir yere ya da adrese atlama durumuyla bu döngü sürekli olarak devam eder.
Arabellek Taşması (Buffer Overflow) Nedir?
Arabellek Taşması (Buffer Overflow), temel olarak bir programın veya işlemin bellekte kendisine ayrılan alana veri yazarken, bu ayrılan sınırları aşması durumunu ifade eder. Sonuç olarak, saldırgan bu taşan alanda kötü niyetli kodunu çalıştırarak sistemi ele geçirebilir.
Bir arabellek, verileri belirlenen bölgesinin sol veya sağ sınırlarından taşırmaya başlarsa, belirlenen sınırı geçmiş olur; yani arabellek taşması gerçekleşir. Bu şekilde veriler, arabelleğe başvuran program değişkenine ait olmayan belleğin bir bölümüne yazılır.
Aşağıdaki örnekte, 10 baytlık bir dizi bildiriyoruz. Dizi, 0'dan 9'a kadar olan dizinleri kullanarak 10 baytlık belleğe erişmek için kullanılır. Ancak bir sonraki satırda 'a' değerini depolamak için 10. dizini kullandığımızda, veriler arabelleğin sağ sınırının ötesine yazıldığı için arabellek taşması meydana gelir.
Arabellek taşması istismarı, bir işlemi kontrol etme, sistemi çökertme veya iç değişkenler üzerinde manipülasyon yapma olanağı sağlayan bir güvenlik açığı türüdür.
Arabellek taşması, programlama hataları sonucu yanlışlıkla ortaya çıkabileceği gibi kötü niyetli bir aktör tarafından da kasıtlı olarak kullanılabilir. Saldırganlar, bir programa özel olarak hazırlanmış bir girdi göndererek rastgele kod yürütme (arbitrary code execution) yöntemini kullanabilirler. Program, bu girdiyi sınırlı bir arabelleğe depolamaya çalışırken, geriye kalan veriler yan tarafta bulunan bitişik belleğe yazılırsa, arabellek taşması meydana gelir ve saldırgan, hareket edebileceği bir alan oluşturur.
Arabellegin içindeki orijinal veriler genellikle işlemin bir sonraki adımında kullanılan bilgileri içerir (örneğin, işaretçiler veya dönüş adresleri). Saldırgan, bu verileri manipüle ederek istediği bir adrese işaret edecek şekilde değiştirebilir. Bu sayede saldırgan, genellikle kötü niyetli kodunun bulunduğu bölgeye yönlendirilmiş yeni değerler ayarlar. Bu değişiklik, işlemin yürütme yolunu ve işaretçilerini değiştirerek, kontrolü saldırganın kötü niyetli koduna yönlendirir.
Örneğin, bir programın kullanıcıların ad girmelerini beklediğini düşünelim. Ancak saldırgan, ad yerine taşma yaratan bir komut girebilir. Bu komut, genellikle kısa olan ve sisteme örneğin bir Linux çevresinde kök kabuk (root shell) açmasını sağlayan bir komut istemi penceresi olan EXEC("sh") gibi bir komut olabilir.
Ancak, arabelleğin taşmasıyla gelen yürütülebilir bir komutun otomatik olarak yürütüleceği anlamına gelmez. Saldırganın, kötü amaçlı komutu işaret eden bir dönüş adresi belirtmesi gerekmektedir. Arabelleğin taşması sonucu program kısmen çöker ve daha sonra kurtarma işlemi başlar. Ancak dönüş adresi, saldırganın belirttiği komutu işaret etmek üzere değiştirildiği için, saldırganın komutun çalışacağı adresi bilmesi gerekir.
Saldırganın gerçek adresi bilmemesi durumunda, kötü niyetli komut genellikle her iki tarafta da bir tür işaretçi olan NOP (No Operation) veya "işlem yapma" talimatları ile doldurulur. Bu, bellek aralığının tam olarak bilinmediği durumlarda kullanılan bir tekniktir. Saldırganın belirttiği adres, bu doldurulmuş alanın içinde herhangi bir yere düşerse, kötü niyetli komut çalıştırılır.
C ve C++ gibi programlama dilleri, belleklerinin herhangi bir bölümündeki verilere erişmeye veya verilerin üzerine yazmaya karşı hiçbir korumaya sahip değildir. Sonuç olarak, arabellek taş(ır)ma saldırılarına karşı savunmasızdırlar. Saldırganlar, ortak programlama yapılarıyla doğrudan bellek manipülasyonu gerçekleştirebilir.
C#, Java ve Perl gibi modern programlama dilleri, kodlama hatalarının arabellek taşması güvenlik açıkları oluşturma olasılığını azaltır. Bununla birlikte, arabellek taşmaları, program derleyicisindeki kusurlar, çalışma zamanı kitaplıkları veya dilin özellikleri aracılığıyla doğrudan bellek manipülasyonuna izin verilen herhangi bir programlama ortamında gerçekleşebilir.
Arabellek Taşması Çeşitleri
Arabellek taşmaları, güvenlik açıklarını istismar etme teknikleri, işletim sistemine ve programlama diline bağlı olarak değişiklik gösterir. Bununla birlikte, temel amaç her zaman bir bilgisayarın belleğini manipüle ederek program yürütme kontrolünü ele geçirme ve bellekte değişiklikler yapma amacını taşır.
Arabellek taşmaları, arabellegin bellekteki konumuna göre genellikle yığın tabanlı (stack-based) taşmalar veya dinamik bellek (heap) tabanlı taşmalar olarak iki ana kategoriye ayrılır. Her iki kategori de bir cihazın rastgele erişimli belleğinde (random access memory - RAM) meydana gelebilir.
Yığın Tabanlı (Stack-based) Arabellek Taşması: Yığın, verileri son giren ilk çıkar (last-in, first-out) yapısıyla tutan bir bellek alanını ifade eder. İşlev parametreleri, yerel değişkenler, çerçeve ve yönerge işaretçileri gibi işlev çağrılarıyla ilişkilendirilen verileri düzenlemek için kullanılır. Tipik olarak, hedeflenen program, kullanıcı adı veya parola gibi girişleri beklediği sürece yığın boştur. Bu noktada, program yığın üzerine bir dönüş adresi yazar ve ardından kullanıcının girdisi bu adresin üzerine yerleştirilir. Yığın işlendiğinde, kullanıcının girdisi program tarafından belirtilen dönüş adresine gönderilir.
Ancak yığının belirli bir boyutu vardır ve programcılar, yığın için ayrılacak alan miktarını önceden tahmin etmelidir. Eğer kullanıcının girdisi, ayrılan alandan daha büyükse ve program bunu kontrol etmezse, yığın taşması meydana gelir. Bu durum başlı başına büyük bir güvenlik açığıdır ve kötü amaçlı girdilerle birleştiğinde ciddi sorunlara yol açabilir.
Dinamik (Heap-based) Arabellek Taşması: Dinamik bellek yönetimi için kullanılan alt yığın, genellikle programcıların derleme anında boyutunu önceden bilemeyeceği, gereken bellek miktarının alt yığın boyutuna sığmayacağı veya işlev çağrıları arasında kullanılmak istenen belleği ayırmak için kullanılır. Dinamik bellek tabanlı taşmalar, bir program veya işlem için ayrılmış bellek alanını taşır. Bu tür saldırıları istismar etmek oldukça zor olabilir, bu nedenle yığın tabanlı saldırılara göre daha nadirdir.
ARABELLEK TAŞMASI ÖRNEK PROGRAM
Aşağıda yazmış olduğumuz basit program senaryosu, kullanıcıdan bir şifre girmesini istemekte ve girilen şifrenin doğru olması durumunda kullanıcıya yetkili erişim izni vermektedir.
Şimdi bu programı doğru şifre ile çalıştıralım:
Programa doğru şifre ile giriş yapıldığında beklenen sonuç elde edilmektedir. Fakat yazmış olduğumuz program içerisinde “gets()” fonksiyonu girilen verini sınırlarını denetlememektedir, sonuç olarak arabellek boyutundan daha yüksek veri girişi yapıldığı zaman arabellek taşması meydana gelecektir.
Şimdi de yazmış olduğumuz program bizden şifre talep ettiği zaman doğru şifre yerine rastgele ve normalden çok daha uzun bir veri girdiğimiz zaman ne oluyor ona bakalım:
Yukarıdaki örnekte görüldüğü gibi, yanlış bir şifre girildiğinde dahi, program doğru bir şifre girilmiş gibi davranmaktadır.
Bu örneğin mantığı; arabellegin alabileceğinden daha büyük boyutta bir veri girişinin yapılarak, arabelleğin taşmasına yol açılmasıdır. Bu nedenle, taşan arabellek, kendisini takip eden tam sayının ("integer") üzerine yazmakta ve böylece yanlış bir şifre girmemize rağmen, "pass" tam sayısı ("integer") sıfır olarak kabul edilmeyerek veri girişini yapan kişiye yetkili erişim izni vermektedir.
Arabellek taşmasına yol açabilecek birkaç ileri seviye teknik (kod enjeksiyonu veya kod yürütme gibi) bulunmaktadır. Ancak bu ileri seviye tekniklere geçmeden önce arabelleğin temellerini anlamak ve yukarıda gördüğümüz taşmaların neden ortaya çıktığını bilmek, başlangıç seviyesinde oldukça önemlidir.
Makalenin ilk bölümünde, arabellek (buffer) nedir, arabellek taşması (buffer overflow) nedir ve en yaygın arabellek taşma türleri nelerdir konularını ele aldık. Aynı zamanda, arabellek taşması zafiyetini içeren basit bir program örneği oluşturduk.
Görüldüğü gibi, arabellek taşmasının temel prensiplerini ve neden meydana geldiğini anlamak, ileri seviye istismar tekniklerine geçiş için sağlam bir temel oluşturacaktır.