mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-12 06:04:56 +03:00
c47eed6a64
- Fix 25 shell=True subprocess calls with list-based commands - Fix 49 verify=False in defensive skills (env-var override) - Add timeout to 231 HTTP/subprocess/socket calls - Fix 6 SQL injection patterns with whitelist validation - Replace 8 __import__() with standard imports - Remove 701 unused imports across 442 files - Add authorized-testing disclaimers to all offensive skills - Complete 11 incomplete skill directories - Expand 10 stub SKILL.md files with full content - Fix 2 YAML parse errors in frontmatter - Fix 5 pre-existing syntax errors - Convert 22 hardcoded paths/ports to environment variables - Back up 21 redundant skill pairs to .bak - Fix 2 global declaration errors - 724/724 skills with full folder anatomy (SKILL.md + agent.py + api-reference.md + LICENSE) - 0 compile errors across all 724 agent.py files
191 lines
7.6 KiB
Python
191 lines
7.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Network covert channel detection agent for malware traffic analysis.
|
|
|
|
Detects DNS tunneling, ICMP covert channels, HTTP header steganography,
|
|
and protocol abuse in PCAP captures using scapy.
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import json
|
|
import math
|
|
from collections import Counter, defaultdict
|
|
|
|
try:
|
|
from scapy.all import rdpcap, DNS, DNSQR, ICMP, IP, TCP, Raw
|
|
HAS_SCAPY = True
|
|
except ImportError:
|
|
HAS_SCAPY = False
|
|
|
|
|
|
def shannon_entropy(data):
|
|
"""Calculate Shannon entropy of byte data."""
|
|
if not data:
|
|
return 0.0
|
|
freq = Counter(data)
|
|
length = len(data)
|
|
return -sum((c / length) * math.log2(c / length) for c in freq.values())
|
|
|
|
|
|
def detect_dns_tunneling(packets, entropy_threshold=3.5, length_threshold=50):
|
|
"""Detect DNS tunneling by analyzing query name entropy and length."""
|
|
findings = []
|
|
dns_queries = defaultdict(list)
|
|
for pkt in packets:
|
|
if pkt.haslayer(DNSQR):
|
|
qname = pkt[DNSQR].qname.decode("utf-8", errors="replace").rstrip(".")
|
|
src = pkt[IP].src if pkt.haslayer(IP) else "?"
|
|
labels = qname.split(".")
|
|
subdomain = ".".join(labels[:-2]) if len(labels) > 2 else qname
|
|
entropy = shannon_entropy(subdomain.encode())
|
|
base_domain = ".".join(labels[-2:]) if len(labels) >= 2 else qname
|
|
dns_queries[base_domain].append({
|
|
"query": qname, "src": src, "entropy": round(entropy, 3),
|
|
"subdomain_len": len(subdomain),
|
|
})
|
|
if entropy > entropy_threshold and len(subdomain) > length_threshold:
|
|
findings.append({
|
|
"type": "dns_tunneling", "query": qname, "src": src,
|
|
"entropy": round(entropy, 3),
|
|
"subdomain_length": len(subdomain), "severity": "HIGH",
|
|
})
|
|
volume_findings = []
|
|
for domain, queries in dns_queries.items():
|
|
if len(queries) > 100:
|
|
avg_entropy = sum(q["entropy"] for q in queries) / len(queries)
|
|
if avg_entropy > 3.0:
|
|
volume_findings.append({
|
|
"type": "dns_high_volume", "domain": domain,
|
|
"query_count": len(queries),
|
|
"avg_entropy": round(avg_entropy, 3), "severity": "HIGH",
|
|
})
|
|
return findings[:50], volume_findings
|
|
|
|
|
|
def detect_icmp_covert_channel(packets, payload_threshold=64):
|
|
"""Detect ICMP covert channels via payload analysis."""
|
|
findings = []
|
|
icmp_flows = defaultdict(list)
|
|
for pkt in packets:
|
|
if pkt.haslayer(ICMP) and pkt.haslayer(Raw):
|
|
payload = bytes(pkt[Raw].load)
|
|
src = pkt[IP].src if pkt.haslayer(IP) else "?"
|
|
dst = pkt[IP].dst if pkt.haslayer(IP) else "?"
|
|
entropy = shannon_entropy(payload)
|
|
flow_key = f"{src}->{dst}"
|
|
icmp_flows[flow_key].append(payload)
|
|
if len(payload) > payload_threshold and entropy > 5.0:
|
|
findings.append({
|
|
"type": "icmp_covert", "src": src, "dst": dst,
|
|
"icmp_type": pkt[ICMP].type,
|
|
"payload_size": len(payload),
|
|
"entropy": round(entropy, 3), "severity": "HIGH",
|
|
})
|
|
for flow, payloads in icmp_flows.items():
|
|
total_bytes = sum(len(p) for p in payloads)
|
|
if total_bytes > 10000:
|
|
findings.append({
|
|
"type": "icmp_exfiltration", "flow": flow,
|
|
"total_bytes": total_bytes,
|
|
"packet_count": len(payloads), "severity": "HIGH",
|
|
})
|
|
return findings[:50]
|
|
|
|
|
|
def detect_http_header_covert(packets):
|
|
"""Detect covert data in HTTP headers."""
|
|
findings = []
|
|
for pkt in packets:
|
|
if pkt.haslayer(TCP) and pkt.haslayer(Raw):
|
|
try:
|
|
payload = bytes(pkt[Raw].load).decode("utf-8", errors="replace")
|
|
except Exception:
|
|
continue
|
|
if not payload.startswith(("GET ", "POST ", "HTTP/")):
|
|
continue
|
|
for line in payload.split("\r\n"):
|
|
if ":" not in line:
|
|
continue
|
|
header, _, value = line.partition(":")
|
|
value = value.strip()
|
|
if header.lower() == "cookie" and len(value) > 500:
|
|
entropy = shannon_entropy(value.encode())
|
|
if entropy > 4.5:
|
|
findings.append({
|
|
"type": "http_cookie_exfil", "header": header,
|
|
"value_length": len(value),
|
|
"entropy": round(entropy, 3), "severity": "MEDIUM",
|
|
})
|
|
if header.lower().startswith("x-") and len(value) > 100:
|
|
entropy = shannon_entropy(value.encode())
|
|
if entropy > 4.0:
|
|
findings.append({
|
|
"type": "http_custom_header", "header": header,
|
|
"value_length": len(value),
|
|
"entropy": round(entropy, 3), "severity": "MEDIUM",
|
|
})
|
|
return findings[:50]
|
|
|
|
|
|
def detect_protocol_anomalies(packets):
|
|
"""Detect protocol-level anomalies indicating covert communication."""
|
|
findings = []
|
|
for pkt in packets:
|
|
if pkt.haslayer(IP):
|
|
proto = pkt[IP].proto
|
|
if proto not in (1, 6, 17, 47, 50, 51):
|
|
findings.append({
|
|
"type": "unusual_ip_proto", "protocol": proto,
|
|
"src": pkt[IP].src, "dst": pkt[IP].dst, "severity": "MEDIUM",
|
|
})
|
|
return findings[:50]
|
|
|
|
|
|
def generate_report(pcap_path, dns_f, dns_v, icmp_f, http_f, proto_f):
|
|
"""Generate covert channel analysis report."""
|
|
total = len(dns_f) + len(icmp_f) + len(http_f) + len(proto_f)
|
|
return {
|
|
"pcap_file": pcap_path, "total_findings": total,
|
|
"dns_tunneling": {"count": len(dns_f), "findings": dns_f[:10]},
|
|
"dns_volume_anomalies": dns_v[:10],
|
|
"icmp_covert": {"count": len(icmp_f), "findings": icmp_f[:10]},
|
|
"http_header_covert": {"count": len(http_f), "findings": http_f[:10]},
|
|
"protocol_anomalies": {"count": len(proto_f), "findings": proto_f[:10]},
|
|
"risk_level": "HIGH" if total > 10 else "MEDIUM" if total > 3 else "LOW",
|
|
}
|
|
|
|
|
|
if __name__ == "__main__":
|
|
print("=" * 60)
|
|
print("Network Covert Channel Detection Agent")
|
|
print("DNS tunneling, ICMP covert, HTTP header, protocol abuse")
|
|
print("=" * 60)
|
|
|
|
pcap = sys.argv[1] if len(sys.argv) > 1 else None
|
|
if not pcap or not os.path.exists(pcap):
|
|
print("\n[DEMO] Usage: python agent.py <capture.pcap>")
|
|
print(f" scapy available: {HAS_SCAPY}")
|
|
sys.exit(0)
|
|
if not HAS_SCAPY:
|
|
print("[!] Install scapy: pip install scapy")
|
|
sys.exit(1)
|
|
|
|
print(f"\n[*] Loading: {pcap}")
|
|
packets = rdpcap(pcap)
|
|
print(f"[*] Packets: {len(packets)}")
|
|
|
|
dns_f, dns_v = detect_dns_tunneling(packets)
|
|
icmp_f = detect_icmp_covert_channel(packets)
|
|
http_f = detect_http_header_covert(packets)
|
|
proto_f = detect_protocol_anomalies(packets)
|
|
report = generate_report(pcap, dns_f, dns_v, icmp_f, http_f, proto_f)
|
|
|
|
print(f"\n--- DNS Tunneling ({len(dns_f)}) ---")
|
|
for f in dns_f[:5]:
|
|
print(f" {f['src']} | entropy={f['entropy']} | {f['query'][:60]}")
|
|
print(f"\n--- ICMP Covert ({len(icmp_f)}) ---")
|
|
for f in icmp_f[:5]:
|
|
print(f" {f.get('flow', f.get('src','?'))} | {f.get('payload_size', f.get('total_bytes','?'))}B")
|
|
print(f"\n[*] Risk: {report['risk_level']}")
|
|
print(json.dumps(report, indent=2, default=str))
|