Bugünün birbirine bağlı dünyasında, sadece ABD’deki kötü yazılım kalitesinin maliyeti şaşırtıcı bir şekilde 2,41 trilyon dolara ulaştı (kaynak). İster bağlantılı bir araç bilgi-eğlence sistemi, ister tıbbi cihaz, ister kritik endüstriyel altyapı olsun, her şey bir zafiyete bakıyor. Geleneksel uygulama güvenliği test sistemleri, yazılımı tarayarak içindeki “bilinen” zafiyetleri bulmaya ve düzeltmeye odaklıdır. Peki ya “bilinmeyenler”?
Bilinen ve Bilinmeyen Yazılım Zayıflıkları
Kısaca “bug” olarak adlandırdığımız hatalar, kod güvenlik açıklarıdır. Yazılım dünyasında, güvenlik açığı üç farklı türde gelir:
- Tasarım zayıflıkları, yazılımın kendisiyle ilgili sorunlardır. Örneğin, kullanıcıların kimlik doğrulamasını gerektirmeyen bir banka sitesinde ciddi bir tasarım zafiyeti vardır. Genel olarak, tasarım zafiyetleri insanlar tarafından bulunmalı ve giderilmelidir – bu seviyede otomatik araçlar çok güvenmemeliyiz.
- Yapılandırma zafiyetleri, bir yazılımın kurulumu sırasında bir güvenlik açığı olarak ortaya çıkar. Örneğin, varsayılan (fabrikada kurulu) yönetim kimlik bilgileriyle bir veritabanı dağıtmak yapılandırma açığıdır. Konfigürasyon açıklarını tespit etmeye yardımcı olabilecek bazı otomatik araçlar olsa da, arama ve yok etme çalışmalarının çoğu insanlar tarafından yapılmalıdır.
- Kod güvenlik açıkları, “bug”lar. Manuel kodlanmış test vakalarıyla pozitif testler, işlevsellikle ilgili hataları bulmak ve düzeltmek için kullanılabilir. Bu tür tesler, yoğun şekilde otomatikleştirilebilir ve yazılımın dayanıklılığını ve güvenliğini artırmak için kullanılabilir.
Önceden bilinen zafiyetler olduğu gibi bilinmeyen ve sıfırıncı gün zafiyetlerini de unutmamak lazım. Sorumlu yazılım üreticileri bilinen güvenlik açıklarını gidermek için yazılımları için yeni sürümler veya yamalar yayınlar. Fuzzing genellikle bilinmeyen kod zafiyetlerini tespit etmek için kullanılırken, kötü tasarım veya yapılandırmadan kaynaklanan zafiyetleri de tetikleyebilir Nedir bu bilinmeyen zafiyetler?
- Daha kimse tarafından keşfedilmemiş, uykudaki, bilinmeyen zafiyetler.
- Bir kişi, bir ekip veya organizasyon tarafından keşfedilmiş, ama herhangi bir çözüm veya önlem geliştirilmemiş, belki geliştiricisinin de farkında olmadığı, yayınlanmamış sıfırıncı gün zafiyetleri.
Pozitif ve Negatif Testler
Tarihsel olarak, yazılım testleri işlevselliğe odaklanmıştır. Pozitif testler yazılımın olması gerektiği gibi çalışıp çalışmadığına odaklanırlar. İşlevsel testlerde, yani pozitif test türünde, geliştiriciler hedef yazılıma geçerli girdiler sunan ve doğru çıktıyı kontrol eden kod ve çerçeveler oluşturur. Test geliştirme ekibinin, yazılımın spesifikasyonda tanımlandığı gibi çalıştığını doğrulamak için tasarım gereksinimlerini test vakalarına çevirmek gibi oldukça basit bir görevi vardır.
İşlevsel testin önemi yadsınamaz – hedef yazılım, geçerli girdilerle sunulduğunda beklendiği gibi davranmalıdır. Beklenmedik koşullar ve kötü oluşturulmuş girdilerin olduğu kaotik ve saldırgan bir ortamda, sadece pozitif testlere tabi tutulan yazılımlarda çok çeşitli zafiyetler ve açıklar ortaya çıkabilmektedir. Bu nedenle dayanıklılık testlerine ihtiyaç vardır.
Negatif test, yazılıma yanlış veya beklenmedik girdiler göndermek ve arıza kontrolü sürecidir.
Farklı negatif test araçlarının aynı test hedefi için farklı sonuçlar vereceğini unutmayın. Her araç farklı şekilde çalışır ve hedef yazılımda farklı türde kötü oluşturulmuş girdileri test eder.
Siyah, Beyaz ve Gri Kutu Testleri
Kara kutu testlerinde, test aracı hedefin iç bileşenleri hakkında hiçbir bilgiye sahip değildir. Araç, hedefle yalnızca dış arayüzler aracılığıyla etkileşime girer.
Buna karşılık, beyaz kutu aracı hedefin kaynak kodunu kullanarak zafiyetleri arar. Beyaz kutu testi, kaynak kodu taraması gibi statik teknikleri ve kaynak kodunun daha iyi hedef izleme için yeniden oluşturulduğu dinamik testleri kapsar.
Gri kutu aletleri siyah kutu ve beyaz kutu tekniklerini birleştirir. Bu araçlar, hedefin dış arayüzleri aracılığıyla etkileşime girer, ayrıca ek içgörüler için kaynak kodundan da yararlanır.
Statik ve Dinamik Testler
Güvenlik açığı hem statik hem de dinamik test teknikleriyle araştırılır. Olgun bir geliştirme süreci, riski istenen seviyeye indirmek için çeşitli statik ve dinamik tekniklerden yararlanmalıdır.
Statik teknikler, hedef yazılımı çalıştırmadan da kullanılabilir. Bunlar şunları içerir:
- Kaynak kodunun geliştiriciler tarafından incelenmesi. Burada insan gücü ile kaynak kodununun okunması ve bilinmeyen güvenlik açıklarını aranmasıdır. Bu etkili olabilir ama çok yavaştır ve başarı büyük ölçüde insan becerisine bağlıdır.
- Otomatik kaynak kodu analiz araçları, hedef kaynak kodunu tarar ve zayıflık olabilecek programlama kalıplarını raporlar. Bir insan geliştirici, bu taramanın sonuçlarını incelemesine gerek duyar.
- Statik ikili analiz araçları, derlenmiş (çalıştırılabilir) kodu tarar, kütüphaneler ve ilgili bilinen güvenlik açıklarını da dahil ederek sonuçları raporlar.
Dinamik test teknikleri, hedef yazılım çalışırken uygulanır ve aşağıdakileri içerir:
- Yük testi, hedef yazılıma büyük ve çok sayıda girdi göndererek yüksek hacim nedeniyle arızalanıp arızalanmadığını kontrol eder.
- Birlikte çalışabilirlik testi, iki uygulamanın belirli bir protokol, dil veya gösterimi kullanarak iletişim kurabildiğini doğrular.
- Uyumluluk testi, test edilen sistemin ve davranışının ilgili spesifikasyonlara uygun olduğunu doğrular.
- Fuzzing, yazılıma anormal girdiler göndererek arıza olup olmadığını kontrol eder. Bilinmeyenleri bulmak için mükemmel bir yöntemdir
Fuzzing ya da Fuzz Testi Nedir?
Fuzz kelimesi – İngilizce olup Türkçe’ye bulanıklık olarak çevrilebilir – belirsiz, gürültülü veya belirsiz bir şeyi ifade eder. Fuzzing, yazılımlardaki güvenlik açıklarını bulmak için mükemmel bir teknik olarak yerleşmiştir. Temel prensip, yazılıma, kasıtlı olarak yanlış biçimlendirilmiş veya geçersiz girdiler göndererek yazılımın bozulup bozulmadığını kontrol etmek, hataları tesbit etmektir.
Bir başka deyişle, fuzzing, sömürülebilir güvenlik açığını ortaya çıkarabilecek bir hata durumu veya hata tetikleme sürecidir. Fuzzing, hem yazılım geliştiren hem de yazılım kullanan organizasyonlar için yazılım güvenlik açıklarını yönetmede kritik bir araçtır. Fuzzing, yazılımın geçerli veri verildiğinde amaçlanan işlevleri yerine getirdiğini doğrulayan geleneksel “pozitif test”in aksine, hata tetikleme odaklı bir “negatif test” türüdür.
Gerçek dünyanın “dağınık ve tehlikeli” olduğunu, gürültü, geliştirici hataları ve kötü niyetli saldırganların kötü niyetli girdiler sağladığını varsayar. Bu kaosu otomatikleştirmek için, tam bir fuzzer üç kavramsal bileşen kullanır.
- Şair (Poet) – Test Senaryosu Oluşturucu: Hatalı girişleri veya test senaryolarını oluşturur. Bu senaryolarda rastgelelik ve gürültü esastır. Girdiler kesin değildir—gürültülü, şekilsiz veya bozulmuş olurlar, bu yüzden “bulanıktır.” Şair, görevini icra ederken çeşitli teknikler kullanır:
- Rastgelelik ve gürültü: En basit ama çok da etkin olmayan bir tekniktir; hedefe rastgele veri gönderir. Gönderiler, hedef tarafından beklenen formatta olmadığı için, ret edilme olasılıkları yüksektir.
- Şablon (template): Şablon kullanımında, geçerli girdilere anormallikler eklenir. Genel olarak, şablon test vakaları rastgele test vakalarından çok daha etkilidir çünkü çoğunlukla doğrudurlar. Ancak, şablon kullanımının da önemli sınırlamaları vardır. İlki, bir tür bütünlük doğrulaması içeren protokoller için test etkinliği sınırlı olacaktır. İkinci olarak, durumlu (statuful) özellikler içeren protokoller için bir şablon üreticisi protokolün anlamını anlamaz ve anormalleştirilmiş geçerli mesajlarını körü körüne tekrar oynatır. Oturum tanımlayıcıları gibi durumlu özellikleri doğru şekilde ayarlayamaz, bu yüzden bu tür protokolleri test etme etkinliği sınırlıdır. Son olarak, kısmen veya tamamen şifrelenmiş protokoller için doğrudan bir şablon şair kullanılamaz. Kullanılan şablonların kalitesi, sonuçların kalitesini belirler.
- Nesilsel (Generational): Nesilsel bir üretici (şair), test ettiği protokolü, dosya formatını veya API’yi ilgili kuralları bildiği için, sistematik olarak tüm kuralları çiğneyebilir. Ayrıca, nesilsel fuzzer protokol veya giriş türü hakkında tam bilgiye sahip olduğundan, bir şablon şairi şaşırtan durumları doğru bir şekilde ele alabilir. Nesilsel bir fuzzer, oturum tanımlayıcıları gibi durum bilgisi gerektiren özellikleri takip edebilir ve diğer fuzzing teknikleri için sınırlayıcı olabilecek kontrolleri gibi değerleri doğru bir şekilde ayarlayabilir. Nesilsel bir şair, hedefe meşru gibi görünen yüksek kaliteli test materyali oluşturur. Birden fazla mesaj içeren protokoller için bu, nesilsel fuzzere hedefle birkaç geçerli mesaj değiş tokuş etme olanağı sağlar ve anormal test vakasını sunmadan önce hedefi belirli bir duruma yönlendirebilir.
- Evrimsel (Evolutionary): Evrimsel bir şair, sonraki test vakalarının nasıl oluşturulacağını etkilemek için hedefin davranışına ilişkin geri bildirimi kullanır. Hedefin test vakalarına verdiği yanıta ilişkin bazı ölçümler, daha önce hedefe gönderilmiş olan test vakalarını puanlamak için kullanılır. Şair, en yüksek puan alan önceki test vakalarına dayanarak daha fazla test vakası oluşturur. “Saf” bir evrimsel fuzzing aracı bir kara kutu fuzzer’dır. Hedef adresi ve port sağlandığında, evrimsel fuzzer yalnızca hedefin yanıtına dayanarak giderek daha uygun girdiler gönderir.
- Kurye (Courrier) – Test Sürücüsü: Kurye, şair tarafından oluşturulan test vakalarını hedef yazılıma ulaştırmaktan sorumludur. Fuzzing, kendi zorlukları olan çeşitli disiplinleri kapsar.
- Network protokol fuzzing: Fuzzing için yaygın bir uygulama ağ protokolü testidir. Protokol, farklı yazılım parçalarının ağ üzerinden nasıl iletişim kurduğunu gösteren bir kural kümesidir. Protokol mesajlarını yorumlayan kod bir saldırı vektörüdür. Fuzzing, protokol işleme kodunda bilinmeyen açıklıkları bulmak için mükemmel bir tekniktir.
- File fuzzing: Dosya fuzzing’inde, kasıtlı olarak yanlış biçimlendirilmiş dosyalar bir yazılıma teslim edilir. Burada kurye görevini tanımlamak zordur, çünkü farklı yazılımlar dosyaları standart bir şekilde tüketmez. Bazen en iyi yöntem, test vakalarını hedefe etkili şekilde beslemeyi kolaylaştıran özel bir wrapper veya kod yazmaktır
- API fuzzing: API fuzzing, bir Uygulama Programlama Arayüzü’nün (API) çeşitli yöntemleri veya işlevlerinin yanlış biçimlendirilmiş girdiye nasıl yanıt verdiklerini görmek için test edildiği farklı bir hayvandır. Bu durumda kurye, test vakalarından kaynak kod oluşturmalı, (uygunsa) derlemeli ve kodu çalıştırmalı, ardından bir arıza olup olmadığını kontrol etmelidir. DCERPC, SunRPC ve Java RMI gibi uzaktan prosedür çağrıları, API’lerinin ağ protokolü fuzzing’i kapsamına girer. Benzer şekilde, XML/SOAP ve daha modern RESTful/JSON tabanlı uzak API’ler protokol fuzzing olarak değerlendirilmelidir.
- Kullanıcı arayüzü (UI – User Intarface) fuzzing: UI fuzzing, kullanıcı arayüzüne beklenmedik veya hatalı girdiler sağlama işlemidir. Örneğin, geleneksel bir masaüstündeki bir uygulamada, bir fuzzer, ekranın zıt taraflarına neredeyse aynı anda fare tıklamaları gönderebilir. Çoğu modern işletim sistemi ve programlama ortamı, girdi olaylarını programatik olarak iletmenin bir yolunu sağlar, böylece bu tür testler tamamen yazılımda gerçekleştirilebilir. Bununla birlikte, bazı küçük cihazlar için, kullanıcı girdisini fuzzing etmenin tek yolu, düğmelere basabilen mekanik bir cihaz kullanmaktır.
- Kahin (Oracle) – Denetleyici: Kahin, bir test durumunun geçip geçmediğini belirler. Hedefi kontrol ederek bir hatanın meydana gelip gelmediğine bakar. Bir hatanın ne zaman meydana geldiğini bilmek, fuzzing’in başarısı için çok önemlidir. Hedef yazılımınızda hata yaratmak faydalı değildir, eğer hatayı tekrarlanabilir bir şekilde ortaya çıkaramazsanız, düzeltilemez. Kahinin hedefte yaratmaya çalıştığı durumlar şunlardır:
- Çökmeler, performans düşüşleri, hedefin hizmet vermeyi ret etmesi (DoS)
- Sonsuz döngüye girme
- Kaynak sızıntıları veya tükenmesi (belleki CPU, disk vb.)
- Beklenmeyen davranışlar
Çeşitli kahin/oracle yönetemleri mevcuttur. Bunların çalışma yöntemleri, avantaj ve sınırlamalar aşağıda özetlenmiştir.
| Oracle Yöntemi | Nasıl Çalışır? | Avantajları | Sınırlamaları |
| İnsan gözlemi | Deneyimli gözlemci logları ve davranışı izler | Karmaşık, beklenmedik hataları yakalayabilir | Ölçeklenmesi zor, zaman alıcı |
| Geçerli vaka kahini | Geçerli girdi gönderilir, doğru yanıt kontrol edilir | Basit, otomatikleştirilebilir | Bellek sızıntısı gibi ince sorunları yakalayamaz |
| Kaynak izleme (Resource monitoring) | Bellek, CPU, disk kullanımı takip edilir | Otomatikleştirilebilir, SNMP vb. ile entegre edilebilir | İşlevsel hataları yakalayamaz |
| Harici (external script) kahini | Kullanıcı script’leri logları ve süreçleri kontrol eder | Esnek, özelleştirilebilir | Script kalitesine bağlı |
| Dinamik ikili analiz (DBI) | Çalışan yazılımın davranışı izlenir (strace, PageHeap) | Kaynak kod gerekmez, derin analiz sağlar | Performans yükü getirebilir |
| Kaynak kod enstrümantasyonu | Debug sembolleriyle derlenmiş yazılım gdb, valgrind, ASan ile izlenir | Çok hassas hata tespiti | Kaynak kod ve özel derleme gerekir |
| Fonksiyonel/davranışsal kontroller | Protokol veya format kurallarına göre işlevsel hatalar yakalanır | Güvenlik açısından kritik hataları ortaya çıkarır | Kuralların doğru tanımlanması gerekir |
Yukarıdaki tabloda göreceğiniz üzere Oracle yöntemleri birbirini tamamlar. Basit otomatik yöntemler (geçerli vaka, kaynak izleme) hızlıdır; gelişmiş yöntemler (DBI, enstrümantasyon) derinlemesine güvenlik sağlar. En iyi sonuç için hibrit yaklaşım önerilir.
Özetle Fuzzing
Yukarıda yazdıklarımızı özetlemek gerekirse, Fuzzing, yazılımdaki zayıflıkları bulmak için önemli bir yere sahip ve diğer uygulama güvenliği test araçlarında bulunmayan özelliklere sahip olması nedeniyle tamamlayıcı bir araçtır. Temel işlev, hedef yazılıma kasıtlı olarak yanlış şekillendirilmiş girdi iletmek ve arızayı tespit etmektir.
Tam bir fuzzer üç bileşenden oluşur. Bir “şair”, yanlış şekillendirilmiş girdiler veya test vakalarını yaratır. Bir “kurye”, test vakalarını hedef yazılıma teslim eder. Son olarak, bir “kahin” hedef başarısızlıklarını tespit eder. Farklı fuzzing teknikleri, fuzzing etkinliği üzerinde önemli bir etkiye sahiptir. Çoğunlukla, “şair” neredeyse doğru ama bir şekilde anormal test vakaları yaratabildiğinde daha etkilidir. Farklı “kehanet” teknikleri, farklı seviyelerde arıza tespit yeteneği sağlar. Birden fazla kehanet tekniği birlikte kullanılarak maksimum arıza sayısını tespit etmeye yardımcı olabilir.
Fuzzing, yazılım zayıflık yönetiminde hem yazılım üreten kuruluşlar hem de yazılım kullanan kuruluşlar için kritik bir araçtır. Yazılım üreticileri fuzzing’i Güvenli Geliştirme Yaşam Döngüsünün ayrılmaz bir parçası olarak kullanırken, kullanıcılar fuzzing’i doğrulama ve doğrulamada kritik bir araç olarak kullanır. Mali açıdan bakıldığında, fuzzing para tasarrufu sağlar çünkü hataları daha erken düzeltmek çok daha ucuzdur. Üretim senaryolarında bulunan ve muhtemelen istismar edilen hatalar son derece pahalı olabilir.
Bu yazımızda, yazılım güvenliğinde Fuzz Testlerinin gerekliliğinden ve ilgili bazı kavramlardan bahsettik. Bundan sonraki yazımızda Black Duck Defensics Fuzz Testing ürününden, ilgili bir vakadan ve kullanım pratiğinden bahsediyoruz.
Kaynak:
Sorularınız için her zaman Forcerta ile iletişim kurabilirsiniz.
Forcerta Bilgi Teknolojileri A.Ş ISO/IEC 27001:2022 standardının gereklerine uygunluğu açısından belgelendirilmiştir.