Wireshark für Blue Teams: die Filter, die im Vorfall zählen

Kurzfassung: Wireshark zeigt jedes Byte eines Mitschnitts; Display-Filter machen daraus in Minuten eine Antwort. Die wichtigsten: ip.addr für ein System, tcp.flags.syn == 1 && tcp.flags.ack == 0 für Verbindungsaufbauten, dns.flags.response == 0 für Anfragen, tls.handshake.type == 1 für TLS mit SNI, smb2.tree contains "ADMIN$" für seitliche Bewegung, tcp.stream eq N für eine Verbindung. Der Ablauf: Statistik, eingrenzen, Stream folgen, Objekte exportieren, Beweismittel mit Hash sichern. Zeek findet die Verbindung, Wireshark zeigt, was drin war.

Wireshark-Filter entscheiden darüber, ob ein Paketmitschnitt in einer Stunde eine Antwort liefert oder in drei Tagen keine. Ein Mitschnitt von zehn Minuten an einem Firmennetz enthält Millionen Pakete, und die Frage im Vorfall ist nie „was ist im Netz passiert“, sondern „hat dieses System mit dieser Adresse gesprochen, was wurde übertragen, und wann“. Dieser Beitrag ist als Referenz gedacht: die Display-Filter, die im Vorfall und beim Hunting tatsächlich gebraucht werden, nach Aufgabe sortiert, dazu der Arbeitsablauf vom Mitschnitt zur Zeitlinie, tshark für die Kommandozeile und die Grenzen des Werkzeugs. Versionsstand: Wireshark 4.x.

Wireshark oder Zeek

Beide sehen dasselbe Netz, aber sie beantworten verschiedene Fragen. Zeek läuft dauerhaft, fasst zusammen und liefert Logs: welche Verbindungen es gab, welche Domains aufgelöst wurden, welche Zertifikate gesehen wurden. Wireshark öffnet einen einzelnen Mitschnitt und zeigt jedes Byte jedes Pakets. Der Arbeitsablauf im SOC ist deshalb fast immer derselbe: Zeek oder das SIEM zeigen, welche Verbindung verdächtig ist, und Wireshark zeigt, was in ihr steckt. Wer mit Wireshark einen Mitschnitt von mehreren Gigabyte ohne Vorauswahl öffnet, hat das Werkzeug falsch herum benutzt.

Grundlagen der Display-Filter

Wireshark kennt zwei Filterarten. Capture-Filter in BPF-Syntax entscheiden beim Mitschneiden, was überhaupt gespeichert wird, und sind knapp gehalten: host 10.0.0.5, port 53, not port 443. Display-Filter arbeiten auf einem vorhandenen Mitschnitt und kennen jedes Feld jedes Protokolls, das Wireshark dekodiert, mehrere hunderttausend. Die Syntax: Feld, Operator, Wert. == und != für Gleichheit, contains für Teilstrings, matches für reguläre Ausdrücke, &&, || und ! für die Verknüpfung, in {a b c} für Mengen. Der schnellste Weg zum richtigen Feldnamen ist der Rechtsklick auf ein Feld im Paketdetail und „Als Filter anwenden“; Wireshark schreibt den Filter dann selbst.

Die Filter nach Aufgabe

Überblick verschaffen

FilterZeigt
ip.addr == 10.0.0.5Alles von und zu einem System
!(arp || dns || icmp || ssdp || mdns)Das Rauschen weg, den Rest sehen
tcp.flags.syn == 1 && tcp.flags.ack == 0Jeden Verbindungsaufbau: Wer spricht wen an
!(ip.dst == 10.0.0.0/8 || ip.dst == 172.16.0.0/12 || ip.dst == 192.168.0.0/16)Nur ausgehender Verkehr ins Internet
tcp.analysis.flagsRetransmissions, Resets und andere Auffälligkeiten, bei Scans und Tunneln häufig

DNS

FilterZeigt
dns.flags.response == 0Nur Anfragen, ohne Antworten
dns.qry.name.len > 50Sehr lange Namen: Tunneling und kodierte Daten
dns.flags.rcode != 0Fehlgeschlagene Auflösungen, bei Domain-Generierungsalgorithmen in Serie
dns.qry.type == 16TXT-Anfragen, ein beliebter C2-Kanal
dns.qry.name contains "pastebin"Anfragen zu einer bestimmten Domain oder einem Muster

HTTP und TLS

FilterZeigt
http.requestAlle HTTP-Anfragen mit Methode, Host und URI
http.request.method == "POST"Uploads: Datenabfluss und C2-Antworten
http.user_agent contains "python" || http.user_agent contains "curl"Werkzeuge statt Browser
http.request.uri contains ".exe" || http.content_type contains "octet-stream"Downloads ausführbarer Dateien
tls.handshake.type == 1ClientHello: jeder TLS-Verbindungsaufbau mit SNI und Cipher-Liste
tls.handshake.extensions_server_name contains "example"Verbindungen zu einem Hostnamen, auch wenn der Inhalt verschlüsselt ist
tls.handshake.type == 1 && !tls.handshake.extensions_server_nameTLS ohne SNI: häufig direkte Verbindungen zu C2-Adressen
tls.handshake.ja3 == "..."Verbindungen mit einem bestimmten Client-Fingerabdruck

Anmeldungen und seitliche Bewegung

FilterZeigt
smb2.tree contains "ADMIN$" || smb2.tree contains "C$"Zugriffe auf administrative Freigaben: PsExec, Werkzeuge kopieren
smb2.filename contains ".exe" || smb2.filename contains ".ps1"Ausführbare Dateien über Freigaben
dcerpcRPC-Aufrufe: Dienste starten, WMI, Remote-Registry
ntlmssp.auth.usernameJede NTLM-Anmeldung mit Benutzername
kerberos.CNameStringKerberos-Anfragen mit dem anfragenden Konto
kerberos.etype == 23RC4-Verschlüsselung in Kerberos: Kerberoasting und alte Clients
kerberos.msg_type == 30Kerberos-Fehler in Serie: fehlgeschlagene Anmeldungen, Enumeration
ldap.filter contains "servicePrincipalName"LDAP-Abfragen nach Dienstkonten, der Schritt vor dem Kerberoasting
tcp.port == 3389RDP-Verbindungen, mit Quelle und Ziel

Command-and-Control und Datenabfluss

FilterZeigt
tcp.stream eq 42Eine einzelne Verbindung von Anfang bis Ende
ip.src == 10.0.0.5 && tcp.len > 0Nur Pakete mit Nutzdaten von einem System: Was schickt es hinaus
dataNutzdaten, die Wireshark keinem Protokoll zuordnen kann: eigene Protokolle, Verschleierung
icmp && frame.len > 128Ungewöhnlich große ICMP-Pakete: Tunneling
frame.time_delta_displayed > 59 && frame.time_delta_displayed < 61Nach Filterung auf eine Verbindung: Pakete im 60-Sekunden-Takt, das Muster eines Beacons

Der Arbeitsablauf vom Mitschnitt zur Zeitlinie

  1. Statistik zuerst. Unter Statistiken die Protokollhierarchie für den Anteil der Protokolle, dann Verbindungen und Endpunkte, sortiert nach Bytes: Die größten Verbindungen und die unbekannten Adressen sind der Einstieg.
  2. Eingrenzen. Ein Filter auf das verdächtige System, dann das Rauschen weg, dann die Frage: neue Verbindungen, DNS, HTTP, TLS-Handshakes.
  3. Stream folgen. Rechtsklick auf ein Paket, Folgen, TCP-Stream: die ganze Unterhaltung als Text. Bei HTTP ist das die Anfrage samt Antwort, bei unbekannten Protokollen oft der erste Hinweis, was das ist.
  4. Objekte exportieren. Datei, Objekte exportieren, HTTP oder SMB: Wireshark rekonstruiert übertragene Dateien aus dem Verkehr. Das nachgeladene Werkzeug, das Dokument mit Makro, die abgeflossene Tabelle, mit Hash für die weitere Analyse.
  5. Markieren und exportieren. Relevante Pakete markieren, als eigenen Mitschnitt speichern, mit Hash ins Vorfallprotokoll. Der kleine Mitschnitt ist das Beweismittel, das große bleibt archiviert. Wie das in die Beweiskette passt, steht dort.

Zwei Einstellungen sparen im Vorfall Zeit: die Zeitanzeige auf absolute Uhrzeit umstellen, damit sich Pakete mit Logs abgleichen lassen, und ein eigenes Profil mit Spalten für SNI, HTTP-Host und User-Agent, das beim nächsten Mal schon da ist. Für die Zuordnung von Adressen zu Ländern und Netzbetreibern binden die GeoIP-Datenbanken von MaxMind zusätzliche Felder ein, die als Filter und Spalte verfügbar sind.

Ein Blue-Team-Profil einrichten: Schritt für Schritt

Wireshark speichert Spalten, Farbregeln, Filterschaltflächen und Einstellungen in Profilen. Ein eigenes Profil für die Vorfallanalyse ist in zwanzig Minuten gebaut, lässt sich als Ordner exportieren und im Team teilen, und spart ab dem ersten echten Mitschnitt mehr Zeit, als es gekostet hat.

  1. Profil anlegen. Bearbeiten, Konfigurationsprofile, Neu, Name „Blue Team“. Alles Weitere gilt nur für dieses Profil; das Standardprofil bleibt unangetastet.
  2. Zeitformat. Ansicht, Zeitanzeigeformat, „Datum und Uhrzeit des Tages“ und dazu UTC, wenn das SIEM in UTC arbeitet. Die Zeit ist das Feld, über das Pakete mit Eventlogs zusammenkommen; wer hier mit relativen Sekunden arbeitet, rechnet im Vorfall von Hand.
  3. Spalten. Bearbeiten, Einstellungen, Spalten. Zusätzlich zu Quelle und Ziel drei benutzerdefinierte Spalten mit dem Typ „Custom“ und den Feldern tls.handshake.extensions_server_name für den SNI, http.host und http.user_agent, dazu tcp.stream für die Verbindungsnummer. Diese vier Spalten beantworten beim Scrollen die häufigsten Fragen, ohne dass ein Paket geöffnet werden muss.
  4. Filterschaltflächen. Rechts neben der Filterzeile das Plus: Jede Schaltfläche bekommt einen Namen und einen Filter aus den Tabellen oben. Acht reichen: Rauschen weg, neue Verbindungen, nur DNS-Anfragen, nur HTTP-Anfragen, TLS-Handshakes, Admin-Freigaben, Kerberos-Fehler, ausgehend ins Internet. Die Schaltflächen lassen sich in Gruppen ordnen, etwa „Überblick“ und „Seitlich“.
  5. Farbregeln. Ansicht, Färbungsregeln. Zwei eigene Regeln ganz oben: Rot für smb2.tree contains "$" || tcp.port == 3389, Orange für dns.qry.name.len > 50 || (tls.handshake.type == 1 && !tls.handshake.extensions_server_name). Farbregeln werden von oben nach unten ausgewertet; die eigenen müssen über den mitgelieferten stehen.
  6. Protokolleinstellungen. Bei TCP „Allow subdissector to reassemble TCP streams“ aktiviert lassen, sonst fehlen exportierbare Objekte. Bei TLS den Pfad zu einer Datei mit Sitzungsschlüsseln eintragen, falls das Lab Schlüssel aus Browsern mitschreibt; im Vorfall bleibt das Feld leer.
  7. GeoIP. Bearbeiten, Einstellungen, Name Resolution, MaxMind-Datenbankverzeichnis. Danach stehen ip.geoip.dst_country und ip.geoip.dst_asnum als Filter und Spalte bereit, und „ausgehend nach Ländern“ wird zu einer Zeile in der Statistik.
  8. Exportieren. Das Profilverzeichnis liegt im persönlichen Konfigurationsordner von Wireshark und lässt sich als ZIP im Team-Repository ablegen. Wer in der Notfallkiste einen Wireshark mit diesem Profil hat, fängt beim Kunden nicht bei null an.

Eine Analyse durchgespielt: vom Alarm zum exportierten Objekt

Ausgangslage: Zeek meldet im conn.log, dass der Client 10.10.10.21 in den letzten zwei Stunden 140 Verbindungen zu derselben externen Adresse auf Port 443 aufgebaut hat, jede mit wenigen hundert Bytes. Der Netzwerksensor hat den Zeitraum als Mitschnitt vorgehalten. So läuft die Analyse in Wireshark:

  1. Eingrenzen. ip.addr == 10.10.10.21 && ip.addr == 203.0.113.50. Aus zwei Millionen Paketen werden 3.200. In der Statistik unter Verbindungen zeigt die TCP-Ansicht 140 Ströme mit fast identischer Größe, und die Zeitspalte zeigt Abstände von 60 Sekunden mit wenigen Sekunden Streuung. Das ist das Muster eines Beacons.
  2. Den Handshake ansehen. tls.handshake.type == 1 dazu: Der ClientHello hat keinen SNI, und der JA3-Fingerabdruck in tls.handshake.ja3 ist bei allen 140 Verbindungen identisch. Ein Browser würde einen Hostnamen senden; dieser Client tut es nicht. Der Fingerabdruck wandert als Indikator ins Vorfallprotokoll.
  3. Zurück zum Anfang. Das erste Paket zu dieser Adresse liegt um 13:42 Uhr. Was ist davor passiert? Filter zurück auf ip.addr == 10.10.10.21 und Zeitbereich 13:30 bis 13:45: um 13:41 eine DNS-Anfrage für eine Domain, die der Client nie zuvor aufgelöst hat, und direkt danach eine HTTP-Verbindung auf Port 80 zu einer anderen Adresse.
  4. Stream folgen. Rechtsklick auf das HTTP-Paket, Folgen, TCP-Stream. Die Anfrage ist ein GET auf einen Pfad, der mit .zip endet, der User-Agent ist eine PowerShell-Kennung, die Antwort ist 200 mit application/octet-stream und 412 KB. Um 13:41 hat also eine PowerShell eine Datei geladen, und eine Minute später begann das Beaconing.
  5. Objekt exportieren. Datei, Objekte exportieren, HTTP: Die Liste zeigt die ZIP-Datei mit Hostname, Größe und Inhaltstyp. Speichern in das Beweisverzeichnis, SHA-256 berechnen, Hash ins Protokoll. Der Hash geht an die Sandbox und an die Threat-Intelligence-Abfrage; im Vorfall reicht für die Entscheidung schon, dass eine PowerShell ein ZIP von einer unbekannten Domain geladen hat.
  6. Endpunkt einbeziehen. Mit der Uhrzeit 13:41 und dem Prozessnamen aus dem User-Agent wird auf dem Client gesucht: Sysmon Event 1 zeigt die PowerShell mit kodiertem Befehl, gestartet von winword.exe, und Sysmon Event 3 die Verbindung zur Beacon-Adresse aus einem Prozess, der aus dem Temp-Verzeichnis läuft. Die Kette ist geschlossen: Dokument, Makro, PowerShell, Download, Beacon.
  7. Beweismittel sichern. Alle Pakete der beiden Verbindungen markieren, Datei, Spezifizierte Pakete exportieren, nur markierte, als eigenen Mitschnitt speichern, Hash ins Protokoll. Der große Mitschnitt bleibt archiviert, der kleine ist das Beweismittel, das in den Bericht und an die Forensik geht.

Zeit für den ganzen Ablauf mit vorbereitetem Profil: etwa zwanzig Minuten. Ohne Profil, ohne die Filter und ohne die Gewohnheit, mit der Statistik zu beginnen, dauert dieselbe Analyse einen Nachmittag, und der Schritt zurück zum ersten Paket wird oft vergessen. Aus dem Ergebnis entstehen drei Dinge: der Host wird isoliert, die Beacon-Adresse und die Download-Domain werden gesperrt und als Indikatoren geteilt, und aus dem JA3-Fingerabdruck und dem TLS-ohne-SNI-Muster wird eine Regel im Netzwerksensor, die den nächsten Client mit demselben Beacon meldet, bevor jemand einen Mitschnitt öffnen muss.

tshark für die Kommandozeile

Was in der Oberfläche ein Klick ist, wird mit tshark wiederholbar und auf große Mitschnitte anwendbar. Dieselben Display-Filter, dieselben Feldnamen:

Shell
# Alle abgefragten DNS-Namen, nach Häufigkeit
tshark -r mitschnitt.pcap -Y "dns.flags.response == 0" -T fields -e dns.qry.name | sort | uniq -c | sort -rn | head -50

# TLS-Verbindungen mit SNI und Ziel
tshark -r mitschnitt.pcap -Y "tls.handshake.type == 1" -T fields -e ip.src -e ip.dst -e tls.handshake.extensions_server_name

# Verbindungsübersicht wie in der Statistik
tshark -r mitschnitt.pcap -q -z conv,tcp

# Mitschnitt auf ein System reduzieren
tshark -r mitschnitt.pcap -Y "ip.addr == 10.0.0.5" -w verdaechtig.pcap

Dazu gehören die Werkzeuge aus demselben Paket: capinfos für Zeitraum und Größe eines Mitschnitts, editcap zum Zerlegen großer Dateien nach Zeit oder Paketzahl, mergecap zum Zusammenführen mehrerer Sensoren. Die vollständige Referenz aller Filterfelder stellt das Projekt in der Display Filter Reference bereit, und das Benutzerhandbuch beschreibt jede Funktion der Oberfläche.

Grenzen

  • Verschlüsselung. Der Inhalt von TLS-Verbindungen bleibt unsichtbar, sofern nicht die Sitzungsschlüssel aus dem Client vorliegen. Handshake, SNI, Zertifikat, Zeiten und Datenmengen bleiben sichtbar, und für die meisten Fragen im Vorfall reicht das.
  • Größe. Wireshark ist für Mitschnitte im Bereich von Megabyte bis wenigen Gigabyte gemacht. Alles darüber wird mit tshark oder editcap vorgefiltert oder zuerst durch Zeek geschickt.
  • Keine Erkennung. Wireshark meldet nichts von selbst. Was verdächtig ist, muss der Analyst wissen, und dafür sind die Filter oben der Anfang, nicht das Ende.
  • Datenschutz. Ein vollständiger Mitschnitt enthält alles, was Menschen im Netz getan haben. Mitschnitte werden zweckgebunden erstellt, verschlüsselt gespeichert, nach der Analyse gelöscht und nur von denen geöffnet, die den Vorfall bearbeiten.

Fazit

Wireshark ist das Mikroskop des Blue Teams: nicht das Werkzeug, mit dem man das Netz überwacht, sondern das, mit dem man am Ende beweist, was übertragen wurde. Die dreißig Filter aus diesem Beitrag decken den Großteil dessen ab, was im Vorfall gefragt wird, und wer sie einmal an einem Mitschnitt aus dem Homelab durchgespielt hat, findet im Ernstfall die Verbindung, um die es geht, in Minuten statt Stunden.

NH

$ whoami

Norbert Hofmann

Cyber Defense Analyst im Security Operations Center eines Managed Security Service Providers. Red und Blue Teaming, Malware-Analyse, Incident Response und Security-Awareness-Trainings. Finalist bei „Deutschlands bester Hacker“ 2022, mehrere CVE-Einträge für WordPress-Plugins.