Zum Inhalt springen

Services, Wiki-Artikel, Blog-Beiträge und Glossar-Einträge durchsuchen

↑↓NavigierenEnterÖffnenESCSchließen
Security Testing Glossar

Fuzzing - Automatisiertes Schwachstellen-Testing

Fuzzing (Fuzz Testing) ist eine automatisierte Testmethode bei der ein Programm mit massenhaft zufaelligen oder systematisch mutierten Eingaben bombardiert wird um Crashes, Assertions oder unerwartetes Verhalten auszulösen das auf Sicherheitsschwachstellen hinweist. Coverage-guided Fuzzer wie AFL++ und LibFuzzer maximieren Codeabdeckung. Wichtigste Einsatzgebiete: Netzwerkprotokolle, Dateiparser, Browser-Engines, Kryptobibliotheken.

Fuzzing ist eine der effektivsten Methoden um Sicherheitsschwachstellen in Software zu finden, die manuelle Code-Reviews und statische Analyse übersehen. Ein Fuzzer generiert automatisch massive Mengen an Testfällen, sendet sie an das Ziel-Programm und überwacht ob dieses abstürzt, hängt oder unerwartete Fehler produziert - Indikatoren für Buffer-Overflows, Use-After-Free oder andere speicher-basierte Schwachstellen. Google OSS-Fuzz hat mit Fuzzing über 10.000 Schwachstellen in Open-Source-Software gefunden.

Fuzzing-Arten

Fuzzing-Taxonomie:

1. Black-Box-Fuzzing (kein Source-Code-Zugriff):
   → Generiert Inputs ohne Kenntnis der Programmstruktur
   → Einfach zu starten, aber niedrige Code-Coverage
   → Beispiel: zufällige HTTP-Requests an Web-API
   → Tools: Peach Fuzzer, Boofuzz (Netzwerk-Protokolle)

2. Grey-Box-Fuzzing / Coverage-Guided (Stand der Technik):
   → Instrumentiert das Binary → muss Code-Coverage messen
   → Behält Inputs die neue Codepfade entdecken (genetischer Algorithmus!)
   → Exponentiell effizienter als Black-Box
   → Tools: AFL++ (American Fuzzy Lop), LibFuzzer, HonggFuzz

   Ablauf:
   a. Fuzzer startet mit Seed-Corpus (echte Testdateien)
   b. Mutiert Inputs: bit flips, byte swaps, interessante Werte
   c. Führt Programm aus, misst Coverage
   d. Neuer Code-Pfad erreicht? → Input in Corpus behalten!
   e. Kein neuer Pfad? → Input verwerfen
   f. Crash? → Bug gefunden! Input als Crash-Reproducer speichern

3. White-Box-Fuzzing / Symbolic Execution:
   → Analysiert Quellcode + Pfadbedingungen symbolisch
   → Generiert Inputs die exakte Codepfade abdecken
   → Tools: KLEE (LLVM), angr, S2E
   → Sehr rechenintensiv, aber präzise für komplexe Logik

Fuzzing-Kategorien nach Ziel:
  □ Dateiparser: PDF, PNG, MP4, Office-Dokumente → LibFuzzer
  □ Netzwerkprotokolle: HTTP, TLS, DNS, SMB → Boofuzz, Peach
  □ Web-APIs: REST, SOAP, GraphQL → RESTler, CATS
  □ Browser-Engines: V8, SpiderMonkey → Domino, Dharma
  □ Kryptobibliotheken: OpenSSL, BoringSSL → Google OSS-Fuzz
  □ Betriebssystem-Kernel: syscall-Fuzzing → syzkaller
  □ Embedded/IoT: Firmware-Fuzzing → FIRM-AFL, Firmfuzz

Coverage-Guided Fuzzing mit AFL++

AFL++ (American Fuzzy Lop++) - Praxis:

Installation:
  apt install afl++    # Ubuntu
  brew install afl++   # macOS

Schritt 1: Binary instrumentieren (Source verfügbar):
  # C/C++ mit AFL-Compiler-Wrapper:
  CC=afl-clang-fast ./configure
  make
  → Erzeugt instrumentiertes Binary mit Coverage-Tracking

Schritt 2: Seed-Corpus erstellen:
  mkdir seeds/
  echo '{"user":"test"}' > seeds/basic.json
  echo '{"user":"a"}' > seeds/short.json
  # Reale Samples → besserer Start!
  # Tools: afl-cmin (minimiert Corpus)

Schritt 3: Fuzzing starten:
  afl-fuzz -i seeds/ -o findings/ ./target_binary @@
  # @@ = Platzhalter für Eingabedatei
  # -i: Input-Corpus-Verzeichnis
  # -o: Output-Verzeichnis (Crashes, Hangs, Queue)

Schritt 4: Ergebnisse auswerten:
  ls findings/crashes/     → Crash-reproduzierende Inputs!
  ls findings/hangs/       → Inputs die zu Timeouts führen!
  ls findings/queue/       → Coverage-erhöhende Inputs

AFL++-Ausgabe interpretieren:
  execs/sec:    > 500 → gute Performance
  stability:    sollte > 90% sein
  coverage:     wie viele Pfade entdeckt
  crashes:      Anzahl Crashes → sofort analysieren!

Paralleles Fuzzing (mehrere CPU-Kerne):
  # Master:
  afl-fuzz -M fuzzer01 -i seeds/ -o findings/ ./target @@
  # Slaves (Anzahl = CPU-Kerne - 1):
  afl-fuzz -S fuzzer02 -i seeds/ -o findings/ ./target @@
  afl-fuzz -S fuzzer03 -i seeds/ -o findings/ ./target @@
  → Teilen Corpus untereinander → bessere Coverage!

Crash-Analyse:
  # Reproduzieren:
  ./target findings/crashes/id:000001
  # Debuggen mit AddressSanitizer:
  CC=afl-clang-fast ASAN_OPTIONS=... ./configure
  make
  ASAN_OPTIONS=detect_leaks=0 ./target findings/crashes/id:000001

LibFuzzer (Google/LLVM)

LibFuzzer - Für Bibliotheken und Code-Einheiten:

LibFuzzer-Unterschied zu AFL++:
  → LibFuzzer ist in-process: kein neuer Prozess pro Input
  → Schneller (keine fork()-Overhead)
  → Ideal für Bibliotheken/Parser (libpng, zlib, JSON-Parser)
  → Coverage via LLVM SanitizerCoverage

Fuzz-Target schreiben (C/C++):
  // fuzz_target.cpp
  #include <stdint.h>
  #include <stddef.h>
  #include "my_parser.h"

  extern "C" int LLVMFuzzerTestOneInput(
      const uint8_t *Data, size_t Size) {
    // Dieser Code wird mit jedem Fuzzer-Input aufgerufen
    parse_json(Data, Size);
    return 0;  // 0 = kein Crash erwartet
  }

Kompilieren und ausführen:
  clang++ -g -O1 -fsanitize=fuzzer,address \
          fuzz_target.cpp my_parser.cpp -o fuzzer

  ./fuzzer corpus_dir/ -max_len=4096 -jobs=4

  Mit AddressSanitizer (empfohlen!):
  -fsanitize=fuzzer,address,undefined
  → Findet Memory-Bugs + Undefined Behavior

Go-Fuzzing (seit Go 1.18, built-in):
  func FuzzReverse(f *testing.F) {
    f.Add("hello")    // Seed
    f.Fuzz(func(t *testing.T, s string) {
      rev := Reverse(s)
      // Invariante: doppeltes Reverse = Original
      if Reverse(rev) != s {
        t.Errorf("Reverse(%q) = %q, want %q", s, rev, s)
      }
    })
  }
  go test -fuzz=FuzzReverse -fuzztime=60s

Python-Fuzzing (Atheris):
  pip install atheris
  import atheris
  import sys

  @atheris.instrument_func
  def TestOneInput(data):
      fdp = atheris.FuzzedDataProvider(data)
      input_str = fdp.ConsumeUnicodeNoSurrogates(100)
      your_function(input_str)

  atheris.Setup(sys.argv, TestOneInput)
  atheris.Fuzz()

Web-API Fuzzing

REST-API Fuzzing:

Werkzeuge:
  RESTler (Microsoft): automatisches REST-API Fuzzing
    → Liest OpenAPI/Swagger-Spec
    → Generiert Test-Sequenzen basierend auf API-Abhängigkeiten
    → Findet Business-Logic-Fehler, Crashs, Auth-Bypass

  CATS (REST API Fuzzer):
    → OpenAPI-basiert
    → 97+ built-in Fuzz-Tests pro Endpoint
    → Findet: XSS, SQLi, SSRF, Zugriffskontrolle-Fehler

  ffuf (für HTTP-Endpoints):
    # Parameter-Fuzzing:
    ffuf -u 'https://api.example.com/user?FUZZ=value' \
         -w /usr/share/wordlists/common.txt
    # Body-Fuzzing:
    ffuf -u 'https://api.target.com/api/create' -X POST \
         -H 'Content-Type: application/json' \
         -d '{"name": "FUZZ", "type": "user"}' \
         -w mutations.txt

Manuelle Fuzzing-Ansätze (Burp Suite):
  Intruder → Cluster Bomb für mehrere Parameter:
  → Payload 1: Zahlen 0-65535 (Integer-Overflows)
  → Payload 2: Sonderzeichen (<, >, ', ", null-bytes)
  → Kombiniert: alle Parameter-Kombinationen

Interessante Fuzz-Werte:
  Zahlen: 0, -1, 2147483647 (MAX_INT), 2147483648, 9999999999
  Strings: "", null, "null", "\x00", "A"*4096 (Buffer)
  Arrays: [], [null], sehr große Arrays
  Typen: String statt Int, Boolean statt String
  Unicode: "\u0000", Emoji, RTL-Zeichen, sehr lange Strings

Continuous Fuzzing (CI/CD Integration)

OSS-Fuzz (Google) - für Open-Source-Projekte:
  → Google betreibt kontinuierliches Fuzzing für Open-Source
  → 1000+ Projekte: OpenSSL, libjpeg, curl, SQLite, etc.
  → Fuzz-Ergebnisse: 10.000+ Sicherheitslücken gefunden
  → Kostenlos für qualifizierte Open-Source-Projekte

Google ClusterFuzz / FuzzBench:
  → Enterprise-Grade distributed Fuzzing
  → Skaliert auf tausende CPU-Kerne
  → Automatische Crash-Deduplication + Triage

CI/CD Integration (GitHub Actions Beispiel):
  # .github/workflows/fuzzing.yml
  - uses: google/oss-fuzz/infra/cifuzz@master
    with:
      oss-fuzz-project-name: 'myproject'
      fuzz-seconds: 600    # 10 Minuten Fuzzing pro PR

  → Regression-Fuzzing: neuer Code → automatisch gefuzzt
  → Wenn Crash: PR blockiert, Bug-Report erstellt

Best Practices:
  □ Seed-Corpus aus echten Produktionsdaten
  □ AddressSanitizer (ASAN) + UndefinedBehaviorSanitizer (UBSAN) immer aktiviert
  □ Crash-Reproducer speichern + in Regression-Tests aufnehmen
  □ Dictionary für Protokoll-Keywords (verbessert Coverage)
  □ AFL_PRELOAD + afl-cov für Coverage-Reports

Cookielose Analyse via Matomo (selbst gehostet, kein Tracking-Cookie). Datenschutzerklärung