digital forensics

Performing Network Packet Capture Analysis

Perform forensic analysis of network packet captures (PCAP/PCAPNG) using Wireshark, tshark, and tcpdump to reconstruct network communications, extract transferred files, identify malicious traffic, and establish evidence of data exfiltration or command-and-control activity.

network-evidencenetwork-forensicspacket-capturepcappcapngprotocol-analysistcpdumptraffic-analysis
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

Overview

Network packet captures (PCAP/PCAPNG files) represent the ultimate source of truth about network activity and provide irrefutable evidence of communications between hosts. PCAP files log every packet transmitted over a network segment, making them vital for forensic investigations involving data exfiltration, command-and-control communications, lateral movement, malware delivery, and unauthorized access. Wireshark is the primary tool for interactive analysis, while tshark provides command-line capabilities for automated processing and scripting. Modern PCAPNG format supports additional metadata including interface descriptions, capture comments, precise timestamps, and per-packet annotations.

When to Use

  • When conducting security assessments that involve performing network packet capture analysis
  • When following incident response procedures for related security events
  • When performing scheduled security testing or auditing activities
  • When validating security controls through hands-on testing

Prerequisites

  • Wireshark 4.x with protocol dissectors
  • tshark command-line tool (included with Wireshark)
  • tcpdump for capture and basic filtering
  • Python 3.8+ with scapy and pyshark libraries
  • Sufficient disk space for PCAP files (can be multi-GB)

Capture Techniques

tcpdump

# Capture all traffic on interface eth0
tcpdump -i eth0 -w capture.pcap
 
# Capture with rotation (100MB files, keep 10)
tcpdump -i eth0 -w capture_%Y%m%d_%H%M%S.pcap -C 100 -W 10
 
# Capture specific host traffic
tcpdump -i eth0 host 192.168.1.100 -w host_traffic.pcap
 
# Capture specific port traffic
tcpdump -i eth0 port 443 -w https_traffic.pcap
 
# Capture with BPF filter for suspicious ports
tcpdump -i eth0 'port 4444 or port 8080 or port 1337' -w suspicious.pcap

Wireshark Display Filters

# HTTP traffic
http
 
# DNS queries
dns
 
# SMB file transfers
smb2
 
# Specific IP communication
ip.addr == 192.168.1.100
 
# Failed TCP connections
tcp.flags.syn == 1 && tcp.flags.ack == 0
 
# Large data transfers (potential exfiltration)
tcp.len > 1000
 
# Specific protocol by port
tcp.port == 4444
 
# TLS handshakes (SNI extraction)
tls.handshake.type == 1
 
# HTTP POST requests
http.request.method == "POST"
 
# DNS queries to suspicious TLDs
dns.qry.name contains ".xyz" or dns.qry.name contains ".top"
 
# Beaconing detection (regular intervals)
frame.time_delta_displayed > 55 && frame.time_delta_displayed < 65

tshark Analysis Commands

# Extract HTTP URLs from capture
tshark -r capture.pcap -Y "http.request" -T fields -e http.host -e http.request.uri
 
# Extract DNS queries
tshark -r capture.pcap -Y "dns.flags.response == 0" -T fields -e dns.qry.name | sort -u
 
# Extract file transfers (HTTP objects)
tshark -r capture.pcap --export-objects http,exported_files/
 
# Extract SMB file transfers
tshark -r capture.pcap --export-objects smb,smb_files/
 
# Protocol hierarchy statistics
tshark -r capture.pcap -z io,phs
 
# Conversation statistics
tshark -r capture.pcap -z conv,tcp
 
# Extract TLS SNI (Server Name Indication)
tshark -r capture.pcap -Y "tls.handshake.type == 1" -T fields -e tls.handshake.extensions_server_name
 
# Top talkers by bytes
tshark -r capture.pcap -z endpoints,ip -q
 
# Extract credentials (FTP, HTTP Basic)
tshark -r capture.pcap -Y "ftp.request.command == USER || ftp.request.command == PASS || http.authorization" -T fields -e ftp.request.arg -e http.authorization

Python PCAP Analysis

from scapy.all import rdpcap, IP, TCP, UDP, DNS, DNSQR, Raw
import os
import sys
import json
from collections import defaultdict, Counter
from datetime import datetime
 
 
class PCAPForensicAnalyzer:
    """Forensic analysis of PCAP files using Scapy."""
 
    def __init__(self, pcap_path: str, output_dir: str):
        self.pcap_path = pcap_path
        self.output_dir = output_dir
        os.makedirs(output_dir, exist_ok=True)
        self.packets = rdpcap(pcap_path)
 
    def get_conversations(self) -> list:
        """Extract unique IP conversations with byte counts."""
        convos = defaultdict(lambda: {"packets": 0, "bytes": 0})
        for pkt in self.packets:
            if IP in pkt:
                key = tuple(sorted([pkt[IP].src, pkt[IP].dst]))
                convos[key]["packets"] += 1
                convos[key]["bytes"] += len(pkt)
 
        return [
            {"src": k[0], "dst": k[1], "packets": v["packets"], "bytes": v["bytes"]}
            for k, v in sorted(convos.items(), key=lambda x: x[1]["bytes"], reverse=True)
        ]
 
    def extract_dns_queries(self) -> list:
        """Extract all DNS queries from the capture."""
        queries = []
        for pkt in self.packets:
            if DNS in pkt and pkt[DNS].qr == 0 and DNSQR in pkt:
                queries.append({
                    "query": pkt[DNSQR].qname.decode(errors="replace").rstrip("."),
                    "type": pkt[DNSQR].qtype,
                    "src": pkt[IP].src if IP in pkt else "unknown"
                })
        return queries
 
    def detect_beaconing(self, threshold_seconds: float = 5.0) -> list:
        """Detect potential beaconing activity based on regular intervals."""
        ip_timestamps = defaultdict(list)
        for pkt in self.packets:
            if IP in pkt and TCP in pkt:
                key = (pkt[IP].src, pkt[IP].dst, pkt[TCP].dport)
                ip_timestamps[key].append(float(pkt.time))
 
        beacons = []
        for key, times in ip_timestamps.items():
            if len(times) < 5:
                continue
            deltas = [times[i+1] - times[i] for i in range(len(times)-1)]
            if deltas:
                avg_delta = sum(deltas) / len(deltas)
                variance = sum((d - avg_delta) ** 2 for d in deltas) / len(deltas)
                if variance < threshold_seconds and avg_delta > 1:
                    beacons.append({
                        "src": key[0], "dst": key[1], "port": key[2],
                        "avg_interval": round(avg_delta, 2),
                        "variance": round(variance, 4),
                        "connection_count": len(times)
                    })
        return sorted(beacons, key=lambda x: x["variance"])
 
    def get_protocol_distribution(self) -> dict:
        """Get protocol distribution statistics."""
        protocols = Counter()
        for pkt in self.packets:
            if TCP in pkt:
                protocols[f"TCP/{pkt[TCP].dport}"] += 1
            elif UDP in pkt:
                protocols[f"UDP/{pkt[UDP].dport}"] += 1
        return dict(protocols.most_common(50))
 
    def generate_report(self) -> str:
        """Generate comprehensive PCAP analysis report."""
        report = {
            "analysis_timestamp": datetime.now().isoformat(),
            "pcap_file": self.pcap_path,
            "total_packets": len(self.packets),
            "conversations": self.get_conversations()[:50],
            "dns_queries": self.extract_dns_queries()[:200],
            "potential_beacons": self.detect_beaconing(),
            "protocol_distribution": self.get_protocol_distribution()
        }
 
        report_path = os.path.join(self.output_dir, "pcap_forensic_report.json")
        with open(report_path, "w") as f:
            json.dump(report, f, indent=2)
 
        print(f"[*] Total packets: {report['total_packets']}")
        print(f"[*] Conversations: {len(report['conversations'])}")
        print(f"[*] DNS queries: {len(report['dns_queries'])}")
        print(f"[*] Potential beacons: {len(report['potential_beacons'])}")
        return report_path
 
 
def main():
    if len(sys.argv) < 3:
        print("Usage: python process.py <pcap_file> <output_dir>")
        sys.exit(1)
    analyzer = PCAPForensicAnalyzer(sys.argv[1], sys.argv[2])
    analyzer.generate_report()
 
 
if __name__ == "__main__":
    main()

References

Source materials

References and resources

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

References 3

api-reference.md1.6 KB

API Reference — Performing Network Packet Capture Analysis

Libraries Used

  • scapy: PCAP parsing, protocol dissection, packet analysis
  • subprocess: Execute tshark for HTTP extraction and conversation analysis
  • collections.Counter: Traffic statistics aggregation

CLI Interface

python agent.py analyze --pcap capture.pcap
python agent.py http --pcap capture.pcap
python agent.py suspicious --pcap capture.pcap
python agent.py conversations --pcap capture.pcap

Core Functions

analyze_pcap_scapy(pcap_file) — Protocol and IP statistics

Returns: protocol distribution, top source/dest IPs, top destination ports, DNS queries.

extract_http_requests(pcap_file) — HTTP request extraction via tshark

Extracts: source/dest IP, method, host, URI, user agent from HTTP requests.

detect_suspicious_traffic(pcap_file) — Anomaly detection

Detects: port scanning (>=20 SYN to same target), DNS exfiltration (queries >60 chars), suspicious ports (4444, 31337, 6667, etc.).

conversation_analysis(pcap_file) — TCP conversation summary

Uses tshark -z conv,tcp for conversation-level statistics.

Suspicious Port Detection

4444, 5555, 6666, 8888, 9999, 1234, 31337, 12345, 6667, 6697

Detection Categories

Finding Severity Trigger
PORT_SCAN HIGH >=20 SYN packets to same target
DNS_EXFILTRATION HIGH DNS queries >60 characters
SUSPICIOUS_PORTS MEDIUM Traffic on known C2 ports

Dependencies

pip install scapy

System: tshark (optional, for HTTP and conversation analysis)

standards.md0.5 KB

Standards - Network Packet Capture Analysis

Standards

Tools

  • Wireshark: GUI packet analyzer
  • tshark: Command-line packet analyzer
  • tcpdump: Packet capture utility
  • Scapy (Python): Packet manipulation library
  • Zeek (Bro): Network security monitoring
  • NetworkMiner: Network forensic analysis tool
workflows.md0.5 KB

Workflows - Packet Capture Analysis

Workflow: PCAP Forensic Investigation

Open PCAP in Wireshark
    |
Review protocol hierarchy (Statistics > Protocol Hierarchy)
    |
Identify top talkers (Statistics > Endpoints)
    |
Filter for suspicious protocols/ports
    |
Extract files (File > Export Objects)
    |
Analyze DNS for C2 domains
    |
Detect beaconing patterns
    |
Extract credentials from clear-text protocols
    |
Generate investigation report

Scripts 2

agent.py6.0 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Agent for performing network packet capture analysis with scapy and tshark."""

import json
import argparse
import subprocess
from collections import Counter

try:
    from scapy.all import rdpcap, IP, TCP, UDP, DNS, DNSQR
    HAS_SCAPY = True
except ImportError:
    HAS_SCAPY = False


def analyze_pcap_scapy(pcap_file):
    """Analyze PCAP file using scapy for protocol statistics."""
    if not HAS_SCAPY:
        return {"error": "scapy not installed — pip install scapy"}
    packets = rdpcap(pcap_file)
    total = len(packets)
    protocols = Counter()
    src_ips = Counter()
    dst_ips = Counter()
    src_ports = Counter()
    dst_ports = Counter()
    dns_queries = []
    for pkt in packets:
        if IP in pkt:
            src_ips[pkt[IP].src] += 1
            dst_ips[pkt[IP].dst] += 1
            if TCP in pkt:
                protocols["TCP"] += 1
                src_ports[pkt[TCP].sport] += 1
                dst_ports[pkt[TCP].dport] += 1
            elif UDP in pkt:
                protocols["UDP"] += 1
                if DNS in pkt and pkt.haslayer(DNSQR):
                    query = pkt[DNSQR].qname.decode("utf-8", errors="replace").rstrip(".")
                    dns_queries.append(query)
            else:
                protocols[pkt[IP].proto] += 1
    return {
        "pcap_file": pcap_file, "total_packets": total,
        "protocols": dict(protocols),
        "top_src_ips": dict(src_ips.most_common(10)),
        "top_dst_ips": dict(dst_ips.most_common(10)),
        "top_dst_ports": dict(dst_ports.most_common(15)),
        "dns_queries": list(set(dns_queries))[:30],
        "unique_dns_queries": len(set(dns_queries)),
    }


def extract_http_requests(pcap_file):
    """Extract HTTP requests from PCAP using tshark."""
    cmd = ["tshark", "-r", pcap_file, "-Y", "http.request",
           "-T", "fields", "-e", "ip.src", "-e", "ip.dst",
           "-e", "http.request.method", "-e", "http.host",
           "-e", "http.request.uri", "-e", "http.user_agent"]
    try:
        result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
        requests_list = []
        for line in result.stdout.strip().splitlines():
            parts = line.split("\t")
            if len(parts) >= 4:
                requests_list.append({
                    "src": parts[0], "dst": parts[1],
                    "method": parts[2], "host": parts[3],
                    "uri": parts[4] if len(parts) > 4 else "",
                    "user_agent": parts[5][:200] if len(parts) > 5 else "",
                })
        return {"pcap_file": pcap_file, "http_requests": len(requests_list), "requests": requests_list[:50]}
    except FileNotFoundError:
        return {"error": "tshark not found — install Wireshark"}
    except Exception as e:
        return {"error": str(e)}


def detect_suspicious_traffic(pcap_file):
    """Detect suspicious network patterns in PCAP."""
    if not HAS_SCAPY:
        return {"error": "scapy not installed"}
    packets = rdpcap(pcap_file)
    findings = []
    syn_counts = Counter()
    large_dns = []
    unusual_ports = []
    high_ports = [4444, 5555, 6666, 8888, 9999, 1234, 31337, 12345, 6667, 6697]
    for pkt in packets:
        if IP not in pkt:
            continue
        if TCP in pkt:
            if pkt[TCP].flags == 0x02:
                syn_counts[pkt[IP].dst] += 1
            if pkt[TCP].dport in high_ports or pkt[TCP].sport in high_ports:
                unusual_ports.append({"src": pkt[IP].src, "dst": pkt[IP].dst,
                                      "port": pkt[TCP].dport, "sport": pkt[TCP].sport})
        if DNS in pkt and pkt.haslayer(DNSQR):
            query = pkt[DNSQR].qname.decode("utf-8", errors="replace")
            if len(query) > 60:
                large_dns.append({"query": query[:100], "length": len(query), "src": pkt[IP].src})
    port_scan_suspects = [{"target": ip, "syn_count": count} for ip, count in syn_counts.most_common(5) if count >= 20]
    if port_scan_suspects:
        findings.append({"type": "PORT_SCAN", "severity": "HIGH", "details": port_scan_suspects})
    if large_dns:
        findings.append({"type": "DNS_EXFILTRATION", "severity": "HIGH", "details": large_dns[:10]})
    if unusual_ports:
        findings.append({"type": "SUSPICIOUS_PORTS", "severity": "MEDIUM", "details": unusual_ports[:10]})
    return {
        "pcap_file": pcap_file,
        "findings": findings,
        "total_findings": len(findings),
        "severity": "HIGH" if any(f["severity"] == "HIGH" for f in findings) else "MEDIUM" if findings else "LOW",
    }


def conversation_analysis(pcap_file):
    """Analyze TCP/UDP conversations using tshark."""
    cmd = ["tshark", "-r", pcap_file, "-q", "-z", "conv,tcp"]
    try:
        result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
        return {"pcap_file": pcap_file, "tcp_conversations": result.stdout[:3000]}
    except Exception as e:
        return {"error": str(e)}


def main():
    parser = argparse.ArgumentParser(description="Network Packet Capture Analysis Agent")
    sub = parser.add_subparsers(dest="command")
    a = sub.add_parser("analyze", help="Protocol and IP statistics")
    a.add_argument("--pcap", required=True)
    h = sub.add_parser("http", help="Extract HTTP requests")
    h.add_argument("--pcap", required=True)
    s = sub.add_parser("suspicious", help="Detect suspicious traffic")
    s.add_argument("--pcap", required=True)
    c = sub.add_parser("conversations", help="TCP conversation analysis")
    c.add_argument("--pcap", required=True)
    args = parser.parse_args()
    if args.command == "analyze":
        result = analyze_pcap_scapy(args.pcap)
    elif args.command == "http":
        result = extract_http_requests(args.pcap)
    elif args.command == "suspicious":
        result = detect_suspicious_traffic(args.pcap)
    elif args.command == "conversations":
        result = conversation_analysis(args.pcap)
    else:
        parser.print_help()
        return
    print(json.dumps(result, indent=2, default=str))


if __name__ == "__main__":
    main()
process.py1.8 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""PCAP Forensic Analyzer - Analyzes packet captures for forensic investigation."""
import json, os, sys
from collections import defaultdict, Counter
from datetime import datetime
try:
    from scapy.all import rdpcap, IP, TCP, UDP, DNS, DNSQR
except ImportError:
    print("Install scapy: pip install scapy"); sys.exit(1)

def analyze_pcap(pcap_path: str, output_dir: str) -> str:
    os.makedirs(output_dir, exist_ok=True)
    packets = rdpcap(pcap_path)
    convos = defaultdict(lambda: {"pkts": 0, "bytes": 0})
    dns_queries = []
    protocols = Counter()
    for pkt in packets:
        if IP in pkt:
            key = tuple(sorted([pkt[IP].src, pkt[IP].dst]))
            convos[key]["pkts"] += 1; convos[key]["bytes"] += len(pkt)
            if TCP in pkt: protocols[f"TCP/{pkt[TCP].dport}"] += 1
            elif UDP in pkt: protocols[f"UDP/{pkt[UDP].dport}"] += 1
        if DNS in pkt and pkt[DNS].qr == 0 and DNSQR in pkt:
            dns_queries.append({"query": pkt[DNSQR].qname.decode(errors="replace").rstrip("."),
                                "src": pkt[IP].src if IP in pkt else ""})
    top_convos = sorted([{"src": k[0], "dst": k[1], **v} for k, v in convos.items()],
                        key=lambda x: x["bytes"], reverse=True)[:50]
    report = {"total_packets": len(packets), "conversations": top_convos,
              "dns_queries": dns_queries[:200], "protocols": dict(protocols.most_common(30))}
    out = os.path.join(output_dir, "pcap_analysis.json")
    with open(out, "w") as f: json.dump(report, f, indent=2)
    print(f"[*] Packets:{len(packets)} Convos:{len(convos)} DNS:{len(dns_queries)}")
    return out

if __name__ == "__main__":
    if len(sys.argv) < 3: print("Usage: process.py <pcap> <output>"); sys.exit(1)
    analyze_pcap(sys.argv[1], sys.argv[2])

Assets 1

template.mdtext/markdown · 0.4 KB
Keep exploring