Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 2

Çağrı Grafi ve Veri Akışı ile Kod İncelemesi Stratejileri

Recommended resources

Merhaba, önceki dersimizde bilinmeyen bir kod tabanının mimari haritasını çıkarmak için konfigürasyon dosyalarını, routing tanımlarını ve middleware zincirlerini nasıl analiz edeceğimizi öğrenmiştik. Bu yukarıdan aşağıya yaklaşım sayesinde artık elimizde uygulamanın giriş kapılarını, dış dünya ile olan bağlantılarını ve temel güvenlik kontrollerinin nerede olduğunu gösteren bir yol haritası var.

Bu derste ise bir sonraki adımı atarak, bu haritayı kılavuz olarak kullanıp kodun derinliklerine nasıl ineceğimize odaklanacağız. Manuel kod analizi yaparken kullanabileceğimiz iki temel ve güçlü stratejiyi masaya yatıracağız: çağrı grafi (call-graph) ve veri akışı (data-flow) odaklı analiz. Bu iki yaklaşımın ne olduğunu, ne zaman ve nasıl kullanılacağını, güçlü ve zayıf yönlerini karşılaştırarak, belirli bir analiz görevi için hangi stratejinin daha uygun olduğunu seçme yeteneğinizi geliştireceğiz. Bu, otomatize araçların göremediği mantıksal zafiyetleri tespit etme yolunda "uzman gözünü" keskinleştirmenin temel taşlarından biridir.

Kod Analizinin İki Merceği: Kontrol ve Veri

Bir kod tabanını incelerken, onu iki farklı mercekten görebiliriz: programın nasıl çalıştığı (kontrol akışı) ve verinin program içinde nasıl hareket ettiği (veri akışı). Güvenlik analizi de bu iki temel perspektif etrafında şekillenir.

Bu görsel, bir uygulamanın analizini iki ana eksende soyutlar: **Kontrol Akışı (Control Flow)**, programın hangi kod yollarını izlediğini ve hangi fonksiyonların yürütüldüğünü incelerken; **Veri Akışı (Data Flow)**, verinin uygulama içindeki yolculuğuna odaklanır.
  1. Kontrol Akışı Analizi (Çağrı Grafi Yaklaşımı): Bu strateji, "Bu kod ne yapıyor ve hangi koşullar altında çalışıyor?" sorusuna cevap arar. Bir isteğin giriş noktasından (örneğin bir controller metodu) başlayarak, hangi fonksiyonların hangi sırayla çağrıldığını takip ederiz. Bu, uygulamanın yürütme mantığını ve karar mekanizmalarını anlamamızı sağlar. Matematiksel bir bakış açısıyla, bunu fonksiyonların düğüm (node), fonksiyon çağrılarının ise yönlendirilmiş kenar (directed edge) olduğu bir graf olarak düşünebilirsiniz.

  2. Veri Akışı Analizi (Taint Analizi Yaklaşımı): Bu strateji ise "Güvenilmeyen veri nereden gelip nereye gidiyor?" sorusuna odaklanır. Kullanıcıdan veya harici sistemlerden gelen "kirli" (tainted) veriyi, tehlikeli bir işlevin (sink) kullanabileceği son noktaya kadar izleriz. Amaç, bu verinin yol boyunca yeterince temizlenip temizlenmediğini (sanitization) veya doğrulanıp doğrulanmadığını (validation) tespit etmektir.

Şimdi bu iki stratejiyi daha derinlemesine inceleyelim.


Strateji 1: Çağrı Grafi (Call-Graph) Odaklı Analiz

Çağrı grafi analizi, bir işlevin mantığını anlamak için onu çağıran ve onun tarafından çağrılan diğer işlevlerle olan ilişkisini haritalamaktır. Bu, özellikle iş mantığı, kimlik doğrulama ve yetkilendirme gibi durum ve koşula bağlı zafiyetleri bulmak için son derece etkilidir.

Ne Zaman Kullanılır?

  • Kimlik Doğrulama ve Yetkilendirme Atlatmaları (Auth Bypass): Bir yetkilendirme kontrolünün (örneğin bir middleware veya decorator) belirli kod yollarında neden uygulanmadığını veya atlandığını anlamak için idealdir.
  • İş Mantığı Hataları (Business Logic Flaws): Çok adımlı bir sürecin (örneğin, bir sipariş tamamlama akışı) durumlarını ve bu durumlar arasındaki geçişleri analiz ederek, istenmeyen veya yasadışı durum geçişlerini tespit etmek için kullanılır.
  • Yarış Koşulları (Race Conditions) ve TOCTOU: Kritik bir kaynağa erişimden önce yapılan kontrol (Time-of-Check) ile kaynağın kullanıldığı an (Time-of-Use) arasında başka bir işlemin araya girip giremeyeceğini anlamak için kodun yürütme sırasını takip etmek gerekir.

Pratik Bir Örnek: Yetkilendirme Mantığı Atlatma

Bir middleware'in belirli URL'ler için kimlik doğrulaması gerektirdiğini, diğerleri için ise gerektirmediğini düşünün. Çağrı grafi analizi, bu kararın verildiği if-else bloğuna odaklanır. Saldırganın bu if koşulunu atlatarak kimlik doğrulaması gerektiren bir fonksiyona erişip erişemeyeceğini bu şekilde analiz ederiz.

Aşağıdaki video, bu tür bir kontrol akışı zafiyetine harika bir örnektir.

ChatGPT vs Hacker ! SonarSource Kaynak Kod Analizi ile Zafiyet Tespiti Challenge'ı

Mehmet İnce'nin "ChatGPT vs Hacker" videosunda, basit bir kontrol akışı hatasından kaynaklanan bir yetkilendirme atlatma zafiyetini incelediği bölümü izleyelim.

Lütfen videodaki JavaScript örneğini izleyin. Burada kodun, URL'in /api/ ile başlayıp başlamadığını kontrol ettiğini göreceksiniz. Analist, bu kontrolün büyük/küçük harf duyarlılığı veya URL normalizasyonu gibi durumları nasıl ele aldığını sorgulayarak bir kontrol akışı analizi yapar. Zafiyet, verinin kendisinden çok, veriye dayalı olarak hangi kod yolunun izlendiğiyle ilgilidir.

Sınırlılıkları:
Çağrı grafi analizi, özellikle büyük ve karmaşık projelerde çok "gürültülü" olabilir. Birçok farklı yerden çağrılan merkezi bir yardımcı fonksiyon, grafı okunmaz hale getirebilir. Ayrıca, bu yaklaşım doğası gereği verinin kendisini takip etmez, bu nedenle enjeksiyon tipi zafiyetleri bulmak için tek başına genellikle yetersizdir.


Strateji 2: Veri Akışı (Data-Flow) Odaklı Analiz

Veri akışı analizi, modern web uygulamalarındaki en yaygın zafiyet sınıflarından biri olan enjeksiyon saldırılarını bulmak için en etkili manuel tekniktir. Bu yaklaşım, genellikle "taint analizi" olarak da bilinir ve üç temel bileşenden oluşur:

  • Kaynak (Source): Güvenilmeyen verinin uygulamaya girdiği nokta. Örnekler: HTTP istek parametreleri, dosya yüklemeleri, veritabanından okunan veriler, harici API'lerden gelen yanıtlar.
  • Hedef (Sink): "Kirli" verinin tehlikeli bir eyleme neden olabileceği işlev veya konum. Örnekler: SQL sorgu çalıştıran fonksiyonlar (cursor.execute()), işletim sistemi komutu çalıştıran fonksiyonlar (os.system()), bir HTML sayfasında render edilen değişkenler.
  • Veri Akış Yolu (Data Flow Path): Verinin kaynaktan hedefe ulaşana kadar izlediği yol. Bu yol üzerindeki temizleyiciler (sanitizers) ve doğrulayıcılar (validators), zafiyetin var olup olmadığını belirler.
Bu diyagram, veri akışı analizinin temel mantığını özetler: Güvenilmeyen bir kaynaktan (örn. HTTP GET isteği) gelen verinin, tehlikeli bir hedefe (örn. veritabanı sorgusu) ulaşıp ulaşmadığı izlenir.

Ne Zaman Kullanılır?

  • Enjeksiyon Zafiyetleri: SQL Injection, Cross-Site Scripting (XSS), Sunucu Taraflı İstek Sahteciliği (SSRF), Komut Enjeksiyonu (Command Injection) gibi zafiyetlerin neredeyse tamamı, kirli verinin hedefe temizlenmeden ulaşmasıyla ortaya çıkar.
  • Veri Sızıntıları: Hassas bir verinin (örneğin parola, API anahtarı) kaynaktan çıkıp bir log dosyası veya HTTP yanıtı gibi istenmeyen bir hedefe gidip gitmediğini takip etmek için kullanılır.

Pratik Örnekler: XSS ve SSRF

Aynı videodan, bu kez veri akışı odaklı iki klasik zafiyet örneğini inceleyelim.

ChatGPT vs Hacker ! SonarSource Kaynak Kod Analizi ile Zafiyet Tespiti Challenge'ı

Şimdi, aynı videoda veri akışının kritik olduğu iki farklı senaryoyu görelim. Birinde kullanıcı girdisi doğrudan HTML çıktısına yansırken, diğerinde bir URL oluşturmak için kullanılıyor.

İlk olarak, Java'daki Stored XSS örneğini izleyin. Burada "kaynak", kullanıcıdan alınan comment verisidir. Veri, hatalı bir replace işleminden (sözde sanitizer) geçtikten sonra doğrudan HTML çıktısına ("hedef") yazılır. Analistin görevi, bu akışı takip ederek temizlemenin yetersiz olduğunu kanıtlamaktır. Ardından, C#'taki Open Redirect/SSRF örneğine bakın. Bu daha karmaşık bir veri akışıdır. Kullanıcıdan gelen path parametresi ("kaynak"), bir iç API'ye istek göndermek için kullanılacak olan URL'in ("hedef") bir parçası haline gelir. Buradaki kritik soru şudur: Kullanıcı tarafından kontrol edilen bu veri, URL'in yapısını değiştirerek isteğin hedefini istenmeyen bir sunucuya yönlendirebilir mi?

Sınırlılıkları:
Veri akışını manuel olarak takip etmek, özellikle birçok katman (frontend, backend, microservice'ler) içeren modern uygulamalarda son derece zorlayıcı olabilir. Analist, odağını tek bir veri parçasına kilitlediği için genel iş mantığı hatalarını veya yetkilendirme sorunlarını gözden kaçırabilir.


Stratejileri Karşılaştırma ve Doğru Yaklaşımı Seçme

Peki, bir kod analizine başlarken hangi stratejiyi seçmelisiniz? Cevap, hedefinize ve kodun bağlamına bağlıdır. Çoğu zaman en etkili yöntem, bu iki stratejiyi birleştirmektir.

Strateji Odak Noktası Güçlü Yönleri Tipik Zafiyetler
Çağrı Grafi (Kontrol Akışı) Kodun ne yaptığı, yürütme mantığı. Mantık hataları, durum yönetimi, erişim kontrolü. Yetkilendirme atlatma, iş mantığı hataları, TOCTOU.
Veri Akışı (Taint Analizi) Verinin nereye gittiği, kirlilik takibi. Tüm enjeksiyon türleri, veri sızıntıları. SQLi, XSS, SSRF, Command Injection, Log Injection.

Hibrit Yaklaşım: Uzmanın Stratejisi
Tecrübeli bir güvenlik analisti, bu iki merceği duruma göre değiştirerek kullanır. İşte tipik bir hibrit iş akışı:

  1. Mimari Haritalama (Önceki Ders): Önceki derste öğrendiğimiz gibi, uygulamanın giriş noktalarını ve ana bileşenlerini belirleyin.
  2. Geniş Keşif (Çağrı Grafi): Hassas bir işlevselliğe sahip bir controller (örneğin, AdminController) seçin. Bu controller'daki metotların hangi servisleri çağırdığını, hangi yardımcı fonksiyonları kullandığını anlamak için çağrı grafiği yaklaşımını kullanın. Bu size "ilginç" görünen kod bölgelerini (örneğin, karmaşık bir yetki kontrolü, dosya işleme, şifreleme) belirlemenizde yardımcı olur.
  3. Odaklanmış Dalış (Veri Akışı): "İlginç" olarak belirlediğiniz bu kod parçasına kullanıcıdan gelen bir verinin ulaşıp ulaşmadığını kontrol edin. Eğer ulaşıyorsa, merceğinizi veri akışına çevirin ve bu verinin son durağına kadar izini sürün.

Örneğin, bir profil resmi yükleme işlevini analiz ediyorsunuz.

  • Çağrı Grafi: ProfileController'daki uploadAvatar metodundan başlayarak ImageService -> FileStorageHelper gibi çağrıları takip edersiniz. FileStorageHelper'ın dosyayı diske yazdığını görürsünüz.
  • Veri Akışı: Şimdi merceği değiştirirsiniz. Kullanıcının yüklediği dosyanın adı (filename) ve içeriği (content) "kirli" verilerdir.
    • filename verisi, dosya yolu oluşturmak için kullanılıyor mu? ../../ gibi karakterler temizleniyor mu? (Path Traversal riski).
    • content verisi, sunucuda işlenmeden önce doğrulanıyor mu? (Örn. bir "image bomb" veya zararlı bir SVG dosyası).
    • Resim daha sonra bir sayfada gösterildiğinde, content-type başlığı doğru ayarlanıyor mu? Veya bir XSS'e yol açabilir mi?

Bu hibrit yaklaşım, hem geniş resmi görmenizi hem de gerektiğinde en ince ayrıntıya kadar inmenizi sağlar.


Sonuç

Bu derste, bir mimari haritası çıkardıktan sonra kodun derinliklerine inmek için kullanabileceğimiz iki temel manuel analiz stratejisini öğrendik.

Temel Çıkarımlar:

  • Çağrı Grafi Analizi, kodun yürütme mantığına odaklanır ve "kod ne yapıyor?" sorusuna cevap arar. Özellikle yetkilendirme, iş mantığı ve durum yönetimiyle ilgili zafiyetleri bulmak için güçlüdür.
  • Veri Akışı Analizi, güvenilmeyen verinin uygulama içindeki yolculuğuna odaklanır ve "veri nereye gidiyor?" sorusuna cevap arar. Enjeksiyon tipi zafiyetleri bulmak için en etkili yöntemdir.
  • Bir uzman, bu iki stratejiyi tek başına kullanmak yerine, hedefine göre aralarında geçiş yaptığı veya birleştirdiği hibrit bir yaklaşım benimser. Önce genel mantığı anlamak için çağrı grafiği, ardından belirli bir riskli bölgedeki veri akışını izlemek için veri akışı analizi kullanılır.

Artık elimizde hem bir mimari haritası hem de bu harita üzerinde hareket etmek için iki temel strateji var. Bir sonraki dersimizde, bu stratejileri uygulayacağımız en kritik yerlerden birine odaklanacağız: güven sınırları. Özellikle servisler arası iletişim ve dolaylı veri akışları gibi modern mimarilerde ortaya çıkan örtük ve gizli güven sınırlarını kodda nasıl tespit edeceğimizi öğreneceğiz.