Skip to main content

Welcome to a Grasp lesson

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

Lesson 3

Kontrol Akış Analizi Uygulamaları

Recommended resources

Merhaba, "İleri Seviye Güvenli Kod İnceleme Metodolojisi" modülümüzün üçüncü dersine hoş geldiniz. Önceki dersimizde, güvenilmeyen verinin program içindeki yolculuğunu takip eden Veri Akış Analizi (Data Flow Analysis - DFA) tekniklerini derinlemesine inceledik. Bu analizle, bir verinin programdaki "nerelere" gittiğini ve potansiyel olarak tehlikeli hedeflere (sinks) ulaşıp ulaşmadığını sistematik olarak nasıl belirleyeceğimizi öğrendik.

Bu derste ise merceğimizi verinin kendisinden, programın mantıksal akışına çeviriyoruz. Konumuz, Kontrol Akış Analizi (Control Flow Analysis - CFA). Bu analiz türü, "program hangi yollardan geçerek çalışır?" sorusuna yanıt arar. DFA'nın gözden kaçırabileceği, tamamen programın karar verme mantığındaki hatalardan kaynaklanan kritik zafiyetleri, özellikle kimlik doğrulama ve yetkilendirme atlatma (bypass) gibi kusurları bulmak için CFA vazgeçilmez bir tekniktir. Dersin sonunda, bir programın yürütme mantığını modelleyerek ve analiz ederek güvenlik açısından kritik mantık hatalarını nasıl tespit edeceğinizi öğreneceksiniz.

Kontrol Akış Analizi: Programın Mantık Haritasını Çıkarmak

Veri akış analizi (DFA) verinin programdaki hareketini takip ederken, kontrol akış analizi (CFA) program sayacının (program counter) kendisinin potansiyel hareketini takip eder. Yani, hangi kod bloğundan sonra hangisinin çalışabileceğini, hangi koşulların hangi yürütme patikalarını aktive ettiğini ve hangi kod parçalarının asla çalıştırılamayacağını (ölü kod) anlamamızı sağlar.

Bir önceki derste temelini attığımız Kontrol Akış Grafiği (Control Flow Graph - CFG), CFA'nın temelini oluşturur. Hatırlayacağınız üzere CFG, programın tüm olası yürütme yollarını gösteren bir grafiktir. CFA, bu grafik üzerinde çeşitli algoritmalar çalıştırarak programın davranışını analiz eder.

Bu görsel, basit bir kimlik doğrulama mantığına ait kontrol akış grafiğini (CFG) göstermektedir. `if request.user.is_superuser` gibi karar noktaları (düğümler), programın akışını farklı yollara (kenarlar) yönlendirir. CFA, bu yolların tamamını analiz eder.

Bu konunun teorik altyapısını ve temel kavramlarını daha iyi anlamak için aşağıdaki makaleyi inceleyelim.

How Data and Control Flow Analysis Powers Smarter Static Code ...

Bu blog yazısı, veri ve kontrol akışı analizinin temellerini ve pratik uygulamalarını açıklıyor. Özellikle kontrol akışı analiziyle ilgili bölümleri, konunun özünü kavramak için oldukça yararlıdır.

Lütfen "Control Flow Analysis: Mapping the Execution Path" başlığı altındaki tanımı okuyarak başlayın. Ardından, "Core Concepts and Representations" bölümünün tamamını dikkatle inceleyin. Bu kısımda şu kavramlar açıklanmaktadır: Kontrol Akış Grafikleri (CFG): Analizin temelini oluşturan bu yapının nasıl kurulduğunu pekiştirin. Dallanma ve Yol Hassasiyeti (Branch and Path Sensitivity): Bir analizin bir if bloğunun sadece iki dala ayrıldığını bilmesi (branch-sensitive) ile o dala hangi koşul dizisiyle ulaşıldığını bilmesi (path-sensitive) arasındaki farkı anlamak kritiktir. Güvenlik zafiyetleri genellikle belirli bir yürütme patikasına özgüdür. Prosedürler Arası Kontrol Akışı (Interprocedural Control Flow): Analizin fonksiyon veya metot çağrılarını nasıl takip ederek bütüncül bir akış haritası çıkardığını öğrenin.

Okuduğunuz bölümden de anlaşılacağı üzere, CFA'nın gücü, programın sadece yerel dallanmalarını değil, tüm olası yürütme senaryolarını bir bütün olarak ele alabilmesinden gelir. Özellikle yol hassasiyeti (path sensitivity), güvenlik analizinde hayati bir rol oynar. Bir kod parçasının güvenli olup olmadığı, genellikle o kod parçasına hangi koşullar altında ulaşıldığına bağlıdır.


Pratikte Kontrol Akışı: Mantık Hatalarıyla Gelen CVSS 10.0'lık Zafiyet

Teoriyi bir kenara bırakıp CFA'nın gerçek dünyada ne kadar güçlü olabileceğini somut bir örnekle görelim. pac4j-jwt adlı popüler bir Java kütüphanesinde keşfedilen ve CVSS puanı 10.0 (Kritik) olan bir kimlik doğrulama atlatma zafiyeti, tam olarak bir kontrol akışı hatasından kaynaklanıyordu.

Zafiyetin özeti şu şekildedir: Kütüphane, şifrelenmiş bir JWT (JWE) aldığında, içindeki imzalı JWT'yi (JWS) çıkarıp imzasını doğrulamalıdır. Ancak kodda şöyle bir mantık vardı:

  1. Gelen şifreli token'ı çöz.
  2. İçindeki veri imzalı bir JWT ise, onu ayrıştır. Değilse, null dön.
  3. Ayrıştırılan nesne null değilse, imza doğrulamasını yap.
  4. Kimlik doğrulama sürecine devam et.

Buradaki kritik hata 3. adımdadır. Eğer bir saldırgan, şifreli token'ın içine imzalı bir JWT yerine imzasız bir JWT (PlainJWT) yerleştirirse, 2. adımdaki ayrıştırma işlemi null döner. Bu durumda 3. adımdaki if koşulu false olur ve tüm imza doğrulama bloğu atlanır. Program akışı doğrudan 4. adıma geçer ve kimliği asla doğrulanmamış bir token ile kullanıcıya (örneğin bir admin'e) erişim verilir.

Bu zafiyet, "kirli veri" ile ilgili değildir. Tamamen programın kontrol akışındaki bir varsayım hatasıdır: "Gelen token'ın içi her zaman imzalıdır." Bu varsayım ihlal edildiğinde, güvenlik kontrolü sessizce by-pass edilir.

Aşağıdaki makale, bu zafiyetin keşfedilme sürecini ve teknik detaylarını anlatıyor. Bu, kontrol akışı analizinin önemini gösteren mükemmel bir vak'a çalışmasıdır.

When an AI Code Reviewer Flags a CVSS-10 Authentication Bypass

Bu makale, yapay zeka destekli bir kod inceleme aracının, pac4j-jwt kütüphanesindeki kritik bir kimlik doğrulama zafiyetini nasıl bulduğunu anlatıyor. Zafiyetin temelinde bir kontrol akışı hatası yatmaktadır.

Lütfen aşağıdaki bölümleri sırasıyla okuyun: "The Research Question That Started It" bölümünde, yapay zekanın imza doğrulama bloğunu koruyan bir null kontrolünü nasıl şüpheli bulduğunu okuyun. "How JWT Authentication Is Intended to Work" bölümünü okuyarak JWT kimlik doğrulamasının beklenen kontrol akışını anlayın. "The Code Path That Broke Authentication" bölümü, zafiyetli kod akışını ve signedJWT değişkeni null olduğunda imza doğrulamasının nasıl atlandığını detaylandırıyor. Burası dersimizin ana fikrini somutlaştıran en önemli kısımdır. "Why This Bug Matters Beyond One Library" bölümü, bu tür hataların tek bir kütüphaneye özgü olmayıp, bileşenlerin etkileşimi hakkındaki yanlış varsayımlardan kaynaklanan daha genel bir zafiyet sınıfını temsil ettiğini vurgulamaktadır. Son olarak, "When AI Code Review Exposes Security Assumptions" bölümünü okuyarak, bu tür zafiyetlerin neden geleneksel statik analiz araçları tarafından kaçırılabileceğini ve kontrol akışını derinlemesine anlayan analizlerin neden önemli olduğunu kavrayın.

pac4j örneği, kontrol akışı analizinin neden sadece bir derleyici optimizasyon tekniği olmadığını, aynı zamanda birinci sınıf bir güvenlik aracı olduğunu göstermektedir. DFA, SQL enjeksiyonu gibi veri akışına dayalı zafiyetleri bulmada mükemmeldir. Ancak CFA, program mantığının kendisindeki boşlukları ve hatalı varsayımları bularak yetkilendirme bypass'ları, durum makinesi hataları (state machine errors) ve yarış koşulları (race conditions) gibi daha incelikli zafiyetleri ortaya çıkarır.


CFA'nın Diğer Uygulamaları ve Dinamik Analizle İlişkisi

Kontrol akışı analizinin güvenlikteki tek uygulaması mantık hatalarını bulmak değildir. LINK numaralı kaynakta da belirtildiği gibi, şu gibi pratik faydaları da vardır:

  • Ölü Kod Tespiti (Dead Code Detection): Hiçbir yürütme patikasından ulaşılamayan kod bloklarını tespit eder. Bu bloklar, uygulamanın saldırı yüzeyini gereksiz yere artırabilir, yanıltıcı olabilir ve bakım maliyeti yaratır. LINK numaralı görseldeki gibi analiz araçları, bu tür ölü kodları (Dead Code) görselleştirebilir.
  • Sonsuz Döngü Tespiti (Infinite Loop Detection): CFG'deki döngüleri ve çıkış koşullarını analiz ederek potansiyel DoS (Denial of Service) zafiyetlerini belirleyebilir.
Modern analiz platformları, kontrol ve veri akışı analizini birleştirerek bileşenler arası ilişkileri, bağımlılıkları ve `Dead Code` gibi statik kod durumlarını görselleştirir. Bu, mimari düzeyde güvenlik risklerini anlamayı kolaylaştırır.

Şimdiye kadar tartıştığımız analizler statikti, yani program çalıştırılmadan, kaynak kod üzerinden yapılıyordu. Bir de bu analizin dinamik karşılığı vardır. Özellikle bir önceki derste bahsettiğimiz Program Dilimleme (Program Slicing) tekniğinin dinamik bir versiyonu, kontrol akışı konseptini farklı bir açıdan ele alır.

  • Statik Dilimleme: Belirli bir program noktasını etkileyebilecek tüm kod satırlarını bulur.
  • Dinamik Dilimleme: Belirli bir girdi ile çalıştırılan programda, ilgilenilen bir noktadaki değeri etkileyen kod satırlarını bulur.

Dinamik dilimleme, belirli bir exploit'in veya hatanın kök neden analizini yaparken çok daha küçük ve odaklanmış bir kod dilimi sunar. Aşağıdaki video, bu konsepti pratik bir örnek üzerinden açıklıyor.

Lecture "Program Slicing (Part 4, Dynamic Slicing)" of "Program Analysis"

Michael Pradel'in "Program Analysis" dersinden alınan bu video, dinamik program dilimlemenin ne olduğunu ve statik yaklaşımdan nasıl farklılaştığını anlatıyor.

Lütfen şu kısımları izleyin: Giriş bölümü, dinamik dilimlemenin tanımını yapar ve belirli bir yürütme (execution) için geçerli olduğunu vurgular. Hata ayıklama (debugging) için neden faydalı olduğunu açıklar. "Basit Yaklaşım" bölümü, belirli bir girdi (-1) için programın yürütme geçmişinin (execution history) nasıl çıkarıldığını ve bu geçmiş kullanılarak statik bağımlılık grafiğinin nasıl filtrelendiğini gösterir. Bu, statik ve dinamik analiz arasındaki hibrit bir yaklaşımı sergiler. "Revize Edilmiş Yaklaşım" bölümü, daha hassas bir dilim elde etmek için sadece o yürütmede gerçekleşen bağımlılıkları içeren bir dinamik bağımlılık grafiğinin nasıl oluşturulduğunu ve kullanıldığını anlatır. Bu, saf dinamik analize daha yakındır ve daha kesin sonuçlar verir.


Özet ve Sonraki Adımlar

Bu derste, kod incelemesinde programın mantıksal akışını takip etmenin önemini ve bunun için kullanılan Kontrol Akışı Analizi (CFA) tekniklerini ele aldık.

  • CFA, bir programın tüm olası yürütme yollarını Kontrol Akış Grafiği (CFG) üzerinde modeller.
  • Yol hassasiyeti (path sensitivity) gibi özellikler sayesinde, belirli koşullara bağlı olarak ortaya çıkan karmaşık mantık hatalarını tespit edebilir.
  • pac4j örneğinde gördüğümüz gibi CFA, kimlik doğrulama ve yetkilendirme mekanizmalarındaki kritik zafiyetleri bulmak için vazgeçilmezdir. Bu tür hatalar, genellikle hatalı varsayımlar nedeniyle güvenlik kontrollerinin tamamen atlanmasına yol açar.
  • CFA ayrıca ölü kod tespiti gibi kod kalitesini ve güvenliğini artıran başka pratik uygulamalara da sahiptir.
  • Dinamik dilimleme gibi teknikler, CFA prensiplerini belirli bir yürütme bağlamına uygulayarak hata analizi ve exploit incelemesi gibi durumlarda daha odaklı sonuçlar sunar.

Statik analizin iki temel direği olan Veri Akışı ve Kontrol Akışı analizlerini tamamladık. Artık zafiyetleri bulmak için kullanılan temel teorik araç setine hakimsiniz. Bir sonraki dersimizde bu teorik bilgiyi pratiğe dökecek ve en yaygın zafiyet sınıflarından biri olan enjeksiyon (injection) zafiyetlerinin farklı diller (Java, Python, JavaScript, C#) ve framework'lerdeki somut kod seviyesindeki görünümlerini karşılaştıracağız. Bu, analitik becerilerinizi farklı teknoloji yığınlarına nasıl uygulayacağınızı gösterecek.