Performing Network Packet Capture Analysis
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
tcpdump -i eth0 -w capture.pcap
tcpdump -i eth0 -w capture_%Y%m%d_%H%M%S.pcap -C 100 -W 10
tcpdump -i eth0 host 192.168.1.100 -w host_traffic.pcap
tcpdump -i eth0 port 443 -w https_traffic.pcap
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
tshark -r capture.pcap -Y "http.request" -T fields -e http.host -e http.request.uri
tshark -r capture.pcap -Y "dns.flags.response == 0" -T fields -e dns.qry.name | sort -u
tshark -r capture.pcap --export-objects http,exported_files/
tshark -r capture.pcap --export-objects smb,smb_files/
tshark -r capture.pcap -z io,phs
tshark -r capture.pcap -z conv,tcp
tshark -r capture.pcap -Y "tls.handshake.type == 1" -T fields -e tls.handshake.extensions_server_name
tshark -r capture.pcap -z endpoints,ip -q
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], : k[], : v[], : v[]}
k, v (convos.items(), key= x: x[][], reverse=)
]
() -> :
queries = []
pkt .packets:
DNS pkt pkt[DNS].qr == DNSQR pkt:
queries.append({
: pkt[DNSQR].qname.decode(errors=).rstrip(),
: pkt[DNSQR].qtype,
: pkt[IP].src IP pkt
})
queries
() -> :
ip_timestamps = defaultdict()
pkt .packets:
IP pkt TCP pkt:
key = (pkt[IP].src, pkt[IP].dst, pkt[TCP].dport)
ip_timestamps[key].append((pkt.time))
beacons = []
key, times ip_timestamps.items():
(times) < :
deltas = [times[i+] - times[i] i ((times)-)]
deltas:
avg_delta = (deltas) / (deltas)
variance = ((d - avg_delta) ** d deltas) / (deltas)
variance < threshold_seconds avg_delta > :
beacons.append({
: key[], : key[], : key[],
: (avg_delta, ),
: (variance, ),
: (times)
})
(beacons, key= x: x[])
() -> :
protocols = Counter()
pkt .packets:
TCP pkt:
protocols[] +=
UDP pkt:
protocols[] +=
(protocols.most_common())
() -> :
report = {
: datetime.now().isoformat(),
: .pcap_path,
: (.packets),
: .get_conversations()[:],
: .extract_dns_queries()[:],
: .detect_beaconing(),
: .get_protocol_distribution()
}
report_path = os.path.join(.output_dir, )
(report_path, ) f:
json.dump(report, f, indent=)
()
()
()
()
report_path
():
(sys.argv) < :
()
sys.exit()
analyzer = PCAPForensicAnalyzer(sys.argv[], sys.argv[])
analyzer.generate_report()
__name__ == :
main()
References