Files
mukul975 c47eed6a64 Production hardening: security fixes, code quality, 724 skills complete
- 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
2026-03-19 13:26:49 +01:00

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")