npx skills add mukul975/Anthropic-Cybersecurity-SkillsMITRE ATT&CK
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.pcapWireshark 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 < 65tshark 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.authorizationPython 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
- Wireshark Documentation: https://www.wireshark.org/docs/
- PCAP Analysis Mastery: https://insanecyber.com/mastering-pcap-review/
- SANS Network Forensics: https://www.sans.org/cyber-security-courses/network-forensics/
- Public PCAPs for Practice: https://www.netresec.com/?page=PcapFiles
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.pcapCore 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 scapySystem: tshark (optional, for HTTP and conversation analysis)
standards.md0.5 KB
Standards - Network Packet Capture Analysis
Standards
- NIST SP 800-86: Guide to Integrating Forensic Techniques
- RFC 791 (IP), RFC 793 (TCP), RFC 768 (UDP)
- PCAP file format: https://wiki.wireshark.org/Development/LibpcapFileFormat
- PCAPNG format: https://pcapng.com/
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 reportScripts 2
agent.py6.0 KB
#!/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
#!/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])