mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-12 14:14: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
254 lines
9.1 KiB
Python
254 lines
9.1 KiB
Python
#!/usr/bin/env python3
|
|
"""Cuckoo Sandbox behavioral analysis agent for automated malware detonation and reporting."""
|
|
|
|
import json
|
|
import os
|
|
import sys
|
|
import hashlib
|
|
|
|
try:
|
|
import requests
|
|
HAS_REQUESTS = True
|
|
except ImportError:
|
|
HAS_REQUESTS = False
|
|
|
|
|
|
CUCKOO_API = os.environ.get("CUCKOO_API", "http://localhost:8090")
|
|
CUCKOO_STORAGE = os.environ.get("CUCKOO_STORAGE", "/opt/cuckoo/storage/analyses")
|
|
|
|
|
|
def submit_file(filepath, timeout=300, machine=None, package=None):
|
|
"""Submit a malware sample to Cuckoo via REST API."""
|
|
if not HAS_REQUESTS:
|
|
return None
|
|
url = f"{CUCKOO_API}/tasks/create/file"
|
|
files = {"file": (os.path.basename(filepath), open(filepath, "rb"))}
|
|
data = {"timeout": timeout}
|
|
if machine:
|
|
data["machine"] = machine
|
|
if package:
|
|
data["package"] = package
|
|
resp = requests.post(url, files=files, data=data, timeout=30)
|
|
if resp.status_code == 200:
|
|
return resp.json().get("task_id")
|
|
return None
|
|
|
|
|
|
def submit_url(url_to_analyze, timeout=300):
|
|
"""Submit a URL to Cuckoo for analysis."""
|
|
if not HAS_REQUESTS:
|
|
return None
|
|
url = f"{CUCKOO_API}/tasks/create/url"
|
|
data = {"url": url_to_analyze, "timeout": timeout}
|
|
resp = requests.post(url, data=data, timeout=30)
|
|
if resp.status_code == 200:
|
|
return resp.json().get("task_id")
|
|
return None
|
|
|
|
|
|
def get_task_status(task_id):
|
|
"""Check the status of a Cuckoo analysis task."""
|
|
if not HAS_REQUESTS:
|
|
return None
|
|
url = f"{CUCKOO_API}/tasks/view/{task_id}"
|
|
resp = requests.get(url, timeout=30)
|
|
if resp.status_code == 200:
|
|
return resp.json().get("task", {}).get("status")
|
|
return None
|
|
|
|
|
|
def load_report(task_id, report_dir=None):
|
|
"""Load a Cuckoo JSON report from disk."""
|
|
if report_dir is None:
|
|
report_dir = CUCKOO_STORAGE
|
|
report_path = os.path.join(report_dir, str(task_id), "reports", "report.json")
|
|
if os.path.exists(report_path):
|
|
with open(report_path, "r") as f:
|
|
return json.load(f)
|
|
return None
|
|
|
|
|
|
def analyze_processes(report):
|
|
"""Extract and analyze the process tree from the Cuckoo report."""
|
|
processes = []
|
|
for proc in report.get("behavior", {}).get("processes", []):
|
|
pid = proc.get("pid")
|
|
ppid = proc.get("ppid")
|
|
name = proc.get("process_name")
|
|
suspicious_apis = []
|
|
dangerous_apis = [
|
|
"CreateRemoteThread", "VirtualAllocEx", "WriteProcessMemory",
|
|
"NtCreateThreadEx", "RegSetValueExA", "URLDownloadToFileA",
|
|
"ShellExecuteA", "ShellExecuteW", "WinExec", "CreateProcessA",
|
|
"NtWriteVirtualMemory", "QueueUserAPC",
|
|
]
|
|
for call in proc.get("calls", []):
|
|
if call.get("api") in dangerous_apis:
|
|
args = {arg["name"]: arg["value"] for arg in call.get("arguments", [])}
|
|
suspicious_apis.append({"api": call["api"], "args": args})
|
|
processes.append({
|
|
"pid": pid,
|
|
"ppid": ppid,
|
|
"name": name,
|
|
"suspicious_api_calls": len(suspicious_apis),
|
|
"top_suspicious": suspicious_apis[:10],
|
|
})
|
|
return processes
|
|
|
|
|
|
def analyze_network(report):
|
|
"""Extract network activity from the Cuckoo report."""
|
|
network = report.get("network", {})
|
|
return {
|
|
"dns": [
|
|
{"request": d.get("request"), "answers": d.get("answers", [])}
|
|
for d in network.get("dns", [])
|
|
],
|
|
"http": [
|
|
{"method": h.get("method"), "host": h.get("host"),
|
|
"uri": h.get("uri"), "body_size": len(h.get("body", ""))}
|
|
for h in network.get("http", [])
|
|
],
|
|
"tcp_connections": [
|
|
{"src": t.get("src"), "sport": t.get("sport"),
|
|
"dst": t.get("dst"), "dport": t.get("dport")}
|
|
for t in network.get("tcp", [])
|
|
],
|
|
"udp_connections": [
|
|
{"src": u.get("src"), "sport": u.get("sport"),
|
|
"dst": u.get("dst"), "dport": u.get("dport")}
|
|
for u in network.get("udp", [])
|
|
],
|
|
}
|
|
|
|
|
|
def analyze_dropped_files(report):
|
|
"""Extract dropped file information from the report."""
|
|
dropped = []
|
|
for d in report.get("dropped", []):
|
|
dropped.append({
|
|
"filepath": d.get("filepath", ""),
|
|
"sha256": d.get("sha256", ""),
|
|
"size": d.get("size", 0),
|
|
"type": d.get("type", ""),
|
|
})
|
|
return dropped
|
|
|
|
|
|
def analyze_signatures(report):
|
|
"""Extract triggered behavioral signatures."""
|
|
signatures = []
|
|
for sig in report.get("signatures", []):
|
|
marks = []
|
|
for mark in sig.get("marks", []):
|
|
if mark.get("ioc"):
|
|
marks.append(mark["ioc"])
|
|
elif mark.get("call"):
|
|
marks.append(mark["call"].get("api", ""))
|
|
signatures.append({
|
|
"name": sig.get("name"),
|
|
"severity": sig.get("severity"),
|
|
"description": sig.get("description"),
|
|
"marks": marks[:5],
|
|
})
|
|
return sorted(signatures, key=lambda x: x.get("severity", 0), reverse=True)
|
|
|
|
|
|
def analyze_registry(report):
|
|
"""Extract registry modifications from behavior summary."""
|
|
summary = report.get("behavior", {}).get("summary", {})
|
|
return {
|
|
"keys_modified": summary.get("keys", [])[:20],
|
|
"files_created": summary.get("files", [])[:20],
|
|
"mutexes": summary.get("mutexes", [])[:10],
|
|
}
|
|
|
|
|
|
def generate_summary(report, processes, network, dropped, signatures, registry):
|
|
"""Generate a consolidated analysis summary."""
|
|
info = report.get("info", {})
|
|
score = info.get("score", 0)
|
|
return {
|
|
"task_id": info.get("id"),
|
|
"sample": info.get("category", "file"),
|
|
"analysis_time": info.get("duration", 0),
|
|
"machine": info.get("machine", {}).get("name", ""),
|
|
"threat_score": score,
|
|
"process_count": len(processes),
|
|
"suspicious_api_total": sum(p["suspicious_api_calls"] for p in processes),
|
|
"dns_queries": len(network["dns"]),
|
|
"http_requests": len(network["http"]),
|
|
"tcp_connections": len(network["tcp_connections"]),
|
|
"dropped_files": len(dropped),
|
|
"signatures_triggered": len(signatures),
|
|
"high_severity_sigs": len([s for s in signatures if s["severity"] >= 3]),
|
|
"registry_keys_modified": len(registry["keys_modified"]),
|
|
"files_created": len(registry["files_created"]),
|
|
}
|
|
|
|
|
|
if __name__ == "__main__":
|
|
print("=" * 60)
|
|
print("Cuckoo Sandbox Behavioral Analysis Agent")
|
|
print("Automated malware detonation and report parsing")
|
|
print("=" * 60)
|
|
|
|
if len(sys.argv) > 1:
|
|
arg = sys.argv[1]
|
|
|
|
# Check if argument is a report JSON path
|
|
if arg.endswith(".json") and os.path.exists(arg):
|
|
print(f"\n[*] Loading report: {arg}")
|
|
with open(arg, "r") as f:
|
|
report = json.load(f)
|
|
elif arg.isdigit():
|
|
print(f"\n[*] Loading report for task ID: {arg}")
|
|
report = load_report(int(arg))
|
|
elif os.path.exists(arg):
|
|
print(f"\n[*] Submitting sample: {arg}")
|
|
sha256 = hashlib.sha256(open(arg, "rb").read()).hexdigest()
|
|
print(f"[*] SHA-256: {sha256}")
|
|
task_id = submit_file(arg)
|
|
if task_id:
|
|
print(f"[*] Task submitted: ID={task_id}")
|
|
print(f"[*] Monitor at: {CUCKOO_API.replace('8090', '8080')}/analysis/{task_id}/")
|
|
else:
|
|
print("[ERROR] Failed to submit. Check Cuckoo API connection.")
|
|
sys.exit(0)
|
|
else:
|
|
report = None
|
|
|
|
if report:
|
|
processes = analyze_processes(report)
|
|
network = analyze_network(report)
|
|
dropped = analyze_dropped_files(report)
|
|
signatures = analyze_signatures(report)
|
|
registry = analyze_registry(report)
|
|
summary = generate_summary(report, processes, network, dropped, signatures, registry)
|
|
|
|
print(f"\n--- Analysis Summary ---")
|
|
print(f" Score: {summary['threat_score']}/10")
|
|
print(f" Processes: {summary['process_count']}")
|
|
print(f" Suspicious APIs: {summary['suspicious_api_total']}")
|
|
print(f" Signatures: {summary['signatures_triggered']} "
|
|
f"({summary['high_severity_sigs']} high severity)")
|
|
|
|
print(f"\n--- Network ---")
|
|
print(f" DNS: {summary['dns_queries']}, HTTP: {summary['http_requests']}, "
|
|
f"TCP: {summary['tcp_connections']}")
|
|
for http in network["http"][:5]:
|
|
print(f" {http['method']} {http['host']}{http['uri']}")
|
|
|
|
print(f"\n--- Dropped Files ---")
|
|
for d in dropped[:5]:
|
|
print(f" {d['filepath']} ({d['size']} bytes)")
|
|
|
|
print(f"\n--- Top Signatures ---")
|
|
for s in signatures[:5]:
|
|
print(f" [{s['severity']}/5] {s['name']}: {s['description']}")
|
|
else:
|
|
print(f"\n[DEMO] Usage:")
|
|
print(f" python agent.py <sample.exe> # Submit to Cuckoo")
|
|
print(f" python agent.py <task_id> # Parse existing report")
|
|
print(f" python agent.py <report.json> # Parse JSON report file")
|