Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-SkillsFramework mappings
MITRE ATT&CK
When to Use
- When deploying or configuring implementing network traffic analysis with arkime capabilities in your environment
- When establishing security controls aligned to compliance requirements
- When building or improving security architecture for this domain
- When conducting security assessments that require this implementation
Prerequisites
- Familiarity with network security concepts and tools
- Access to a test or lab environment for safe execution
- Python 3.8+ with required dependencies installed
- Appropriate authorization for any testing activities
Instructions
- Install dependencies:
pip install requests - Configure Arkime viewer URL and credentials.
- Run the agent to query Arkime sessions and analyze traffic:
- Search sessions by IP, port, protocol, or expression
- Download PCAP data for forensic analysis
- Detect C2 beaconing via connection interval analysis
- Identify DNS tunneling through query length statistics
- Flag connections to known-bad TLS certificate issuers
python scripts/agent.py --arkime-url https://arkime.local:8005 --user admin --password secret --output arkime_report.jsonExamples
Beaconing Detection
Source: 10.1.2.50 -> 185.220.101.34:443
Sessions: 288 over 24 hours
Avg interval: 300s, Jitter: 4.2%
Verdict: HIGH confidence C2 beaconing (jitter < 5%)Source materials
References and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 1
api-reference.md2.0 KB
API Reference: Arkime Network Traffic Analysis
Authentication
HTTPDigestAuth(username, password)All API requests require Digest authentication.
Session Search
GET /api/sessions| Parameter | Type | Description |
|---|---|---|
date |
int | Time range in hours (1=last hour) |
expression |
string | Arkime search expression |
length |
int | Max results to return |
order |
string | Sort field:direction (e.g. lastPacket:desc) |
fields |
string | Comma-separated field list |
PCAP Download
GET /api/sessions/pcap
GET /api/sessions/pcapng| Parameter | Description |
|---|---|
date |
Time range in hours |
expression |
Filter expression |
| Returns raw PCAP/PCAPNG binary data. |
Connection Graph
GET /api/connectionsReturns nodes (IPs) and links (connections) for network graph visualization.
SPI View (Field Statistics)
GET /api/spiview| Parameter | Description |
|---|---|
spi |
Comma-separated fields (e.g. srcIp,dstIp,dstPort) |
| Returns top values and counts for each field. |
Session Fields
| Field | Description |
|---|---|
srcIp |
Source IP address |
dstIp |
Destination IP address |
srcPort |
Source port |
dstPort |
Destination port |
srcBytes |
Bytes sent by source |
dstBytes |
Bytes sent by destination |
lastPacket |
Timestamp of last packet (ms) |
srcJa3 |
JA3 fingerprint of client TLS |
tls.issuerCN |
TLS certificate issuer CN |
tls.subjectCN |
TLS certificate subject CN |
tls.notAfter |
Certificate expiry (ms epoch) |
Search Expressions
ip.src == 10.0.0.0/8
port.dst == 443
protocols == tls
country.src == CN
bytes > 1000000Beaconing Detection Logic
- Collect connection timestamps per (src, dst, port) tuple
- Calculate intervals between consecutive connections
- Compute jitter ratio:
std_dev / avg_interval - Jitter < 0.05 = high confidence C2, < 0.15 = medium
Scripts 1
agent.py8.2 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Arkime Network Traffic Analysis Agent - Queries Arkime API for session analysis and anomaly detection."""
import json
import logging
import os
import argparse
from datetime import datetime
from collections import defaultdict
import requests
from requests.auth import HTTPDigestAuth
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)
def arkime_request(base_url, endpoint, auth, params=None):
"""Make an authenticated request to Arkime API v3."""
url = f"{base_url}{endpoint}"
try:
resp = requests.get(url, auth=HTTPDigestAuth(*auth), params=params, verify=not os.environ.get("SKIP_TLS_VERIFY", "").lower() == "true", timeout=30) # Set SKIP_TLS_VERIFY=true for self-signed certs in lab environments
resp.raise_for_status()
return resp.json()
except requests.RequestException as e:
logger.error("Arkime API error %s: %s", endpoint, e)
return None
def search_sessions(base_url, auth, expression, date_range=1, length=500):
"""Search Arkime sessions with an expression filter."""
params = {
"date": date_range,
"expression": expression,
"length": length,
"order": "lastPacket:desc",
}
data = arkime_request(base_url, "/api/sessions", auth, params)
if data and "data" in data:
logger.info("Found %d sessions for expression: %s", len(data["data"]), expression)
return data["data"]
return []
def get_connections(base_url, auth, expression, date_range=1):
"""Get connection graph data from Arkime."""
params = {"date": date_range, "expression": expression}
data = arkime_request(base_url, "/api/connections", auth, params)
if data:
nodes = data.get("nodes", [])
links = data.get("links", [])
logger.info("Connection graph: %d nodes, %d links", len(nodes), len(links))
return {"nodes": nodes, "links": links}
return {"nodes": [], "links": []}
def get_spi_view(base_url, auth, expression, date_range=1):
"""Get SPI view field statistics from Arkime."""
params = {"date": date_range, "expression": expression, "spi": "srcIp,dstIp,dstPort"}
data = arkime_request(base_url, "/api/spiview", auth, params)
return data if data else {}
def detect_beaconing(sessions, interval_threshold=0.15):
"""Detect C2 beaconing by analyzing connection intervals."""
connections = defaultdict(list)
for s in sessions:
key = (s.get("srcIp", ""), s.get("dstIp", ""), s.get("dstPort", 0))
connections[key].append(s.get("lastPacket", 0))
beacons = []
for (src, dst, port), timestamps in connections.items():
if len(timestamps) < 10:
continue
timestamps.sort()
intervals = [timestamps[i + 1] - timestamps[i] for i in range(len(timestamps) - 1)]
if not intervals:
continue
avg_interval = sum(intervals) / len(intervals)
if avg_interval == 0:
continue
std_dev = (sum((i - avg_interval) ** 2 for i in intervals) / len(intervals)) ** 0.5
jitter_ratio = std_dev / avg_interval
if jitter_ratio < interval_threshold:
beacons.append({
"src_ip": src,
"dst_ip": dst,
"dst_port": port,
"session_count": len(timestamps),
"avg_interval_sec": round(avg_interval / 1000, 1),
"jitter_ratio": round(jitter_ratio, 4),
"confidence": "high" if jitter_ratio < 0.05 else "medium",
"severity": "critical",
})
logger.warning("Beaconing: %s -> %s:%d (jitter: %.4f)", src, dst, port, jitter_ratio)
return beacons
def detect_dns_tunneling(sessions, query_len_threshold=50):
"""Detect DNS tunneling via abnormally long DNS queries."""
dns_sessions = [s for s in sessions if s.get("dstPort") == 53]
suspicious = []
src_stats = defaultdict(lambda: {"count": 0, "total_bytes": 0})
for s in dns_sessions:
src = s.get("srcIp", "")
src_stats[src]["count"] += 1
src_stats[src]["total_bytes"] += s.get("srcBytes", 0) + s.get("dstBytes", 0)
for src, stats in src_stats.items():
avg_bytes = stats["total_bytes"] / max(stats["count"], 1)
if stats["count"] > 100 and avg_bytes > query_len_threshold:
suspicious.append({
"src_ip": src,
"dns_query_count": stats["count"],
"avg_bytes_per_query": round(avg_bytes, 1),
"total_bytes": stats["total_bytes"],
"severity": "high",
"indicator": "DNS tunneling - high volume with large payloads",
})
return suspicious
def detect_large_transfers(sessions, threshold_mb=100):
"""Detect unusually large data transfers."""
threshold_bytes = threshold_mb * 1024 * 1024
large = []
for s in sessions:
total = s.get("srcBytes", 0) + s.get("dstBytes", 0)
if total > threshold_bytes:
large.append({
"src_ip": s.get("srcIp", ""),
"dst_ip": s.get("dstIp", ""),
"dst_port": s.get("dstPort", 0),
"total_bytes": total,
"total_mb": round(total / (1024 * 1024), 2),
"severity": "high",
})
return large
def detect_tls_anomalies(sessions):
"""Detect TLS certificate anomalies (self-signed, expired, unusual issuers)."""
anomalies = []
for s in sessions:
tls = s.get("tls", {})
if not tls:
continue
ja3 = s.get("srcJa3", "")
issuer_cn = tls.get("issuerCN", "")
not_after = tls.get("notAfter", 0)
if issuer_cn and issuer_cn == tls.get("subjectCN", ""):
anomalies.append({
"src_ip": s.get("srcIp", ""),
"dst_ip": s.get("dstIp", ""),
"issue": "self-signed certificate",
"issuer": issuer_cn,
"severity": "medium",
})
if not_after and not_after < int(datetime.utcnow().timestamp() * 1000):
anomalies.append({
"src_ip": s.get("srcIp", ""),
"dst_ip": s.get("dstIp", ""),
"issue": "expired certificate",
"issuer": issuer_cn,
"severity": "medium",
})
return anomalies
def generate_report(beacons, dns_tunneling, large_transfers, tls_anomalies, session_count):
"""Generate network traffic analysis report."""
all_findings = beacons + dns_tunneling + large_transfers + tls_anomalies
critical = [f for f in all_findings if f.get("severity") == "critical"]
report = {
"timestamp": datetime.utcnow().isoformat(),
"sessions_analyzed": session_count,
"findings_total": len(all_findings),
"critical_count": len(critical),
"beaconing_detected": beacons,
"dns_tunneling": dns_tunneling,
"large_transfers": large_transfers,
"tls_anomalies": tls_anomalies,
}
print(f"ARKIME REPORT: {len(all_findings)} findings ({len(critical)} critical) from {session_count} sessions")
return report
def main():
parser = argparse.ArgumentParser(description="Arkime Network Traffic Analysis Agent")
parser.add_argument("--arkime-url", required=True, help="Arkime viewer URL")
parser.add_argument("--user", required=True)
parser.add_argument("--password", required=True)
parser.add_argument("--expression", default="*", help="Arkime search expression")
parser.add_argument("--date-range", type=int, default=1, help="Date range in hours")
parser.add_argument("--output", default="arkime_report.json")
args = parser.parse_args()
auth = (args.user, args.password)
sessions = search_sessions(args.arkime_url, auth, args.expression, args.date_range)
beacons = detect_beaconing(sessions)
dns_tunnel = detect_dns_tunneling(sessions)
large = detect_large_transfers(sessions)
tls = detect_tls_anomalies(sessions)
report = generate_report(beacons, dns_tunnel, large, tls, len(sessions))
with open(args.output, "w") as f:
json.dump(report, f, indent=2)
logger.info("Report saved to %s", args.output)
if __name__ == "__main__":
main()
Keep exploring