- Katılım
- 15 Ocak 2026
- Mesajlar
- 31
- Tepkime puanı
- 27
- Puan
- 18
Bir aceminin kendi kendine tuttuğu öğrenme günlüğü – Bölüm 1
yazan: blackrose
Bu yazıyı yazma sebebim, fuzzing öğrenirken yaşadığım kafa karışıklığını ve yaptığım hataları kayıt altına almak. En baştan şunu net söyleyeyim: fuzzing konusunda hâlâ yeniyim. Burada yazdıklarımın bir kısmı eksik olabilir, bazı kavramları yanlış anlamış olabilirim. Zaten amacım “biliyorum” demek değil, öğrenirken gördüklerimi paylaşmak.
Bunu tek parça bir rehber gibi düşünmüyorum. Daha çok, zamanla gelişecek çok bölümlü bir öğrenme serisi. Bu ilk bölümde fuzzing nedir, nasıl başlanır ve benim gözümden süreç nasıl ilerliyor bunları anlatıyorum. Akademik ya da kusursuz bir doküman beklenmemeli. Eğer sen de “Fuzzing nedir?”, “Nereden başlasam?” diye soruyorsan, bu yazı tam olarak o aşama için.
Fuzzing Nedir? (Benim Anladığım Haliyle)
Fuzzing’i kısaca şöyle özetleyebilirim: bir yazılıma tonla girdi veriyorsun ve nasıl davrandığını izliyorsun. Bu girdiler rastgele ya da yarı-akıllı şekilde üretiliyor. Program çöker mi, saçma bir şey yapar mı, beklenmeyen bir hata verir mi diye bakıyorsun. Amaç, güvenlik açıklarına yol açabilecek davranışları yakalamak.
Şu ana kadar fuzzing yaparken en sık karşıma çıkan açık türleri Use After Free, Double Free, heap veya stack buffer overflow, null pointer dereference ve reachable assertion oldu. Elbette bu liste sınırlı değil. Benim şu ana kadar birebir gördüklerim bunlar.
Fuzzing sadece C veya C++ ile yapılan bir şey değil. Ama ben şu an bu dillere odaklanıyorum çünkü pratiğim burada. İleride farklı dillerle de denemeler yapmayı planlıyorum.
Başlarken En Zorlandığım Kısım: Hedef Seçimi
Benim için fuzzing’e başlarken en zor kısım hedef seçmek oldu. Çünkü ciddi bir zaman ve enerji harcıyorsun. Boşa gitmesini istemiyorsun. Bu yüzden scope içinde olan, raporlanabilir ve mümkünse kaynak koduna erişebildiğim projelere yönelmeye çalışıyorum.
Bu noktada özellikle hedef isimleri paylaşmıyorum. Bunun sebebi basit: üzerinde çalışılan projelerin gereksiz yere kapatılmasını istemiyorum. Bu kısmı herkesin kendi araştırması gerektiğini düşünüyorum.
Derleme ve Instrumentation
Hedefi seçtikten sonra ilk işim kaynak kodu almak ve derleme için gereken bağımlılıkları kurmak oldu. Ama asıl kritik nokta derlemenin nasıl yapıldığı. Fuzzing yapacaksan, kodu mutlaka instrumentation ile derlemen gerekiyor.
Instrumentation dediğimiz şey, derleme sırasında koda bazı işaretler eklenmesi. Bu işaretler sayesinde fuzzer, programın hangi kod yollarına ulaştığını anlayabiliyor. Ben AFL++ kullandığım için genelde afl-clang-fast gibi derleyicilerle build alıyorum.
Seed Corpus: Küçük Ama Anlamlı
Başlangıç seed’lerinin ne kadar önemli olduğunu pratikte fark ettim. Çok büyük dosyalar fuzzer’ı ciddi anlamda yavaşlatıyor. Küçük ama hedef formatı iyi temsil eden seed’ler çok daha iş görüyor.
İlk başta basit seed’ler yeterli oluyor ama işin içine girdikçe, daha karmaşık ve gerçekçi girdilerle fuzzing yaptığında kodun derinlerine çok daha hızlı ulaştığını fark ediyorsun.
Harness Kavramıyla Tanışmam
Harness benim için oyunu değiştiren şeylerden biri oldu. Kısaca söylemek gerekirse, C/C++ ile yazılan küçük yardımcı programlar. Tüm uygulamayı fuzzing etmek yerine, doğrudan belirli fonksiyonları çağırıyorsun.
Bu sayede saniye başına çok daha fazla deneme yapabiliyorsun, sistem daha az yoruluyor ve crash bulma ihtimali ciddi şekilde artıyor. Özellikle parsing yapan veya matematik ağırlıklı fonksiyonlar için inanılmaz faydalı.
Tek Build ile Olmuyor
Başta yaptığım en büyük hatalardan biri tek bir build ile fuzzing yapmaktı. Zamanla fark ettim ki bu ciddi bir kayıp. Aynı kütüphaneyi farklı şekillerde derlemek gerekiyor.
Performans odaklı, sanitizer içermeyen build’ler path keşfi için çok iyi. AddressSanitizer içeren build’ler bellek hatalarını yakalamada inanılmaz iş görüyor. Cmplog veya RedQueen gibi mekanizmalar ise klasik mutation’ların geçemediği kontrolleri aşabiliyor. UBSan ve MSan da farklı türde bug’ları yakalamak için ayrı bir dünya.
Multi-Architecture Fuzzing’in Gücü
Farklı mimarilerde fuzzing yapmanın ne kadar önemli olduğunu sonradan fark ettim. ARM, AMD ve Intel için özel yazılmış kodlar olabiliyor. Bir mimaride sorunsuz çalışan bir kod, başka bir mimaride çatır çatır crash verebiliyor.
Bu yüzden mümkün olduğunca farklı CPU mimarilerinde fuzzing yapmak, daha önce kimsenin görmediği açıkları yakalama şansını ciddi şekilde artırıyor.
Bulduğum Bir Crash’e Örnek
Kod:
==12345==ERROR: AddressSanitizer: heap-use-after-free
READ of size 4 at 0x6020000000f0 thread T0
#0 0x40123a in parse_input parser.c:87
#1 0x40189f in main harness.c:42
#2 0x7f2a1c9b5d8f in __libc_start_main
Son Notlar
Bu yazı “kusursuz bir fuzzing rehberi” değil. Aksine, benim kendi öğrenme sürecimin filtresiz bir kaydı. Eğer sen de yeniysen ve kafan karışıksa, yalnız değilsin. Devam eden bölümlerde fuzzer’ı çalıştırma, istatistikleri okuma ve crash triage konularına girmeyi planlıyorum.
— blackrose