digital forensics

Performing Network Forensics with Wireshark

Capture and analyze network traffic using Wireshark and tshark to reconstruct network events, extract artifacts, and identify malicious communications.

forensicsnetwork-forensicspacket-analysispcaptraffic-analysiswireshark
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

When to Use

  • When analyzing captured network traffic (PCAP files) from a security incident
  • For identifying command-and-control (C2) communications in captured traffic
  • When reconstructing data exfiltration activities from packet captures
  • During malware analysis to identify network indicators of compromise
  • For extracting files, credentials, and artifacts transferred over the network

Prerequisites

  • Wireshark or tshark installed for packet analysis
  • PCAP/PCAPNG files from network captures (tcpdump, Wireshark, network TAP)
  • NetworkMiner for automated artifact extraction
  • Sufficient RAM for large capture files (1GB+ PCAPs need 8GB+ RAM)
  • Understanding of TCP/IP, HTTP, DNS, TLS protocols
  • GeoIP databases for IP geolocation

Workflow

Step 1: Prepare and Validate the Capture File

# Install Wireshark and tshark
sudo apt-get install wireshark tshark
 
# Verify the PCAP file
capinfos /cases/case-2024-001/network/capture.pcap
 
# Output includes: file type, packet count, capture duration, data size
# Example output:
# File name:           capture.pcap
# File type:           Wireshark/tcpdump/... - pcap
# Number of packets:   1,245,678
# File size:           856 MB
# Data size:           823 MB
# Capture duration:    3600.123456 seconds
# First packet time:   2024-01-15 14:00:00.000000
# Last packet time:    2024-01-15 15:00:00.123456
 
# Hash the PCAP for integrity
sha256sum /cases/case-2024-001/network/capture.pcap \
   > /cases/case-2024-001/network/pcap_hash.txt
 
# Get a protocol hierarchy statistics overview
tshark -r /cases/case-2024-001/network/capture.pcap -q -z io,phs

Step 2: Filter and Identify Suspicious Traffic

# Extract conversation statistics
tshark -r /cases/case-2024-001/network/capture.pcap -q -z conv,tcp
 
# Find top talkers by bytes transferred
tshark -r /cases/case-2024-001/network/capture.pcap -q -z endpoints,ip \
   | sort -t$'\t' -k3 -rn | head -20
 
# Filter for DNS queries (potential C2 or exfiltration)
tshark -r /cases/case-2024-001/network/capture.pcap \
   -Y "dns.qr == 0" \
   -T fields -e frame.time -e ip.src -e dns.qry.name \
   > /cases/case-2024-001/analysis/dns_queries.txt
 
# Find DNS queries to unusual TLDs or long domain names (DNS tunneling)
tshark -r /cases/case-2024-001/network/capture.pcap \
   -Y "dns.qr == 0 && dns.qry.name matches \"[a-z0-9]{30,}\"" \
   -T fields -e frame.time -e ip.src -e dns.qry.name \
   > /cases/case-2024-001/analysis/suspicious_dns.txt
 
# Filter HTTP traffic
tshark -r /cases/case-2024-001/network/capture.pcap \
   -Y "http.request" \
   -T fields -e frame.time -e ip.src -e ip.dst -e http.request.method \
   -e http.host -e http.request.uri -e http.user_agent \
   > /cases/case-2024-001/analysis/http_requests.txt
 
# Find connections to known malicious ports
tshark -r /cases/case-2024-001/network/capture.pcap \
   -Y "tcp.dstport == 4444 || tcp.dstport == 8080 || tcp.dstport == 1337 || tcp.dstport == 6667" \
   -T fields -e frame.time -e ip.src -e ip.dst -e tcp.dstport \
   > /cases/case-2024-001/analysis/suspicious_ports.txt
 
# Detect beaconing patterns (regular interval connections)
tshark -r /cases/case-2024-001/network/capture.pcap \
   -Y "ip.dst == 185.0.0.1" \
   -T fields -e frame.time_epoch \
   > /tmp/beacon_times.txt

Step 3: Extract Files and Objects from Traffic

# Export HTTP objects (files transferred over HTTP)
tshark -r /cases/case-2024-001/network/capture.pcap \
   --export-objects http,/cases/case-2024-001/analysis/http_objects/
 
# Export SMB objects
tshark -r /cases/case-2024-001/network/capture.pcap \
   --export-objects smb,/cases/case-2024-001/analysis/smb_objects/
 
# Export DICOM objects (medical imaging)
tshark -r /cases/case-2024-001/network/capture.pcap \
   --export-objects dicom,/cases/case-2024-001/analysis/dicom_objects/
 
# Export FTP data transfers
tshark -r /cases/case-2024-001/network/capture.pcap \
   -Y "ftp-data" \
   -T fields -e ftp-data.data \
   --export-objects ftp-data,/cases/case-2024-001/analysis/ftp_objects/
 
# Hash all extracted objects
find /cases/case-2024-001/analysis/http_objects/ -type f -exec sha256sum {} \; \
   > /cases/case-2024-001/analysis/extracted_file_hashes.txt
 
# Check extracted file hashes against VirusTotal
while read hash filepath; do
   echo "Checking $filepath ($hash)"
   curl -s "https://www.virustotal.com/api/v3/files/$hash" \
      -H "x-apikey: YOUR_API_KEY" | python3 -c "
import json,sys
data=json.load(sys.stdin)
if 'data' in data:
   stats=data['data']['attributes']['last_analysis_stats']
   print(f'  Malicious: {stats[\"malicious\"]}, Undetected: {stats[\"undetected\"]}')
else:
   print('  Not found on VT')
"
done < /cases/case-2024-001/analysis/extracted_file_hashes.txt

Step 4: Reconstruct TCP Streams and Sessions

# Follow a specific TCP stream (stream index 42)
tshark -r /cases/case-2024-001/network/capture.pcap \
   -q -z "follow,tcp,ascii,42" \
   > /cases/case-2024-001/analysis/stream_42.txt
 
# Extract all HTTP request-response pairs for a suspicious host
tshark -r /cases/case-2024-001/network/capture.pcap \
   -Y "http && ip.addr == 185.0.0.1" \
   -T fields -e frame.time -e http.request.method -e http.host \
   -e http.request.uri -e http.response.code -e http.content_length \
   > /cases/case-2024-001/analysis/suspicious_http.txt
 
# Extract TLS/SSL certificate information
tshark -r /cases/case-2024-001/network/capture.pcap \
   -Y "tls.handshake.type == 11" \
   -T fields -e ip.dst -e tls.handshake.certificate \
   > /cases/case-2024-001/analysis/tls_certs.txt
 
# Extract TLS SNI (Server Name Indication) values
tshark -r /cases/case-2024-001/network/capture.pcap \
   -Y "tls.handshake.extensions_server_name" \
   -T fields -e frame.time -e ip.src -e ip.dst \
   -e tls.handshake.extensions_server_name \
   > /cases/case-2024-001/analysis/tls_sni.txt
 
# Extract credentials from unencrypted protocols
tshark -r /cases/case-2024-001/network/capture.pcap \
   -Y "ftp.request.command == \"USER\" || ftp.request.command == \"PASS\"" \
   -T fields -e frame.time -e ip.src -e ftp.request.command -e ftp.request.arg
 
tshark -r /cases/case-2024-001/network/capture.pcap \
   -Y "http.authorization" \
   -T fields -e frame.time -e ip.src -e http.host -e http.authorization

Step 5: Use NetworkMiner for Automated Analysis

# Install NetworkMiner (Mono required on Linux)
sudo apt-get install mono-complete
wget https://www.netresec.com/?download=NetworkMiner -O NetworkMiner.zip
unzip NetworkMiner.zip -d /opt/NetworkMiner/
 
# Run NetworkMiner
mono /opt/NetworkMiner/NetworkMiner.exe /cases/case-2024-001/network/capture.pcap
 
# NetworkMiner automatically extracts:
# - Host inventory (OS fingerprinting, open ports)
# - Files transferred over HTTP, FTP, SMB, TFTP
# - Images from web traffic
# - Credentials (plaintext and NTLM hashes)
# - DNS records
# - Session parameters
# - Anomalies and alerts

Step 6: Generate Network Forensics Report

# Compile findings
cat << 'EOF' > /cases/case-2024-001/analysis/network_forensics_report.txt
NETWORK FORENSICS ANALYSIS REPORT
===================================
Case: 2024-001
Capture File: capture.pcap (856 MB, 1,245,678 packets)
Capture Period: 2024-01-15 14:00 to 15:00 UTC
Analyst: [Examiner Name]
 
TRAFFIC OVERVIEW:
  Total packets: 1,245,678
  Unique source IPs: 45
  Unique destination IPs: 234
  Protocols: TCP (78%), UDP (18%), ICMP (2%), Other (2%)
 
C2 COMMUNICATION:
  Destination: 185.0.0.1:443
  Beaconing interval: ~60 seconds
  Total connections: 58
  Data transferred: 4.2 MB outbound, 12.3 MB inbound
  TLS SNI: update-service.malware-c2.com
 
EXFILTRATION:
  Method: HTTPS POST to 185.0.0.1
  Volume: 4.2 MB over 45 minutes
  Files: 3 ZIP archives extracted from HTTP objects
 
DNS TUNNELING:
  Suspicious queries to: data.evil-dns.com
  Average subdomain length: 45 characters
  Query count: 1,234 (normal baseline: 50)
EOF

Key Concepts

Concept Description
PCAP/PCAPNG Packet capture file formats storing raw network traffic
TCP stream Complete bidirectional communication between two endpoints
Deep packet inspection Analysis of packet payload content beyond header information
Beaconing Regular-interval callbacks from malware to C2 servers
DNS tunneling Encoding data within DNS queries for covert exfiltration
TLS/SNI Server Name Indication revealing the target hostname in encrypted connections
Network flow Summary of communication between endpoints (IPs, ports, bytes, duration)
Protocol hierarchy Statistical breakdown of protocols present in a capture

Tools & Systems

Tool Purpose
Wireshark GUI-based packet analyzer with deep protocol dissection
tshark Command-line version of Wireshark for scripted analysis
NetworkMiner Automated network forensic analysis and file extraction
tcpdump Command-line packet capture utility
zeek (Bro) Network security monitor generating structured connection logs
ngrep Network grep for pattern matching in packet content
capinfos PCAP file statistics and metadata utility
mergecap Merge multiple PCAP files into a single capture

Common Scenarios

Scenario 1: Malware C2 Communication Analysis Load PCAP in Wireshark, identify beaconing patterns to external IPs, examine TLS certificates for self-signed or unusual issuers, extract HTTP POST data containing encoded commands, correlate C2 IPs with threat intelligence feeds.

Scenario 2: Data Exfiltration Detection Analyze traffic statistics for unusually large outbound transfers, examine DNS query lengths for DNS tunneling indicators, track FTP and HTTP file uploads to external servers, reconstruct exfiltrated files from packet data.

Scenario 3: Lateral Movement in Enterprise Network Filter for SMB, RDP, WMI, and PSExec traffic between internal hosts, identify credential usage patterns across multiple systems, trace the propagation path of the attacker through the network, correlate with Windows Event Log authentication events.

Scenario 4: Web Application Attack Reconstruction Filter HTTP traffic to the web server, identify SQL injection, XSS, and directory traversal attempts, follow the TCP stream of the successful exploit, extract uploaded webshells or payloads, document the attack chain for the incident report.

Output Format

Network Forensics Summary:
  Capture: capture.pcap
  Duration: 1 hour (14:00-15:00 UTC, 2024-01-15)
  Packets: 1,245,678 | Size: 856 MB
 
  Top Suspicious Connections:
    192.168.1.50 -> 185.0.0.1:443   (C2, 58 connections, 4.2MB out)
    192.168.1.50 -> 10.0.0.25:445   (SMB lateral movement)
    192.168.1.50 -> 10.0.0.30:3389  (RDP lateral movement)
 
  Extracted Artifacts:
    Files:        23 (3 malicious per VT)
    Credentials:  2 plaintext FTP logins
    DNS Queries:  1,234 suspicious (possible tunneling)
    TLS Certs:    5 self-signed certificates
 
  IOCs Identified:
    IPs:     185.0.0.1, 203.0.113.50
    Domains: update-service.malware-c2.com, data.evil-dns.com
    Hashes:  3 file hashes flagged as malware
Source materials

References and resources

Everything below is rendered for inspection. Script files are read-only and never run.

References 1

api-reference.md1.6 KB

API Reference: Network Forensics with Wireshark

pyshark API

import pyshark
 
# Open capture file
cap = pyshark.FileCapture("capture.pcap")
cap = pyshark.FileCapture("capture.pcap", display_filter="http.request")
 
# Access packet fields
for pkt in cap:
    print(pkt.ip.src, pkt.ip.dst)
    print(pkt.tcp.dstport)
    print(pkt.http.request_uri)

tshark CLI

Command Description
tshark -r <pcap> -q -z conv,tcp TCP conversation statistics
tshark -r <pcap> -Y "dns.qr==0" -T fields -e dns.qry.name Extract DNS queries
tshark -r <pcap> --export-objects http,<dir> Export HTTP objects
tshark -r <pcap> -q -z io,phs Protocol hierarchy statistics
tshark -r <pcap> -q -z endpoints,ip IP endpoint statistics

Display Filters

Filter Description
dns.qr==0 DNS queries only
http.request HTTP requests
tls.handshake.extensions_server_name TLS SNI values
tcp.flags.syn==1 && tcp.flags.ack==0 TCP SYN packets
ip.dst==<ip> && tcp.dstport==443 Traffic to specific host

Python Libraries

Library Version Purpose
pyshark >=0.6 Python wrapper for tshark packet analysis
dpkt >=1.9 Low-level PCAP parsing without tshark dependency
scapy >=2.5 Packet crafting and analysis

References

Scripts 1

agent.py7.9 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Agent for performing network forensics with Wireshark/pyshark.

Analyzes PCAP files to extract conversations, DNS queries, HTTP
objects, detect beaconing patterns, and identify C2 communications.
"""

import pyshark
import json
import sys
from collections import defaultdict
from pathlib import Path


class NetworkForensicsAgent:
    """Analyzes PCAP files for forensic investigations."""

    def __init__(self, pcap_path, output_dir):
        self.pcap_path = pcap_path
        self.output_dir = Path(output_dir)
        self.output_dir.mkdir(parents=True, exist_ok=True)

    def get_capture_info(self):
        """Get basic capture file statistics."""
        cap = pyshark.FileCapture(self.pcap_path, only_summaries=True)
        packet_count = 0
        first_time = None
        last_time = None
        for pkt in cap:
            packet_count += 1
            if first_time is None:
                first_time = pkt.time
            last_time = pkt.time
        cap.close()
        return {
            "file": self.pcap_path,
            "packets": packet_count,
            "first_packet": str(first_time),
            "last_packet": str(last_time),
        }

    def extract_dns_queries(self, limit=5000):
        """Extract DNS queries from the capture."""
        cap = pyshark.FileCapture(self.pcap_path, display_filter="dns.qr==0")
        queries = []
        count = 0
        for pkt in cap:
            if count >= limit:
                break
            try:
                queries.append({
                    "timestamp": str(pkt.sniff_time),
                    "src_ip": pkt.ip.src,
                    "query": pkt.dns.qry_name,
                    "type": pkt.dns.qry_type,
                })
                count += 1
            except AttributeError:
                continue
        cap.close()
        return queries

    def detect_dns_tunneling(self, min_length=30):
        """Detect potential DNS tunneling by subdomain length."""
        queries = self.extract_dns_queries()
        suspicious = []
        for q in queries:
            domain = q.get("query", "")
            subdomain = domain.split(".")[0] if "." in domain else domain
            if len(subdomain) >= min_length:
                suspicious.append({
                    "query": domain,
                    "subdomain_length": len(subdomain),
                    "src_ip": q["src_ip"],
                    "timestamp": q["timestamp"],
                })
        return suspicious

    def extract_http_requests(self, limit=5000):
        """Extract HTTP requests with method, host, URI, and user-agent."""
        cap = pyshark.FileCapture(self.pcap_path, display_filter="http.request")
        requests_list = []
        count = 0
        for pkt in cap:
            if count >= limit:
                break
            try:
                req = {
                    "timestamp": str(pkt.sniff_time),
                    "src_ip": pkt.ip.src,
                    "dst_ip": pkt.ip.dst,
                    "method": pkt.http.request_method,
                    "host": getattr(pkt.http, "host", ""),
                    "uri": getattr(pkt.http, "request_uri", ""),
                    "user_agent": getattr(pkt.http, "user_agent", ""),
                }
                requests_list.append(req)
                count += 1
            except AttributeError:
                continue
        cap.close()
        return requests_list

    def extract_tls_sni(self, limit=5000):
        """Extract TLS Server Name Indication values."""
        cap = pyshark.FileCapture(
            self.pcap_path,
            display_filter="tls.handshake.extensions_server_name"
        )
        sni_list = []
        count = 0
        for pkt in cap:
            if count >= limit:
                break
            try:
                sni_list.append({
                    "timestamp": str(pkt.sniff_time),
                    "src_ip": pkt.ip.src,
                    "dst_ip": pkt.ip.dst,
                    "sni": pkt.tls.handshake_extensions_server_name,
                })
                count += 1
            except AttributeError:
                continue
        cap.close()
        return sni_list

    def get_top_talkers(self, limit=20):
        """Identify top source and destination IPs by packet count."""
        cap = pyshark.FileCapture(self.pcap_path, only_summaries=True)
        ip_counts = defaultdict(int)
        for pkt in cap:
            try:
                ip_counts[pkt.source] += 1
                ip_counts[pkt.destination] += 1
            except AttributeError:
                continue
        cap.close()
        sorted_ips = sorted(ip_counts.items(), key=lambda x: x[1], reverse=True)
        return [{"ip": ip, "packets": count} for ip, count in sorted_ips[:limit]]

    def detect_beaconing(self, target_ip, tolerance=5):
        """Detect beaconing patterns to a specific IP."""
        cap = pyshark.FileCapture(
            self.pcap_path,
            display_filter=f"ip.dst=={target_ip} and tcp.flags.syn==1"
        )
        timestamps = []
        for pkt in cap:
            try:
                timestamps.append(float(pkt.sniff_timestamp))
            except (AttributeError, ValueError):
                continue
        cap.close()

        if len(timestamps) < 3:
            return {"beaconing": False, "connections": len(timestamps)}

        intervals = [timestamps[i+1] - timestamps[i] for i in range(len(timestamps)-1)]
        avg_interval = sum(intervals) / len(intervals)
        consistent = sum(1 for i in intervals if abs(i - avg_interval) < tolerance)

        return {
            "target_ip": target_ip,
            "connections": len(timestamps),
            "avg_interval_sec": round(avg_interval, 1),
            "consistent_intervals": consistent,
            "total_intervals": len(intervals),
            "beaconing": consistent / len(intervals) > 0.7 if intervals else False,
        }

    def find_suspicious_ports(self):
        """Find connections to commonly malicious ports."""
        suspicious_ports = {"4444", "8080", "1337", "6667", "9001", "31337"}
        cap = pyshark.FileCapture(self.pcap_path, display_filter="tcp")
        findings = defaultdict(lambda: {"count": 0, "sources": set()})

        for pkt in cap:
            try:
                dport = pkt.tcp.dstport
                if dport in suspicious_ports:
                    findings[dport]["count"] += 1
                    findings[dport]["sources"].add(pkt.ip.src)
            except AttributeError:
                continue
        cap.close()

        return {
            port: {"count": data["count"], "sources": list(data["sources"])}
            for port, data in findings.items()
        }

    def generate_report(self, target_ip=None):
        """Generate comprehensive network forensics report."""
        report = {
            "capture_info": self.get_capture_info(),
            "top_talkers": self.get_top_talkers(),
            "dns_query_count": len(self.extract_dns_queries()),
            "dns_tunneling_suspects": self.detect_dns_tunneling(),
            "http_request_count": len(self.extract_http_requests()),
            "tls_sni_count": len(self.extract_tls_sni()),
            "suspicious_ports": self.find_suspicious_ports(),
        }

        if target_ip:
            report["beaconing_analysis"] = self.detect_beaconing(target_ip)

        report_path = self.output_dir / "network_forensics_report.json"
        with open(report_path, "w") as f:
            json.dump(report, f, indent=2, default=list)
        print(json.dumps(report, indent=2, default=list))
        return report


def main():
    if len(sys.argv) < 3:
        print("Usage: agent.py <pcap_file> <output_dir> [target_ip]")
        sys.exit(1)

    pcap_path = sys.argv[1]
    output_dir = sys.argv[2]
    target_ip = sys.argv[3] if len(sys.argv) > 3 else None

    agent = NetworkForensicsAgent(pcap_path, output_dir)
    agent.generate_report(target_ip)


if __name__ == "__main__":
    main()
Keep exploring