npx skills add mukul975/Anthropic-Cybersecurity-SkillsMITRE ATT&CK
Overview
CAPE (Config And Payload Extraction) is an open-source malware sandbox derived from Cuckoo that automates behavioral analysis, payload dumping, and configuration extraction. CAPEv2 features API hooking for behavioral instrumentation, captures files created/modified/deleted during execution, records network traffic in PCAP format, and includes 70+ custom configuration extractors (cape-parsers) for families like Emotet, TrickBot, Cobalt Strike, AsyncRAT, and Rhadamanthys. The signature system includes 1000+ behavioral signatures detecting evasion techniques, persistence, credential theft, and ransomware behavior. CAPE's debugger enables dynamic anti-evasion bypasses combining debugger actions within YARA signatures. Recommended deployment: Ubuntu LTS host with Windows 10 21H2 guest VM.
When to Use
- When conducting security assessments that involve performing automated malware analysis with cape
- 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
- Ubuntu 22.04 LTS server (8+ CPU cores, 32GB+ RAM, 500GB+ SSD)
- KVM/QEMU virtualization support
- Windows 10 21H2 guest image
- Python 3.9+ with CAPEv2 dependencies
- Network configuration for isolated analysis network
Workflow
Step 1: Submit and Analyze Samples via API
#!/usr/bin/env python3
"""CAPE sandbox API client for automated malware submission and analysis."""
import requests
import json
import time
import sys
from pathlib import Path
class CAPEClient:
def __init__(self, base_url="http://localhost:8000", api_token=None):
self.base_url = base_url.rstrip("/")
self.headers = {}
if api_token:
self.headers["Authorization"] = f"Token {api_token}"
def submit_file(self, filepath, options=None):
"""Submit a file for analysis."""
url = f"{self.base_url}/apiv2/tasks/create/file/"
files = {"file": open(filepath, "rb")}
data = options or {}
data.setdefault("timeout", 120)
data.setdefault("enforce_timeout", False)
resp = requests.post(url, files=files, data=data, headers=self.headers)
resp.raise_for_status()
result = resp.json()
task_id = result.get("data", {}).get("task_ids", [None])[0]
print(f"[+] Submitted {filepath} -> Task ID: {task_id}")
return task_id
def get_status(self, task_id):
"""Check task analysis status."""
url = f"{self.base_url}/apiv2/tasks/status/{task_id}/"
resp = requests.get(url, headers=self.headers)
return resp.json().get("data", "unknown")
def wait_for_completion(self, task_id, poll_interval=15, max_wait=600):
"""Wait for analysis to complete."""
elapsed = 0
while elapsed < max_wait:
status = self.get_status(task_id)
if status == "reported":
print(f"[+] Task {task_id} completed")
return True
time.sleep(poll_interval)
elapsed += poll_interval
print(f" Waiting... ({elapsed}s, status: {status})")
return False
def get_report(self, task_id):
"""Retrieve full analysis report."""
url = f"{self.base_url}/apiv2/tasks/get/report/{task_id}/"
resp = requests.get(url, headers=self.headers)
return resp.json()
def get_config(self, task_id):
"""Get extracted malware configuration."""
report = self.get_report(task_id)
configs = report.get("CAPE", {}).get("configs", [])
return configs
def get_dropped_files(self, task_id):
"""List files dropped during analysis."""
report = self.get_report(task_id)
return report.get("dropped", [])
def get_network_iocs(self, task_id):
"""Extract network IOCs from analysis."""
report = self.get_report(task_id)
network = report.get("network", {})
iocs = {
"dns": [d.get("request") for d in network.get("dns", [])],
"http": [h.get("uri") for h in network.get("http", [])],
"tcp": [f"{h.get('dst')}:{h.get('dport')}"
for h in network.get("tcp", [])],
}
return iocs
def analyze_sample(self, filepath):
"""Full automated analysis pipeline."""
task_id = self.submit_file(filepath)
if not task_id:
return None
if self.wait_for_completion(task_id):
report = {
"task_id": task_id,
"config": self.get_config(task_id),
"network_iocs": self.get_network_iocs(task_id),
"dropped_files": len(self.get_dropped_files(task_id)),
}
return report
return None
if __name__ == "__main__":
if len(sys.argv) < 2:
print(f"Usage: {sys.argv[0]} <malware_sample> [cape_url]")
sys.exit(1)
url = sys.argv[2] if len(sys.argv) > 2 else "http://localhost:8000"
client = CAPEClient(url)
result = client.analyze_sample(sys.argv[1])
if result:
print(json.dumps(result, indent=2))Validation Criteria
- Samples submitted and analyzed within configured timeout
- Behavioral signatures triggered for known malware families
- Malware configurations extracted by cape-parsers
- Network traffic captured and IOCs extracted
- Dropped files and payloads collected for further analysis
- Anti-evasion bypasses effective against sandbox-aware malware
References
References and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 3
api-reference.md5.7 KB
API Reference: CAPE Sandbox Automated Malware Analysis
Libraries Used
| Library | Purpose |
|---|---|
requests |
HTTP client for CAPE REST API v2 |
json |
Parse analysis reports and task metadata |
os |
Read CAPE_URL and CAPE_API_KEY environment variables |
time |
Poll task status until analysis completes |
Installation
pip install requestsAuthentication
import requests
import os
CAPE_URL = os.environ.get("CAPE_URL", "http://cape.example.com:8000")
CAPE_KEY = os.environ.get("CAPE_API_KEY", "")
headers = {"Authorization": f"Token {CAPE_KEY}"} if CAPE_KEY else {}REST API v2 Endpoints
| Method | Endpoint | Description |
|---|---|---|
| POST | /apiv2/tasks/create/file/ |
Submit a file for analysis |
| POST | /apiv2/tasks/create/url/ |
Submit a URL for analysis |
| GET | /apiv2/tasks/list/ |
List all analysis tasks |
| GET | /apiv2/tasks/view/{id}/ |
Get task status and metadata |
| GET | /apiv2/tasks/report/{id}/ |
Get full analysis report |
| GET | /apiv2/tasks/report/{id}/lite/ |
Get lightweight report |
| DELETE | /apiv2/tasks/delete/{id}/ |
Delete a task and its data |
| GET | /apiv2/tasks/screenshots/{id}/ |
Get analysis screenshots |
| GET | /apiv2/tasks/procmemory/{id}/ |
Get process memory dumps |
| GET | /apiv2/files/view/sha256/{hash}/ |
Look up file by SHA-256 |
| GET | /apiv2/files/get/{sha256}/ |
Download the sample binary |
| GET | /apiv2/pcap/get/{id}/ |
Download PCAP network capture |
| GET | /apiv2/machines/list/ |
List analysis VMs |
| GET | /apiv2/cuckoo/status/ |
Server status and version |
Core Operations
Submit a File for Analysis
def submit_file(file_path, timeout_mins=5, machine=None):
files = {"file": open(file_path, "rb")}
data = {
"timeout": timeout_mins * 60,
"enforce_timeout": True,
"options": "procmemdump=yes,import_reconstruction=yes",
}
if machine:
data["machine"] = machine
resp = requests.post(
f"{CAPE_URL}/apiv2/tasks/create/file/",
files=files,
data=data,
headers=headers,
timeout=60,
)
resp.raise_for_status()
result = resp.json()
return result["data"]["task_ids"][0]Submit a URL for Analysis
def submit_url(url, timeout_mins=3):
resp = requests.post(
f"{CAPE_URL}/apiv2/tasks/create/url/",
data={
"url": url,
"timeout": timeout_mins * 60,
"options": "procmemdump=yes",
},
headers=headers,
timeout=30,
)
resp.raise_for_status()
return resp.json()["data"]["task_ids"][0]Poll Task Until Complete
import time
def wait_for_task(task_id, poll_interval=30, max_wait=600):
elapsed = 0
while elapsed < max_wait:
resp = requests.get(
f"{CAPE_URL}/apiv2/tasks/view/{task_id}/",
headers=headers,
timeout=30,
)
status = resp.json()["data"]["status"]
if status == "reported":
return True
if status in ("failed_analysis", "failed_processing"):
raise RuntimeError(f"Task {task_id} failed: {status}")
time.sleep(poll_interval)
elapsed += poll_interval
raise TimeoutError(f"Task {task_id} did not complete within {max_wait}s")Retrieve Analysis Report
def get_report(task_id, lite=False):
endpoint = "lite" if lite else ""
resp = requests.get(
f"{CAPE_URL}/apiv2/tasks/report/{task_id}/{endpoint}",
headers=headers,
timeout=120,
)
resp.raise_for_status()
return resp.json()Extract Key Findings from Report
def extract_findings(report):
info = report.get("info", {})
findings = {
"score": info.get("score", 0),
"duration": info.get("duration", 0),
"signatures": [],
"network_iocs": {"domains": [], "ips": [], "urls": []},
"dropped_files": [],
"yara_matches": [],
}
# Behavioral signatures
for sig in report.get("signatures", []):
findings["signatures"].append({
"name": sig["name"],
"severity": sig["severity"],
"description": sig["description"],
})
# Network IOCs
network = report.get("network", {})
findings["network_iocs"]["domains"] = [
d["domain"] for d in network.get("domains", [])
]
findings["network_iocs"]["ips"] = [
h["ip"] for h in network.get("hosts", [])
]
# YARA matches
for target_yara in report.get("target", {}).get("file", {}).get("yara", []):
findings["yara_matches"].append(target_yara["name"])
return findingsDownload Network PCAP
def download_pcap(task_id, output_path):
resp = requests.get(
f"{CAPE_URL}/apiv2/pcap/get/{task_id}/",
headers=headers,
timeout=60,
)
resp.raise_for_status()
with open(output_path, "wb") as f:
f.write(resp.content)Output Format
{
"info": {
"id": 42,
"score": 8.5,
"duration": 120,
"machine": {"name": "win10-01", "label": "win10-01"},
"started": "2025-01-15T10:30:00",
"ended": "2025-01-15T10:32:00"
},
"signatures": [
{"name": "ransomware_bcdedit", "severity": 5, "description": "Modifies boot configuration"},
{"name": "creates_exe", "severity": 3, "description": "Creates executable files on disk"}
],
"network": {
"hosts": [{"ip": "198.51.100.42", "country": "US"}],
"domains": [{"domain": "c2.evil.example.com", "ip": "198.51.100.42"}]
},
"target": {
"file": {
"name": "sample.exe",
"size": 245760,
"sha256": "a1b2c3d4e5f6..."
}
}
}standards.md0.3 KB
Standards Reference - performing-automated-malware-analysis-with-cape
Applicable Standards
- MITRE ATT&CK Framework
- NIST SP 800-83 Guide to Malware Incident Prevention
- NIST SP 800-86 Guide to Integrating Forensic Techniques
Related MITRE ATT&CK Techniques
See SKILL.md for specific technique mappings.
workflows.md0.5 KB
Analysis Workflows - performing-automated-malware-analysis-with-cape
Primary Workflow
[Sample Collection] --> [Static Analysis] --> [Dynamic Analysis] --> [IOC Extraction]
|
v
[Report Generation]See SKILL.md for detailed step-by-step procedures.
Scripts 1
agent.py10.5 KB
#!/usr/bin/env python3
"""CAPE Sandbox automated malware analysis agent.
Submits malware samples to a CAPE Sandbox instance via its REST API,
polls for analysis completion, and retrieves behavioral reports including
process trees, network activity, dropped files, and extracted configs.
"""
import argparse
import json
import os
import sys
import time
from datetime import datetime, timezone
try:
import requests
except ImportError:
print("[!] 'requests' library required: pip install requests", file=sys.stderr)
sys.exit(1)
def get_cape_config():
"""Return CAPE server URL and optional API token."""
server = os.environ.get("CAPE_URL", "http://localhost:8090")
token = os.environ.get("CAPE_API_TOKEN", "")
return server.rstrip("/"), token
def submit_file(server, token, file_path, timeout_minutes=5, machine=None):
"""Submit a file to CAPE for analysis."""
url = f"{server}/apiv2/tasks/create/file/"
headers = {"Authorization": f"Token {token}"} if token else {}
if not os.path.isfile(file_path):
print(f"[!] File not found: {file_path}", file=sys.stderr)
sys.exit(1)
data = {"timeout": timeout_minutes * 60}
if machine:
data["machine"] = machine
print(f"[*] Submitting {os.path.basename(file_path)} to CAPE...")
with open(file_path, "rb") as f:
resp = requests.post(
url,
files={"file": (os.path.basename(file_path), f)},
data=data,
headers=headers,
timeout=120,
)
resp.raise_for_status()
result = resp.json()
if result.get("error"):
print(f"[!] Submission error: {result.get('error_value', result['error'])}", file=sys.stderr)
sys.exit(1)
task_id = result.get("data", {}).get("task_ids", [None])[0]
if not task_id:
task_id = result.get("task_id") or result.get("data", {}).get("task_id")
print(f"[+] Submitted successfully, task ID: {task_id}")
return task_id
def submit_url(server, token, target_url, timeout_minutes=5):
"""Submit a URL to CAPE for analysis."""
url = f"{server}/apiv2/tasks/create/url/"
headers = {"Authorization": f"Token {token}"} if token else {}
data = {"url": target_url, "timeout": timeout_minutes * 60}
print(f"[*] Submitting URL: {target_url}")
resp = requests.post(url, data=data, headers=headers, timeout=60)
resp.raise_for_status()
result = resp.json()
task_id = result.get("data", {}).get("task_ids", [None])[0]
if not task_id:
task_id = result.get("task_id")
print(f"[+] Submitted, task ID: {task_id}")
return task_id
def poll_task_status(server, token, task_id, max_wait=600, interval=15):
"""Poll CAPE until the analysis task completes or times out."""
url = f"{server}/apiv2/tasks/status/{task_id}/"
headers = {"Authorization": f"Token {token}"} if token else {}
print(f"[*] Waiting for analysis to complete (max {max_wait}s)...")
elapsed = 0
while elapsed < max_wait:
try:
resp = requests.get(url, headers=headers, timeout=30)
resp.raise_for_status()
data = resp.json()
status = data.get("data", data.get("status", "unknown"))
if isinstance(status, dict):
status = status.get("status", "unknown")
if status in ("reported", "completed"):
print(f"[+] Analysis complete (status: {status})")
return True
if status in ("failed_analysis", "failed_processing"):
print(f"[!] Analysis failed: {status}", file=sys.stderr)
return False
print(f" Status: {status} ({elapsed}s elapsed)")
except requests.RequestException as e:
print(f" Connection error: {e}")
time.sleep(interval)
elapsed += interval
print("[!] Timed out waiting for analysis", file=sys.stderr)
return False
def get_report(server, token, task_id):
"""Retrieve the full analysis report for a completed task."""
url = f"{server}/apiv2/tasks/get/report/{task_id}/"
headers = {"Authorization": f"Token {token}"} if token else {}
resp = requests.get(url, headers=headers, timeout=120)
resp.raise_for_status()
return resp.json()
def extract_findings(report):
"""Extract structured findings from CAPE report."""
findings = []
# Signatures (behavioral detections)
for sig in report.get("signatures", []):
findings.append({
"category": "signature",
"name": sig.get("name", "Unknown"),
"severity": sig.get("severity", 0),
"description": sig.get("description", ""),
"families": sig.get("families", []),
"ttp": sig.get("ttp", {}),
})
# Network IOCs
network = report.get("network", {})
for dns_entry in network.get("dns", []):
findings.append({
"category": "network_dns",
"request": dns_entry.get("request", ""),
"type": dns_entry.get("type", ""),
"answers": [a.get("data", "") for a in dns_entry.get("answers", [])],
})
for http_entry in network.get("http", []):
findings.append({
"category": "network_http",
"method": http_entry.get("method", ""),
"uri": http_entry.get("uri", ""),
"host": http_entry.get("host", ""),
"port": http_entry.get("port", 80),
})
# Dropped files
for dropped in report.get("dropped", []):
findings.append({
"category": "dropped_file",
"name": dropped.get("name", ""),
"path": dropped.get("filepath", ""),
"type": dropped.get("type", ""),
"size": dropped.get("size", 0),
"sha256": dropped.get("sha256", ""),
})
# CAPE extracted payloads and configs
cape_data = report.get("CAPE", {})
if isinstance(cape_data, dict):
for cape_item in cape_data.get("payloads", []):
findings.append({
"category": "cape_payload",
"name": cape_item.get("name", ""),
"module": cape_item.get("module_path", ""),
"sha256": cape_item.get("sha256", ""),
"cape_type": cape_item.get("cape_type", ""),
})
for config in cape_data.get("configs", []):
findings.append({
"category": "cape_config",
"family": config.get("family", "unknown"),
"config_data": config,
})
return findings
def format_summary(report, findings):
"""Print human-readable analysis summary."""
info = report.get("info", {})
target = report.get("target", {})
score = report.get("malscore", info.get("score", 0))
print(f"\n{'='*60}")
print(f" CAPE Sandbox Analysis Report")
print(f"{'='*60}")
print(f" Task ID : {info.get('id', 'N/A')}")
print(f" Duration : {info.get('duration', 0)}s")
print(f" Malscore : {score}/10")
file_info = target.get("file", {})
if file_info:
print(f" File : {file_info.get('name', 'N/A')}")
print(f" SHA256 : {file_info.get('sha256', 'N/A')}")
print(f" Type : {file_info.get('type', 'N/A')}")
sig_findings = [f for f in findings if f["category"] == "signature"]
net_dns = [f for f in findings if f["category"] == "network_dns"]
net_http = [f for f in findings if f["category"] == "network_http"]
dropped = [f for f in findings if f["category"] == "dropped_file"]
configs = [f for f in findings if f["category"] == "cape_config"]
print(f"\n Signatures : {len(sig_findings)}")
print(f" DNS Queries : {len(net_dns)}")
print(f" HTTP Reqs : {len(net_http)}")
print(f" Dropped : {len(dropped)}")
print(f" CAPE Configs: {len(configs)}")
if sig_findings:
print(f"\n Top Signatures:")
for s in sorted(sig_findings, key=lambda x: x.get("severity", 0), reverse=True)[:10]:
sev = s.get("severity", 0)
label = "HIGH" if sev >= 3 else "MEDIUM" if sev >= 2 else "LOW"
print(f" [{label:6s}] {s['name']}: {s['description'][:80]}")
if configs:
print(f"\n Extracted Configs:")
for c in configs:
print(f" Family: {c.get('family', 'unknown')}")
return score
def main():
parser = argparse.ArgumentParser(
description="CAPE Sandbox malware analysis agent"
)
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("--file", help="Path to malware sample to submit")
group.add_argument("--url", help="URL to submit for analysis")
group.add_argument("--task-id", type=int, help="Retrieve report for existing task")
parser.add_argument("--output", "-o", help="Output JSON report path")
parser.add_argument("--server", help="CAPE server URL (or set CAPE_URL env var)")
parser.add_argument("--token", help="API token (or set CAPE_API_TOKEN env var)")
parser.add_argument("--machine", help="Specific VM to use for analysis")
parser.add_argument("--timeout", type=int, default=5, help="Analysis timeout in minutes")
parser.add_argument("--wait", type=int, default=600, help="Max seconds to wait for completion")
parser.add_argument("--verbose", "-v", action="store_true")
args = parser.parse_args()
if args.server:
os.environ["CAPE_URL"] = args.server
if args.token:
os.environ["CAPE_API_TOKEN"] = args.token
server, token = get_cape_config()
if args.task_id:
task_id = args.task_id
elif args.file:
task_id = submit_file(server, token, args.file, args.timeout, args.machine)
else:
task_id = submit_url(server, token, args.url, args.timeout)
if not args.task_id:
if not poll_task_status(server, token, task_id, args.wait):
sys.exit(1)
report = get_report(server, token, task_id)
findings = extract_findings(report)
score = format_summary(report, findings)
output_report = {
"timestamp": datetime.now(timezone.utc).isoformat(),
"tool": "CAPE Sandbox",
"task_id": task_id,
"malscore": score,
"findings_count": len(findings),
"findings": findings,
"risk_level": (
"CRITICAL" if score >= 8
else "HIGH" if score >= 5
else "MEDIUM" if score >= 3
else "LOW"
),
}
if args.output:
with open(args.output, "w") as f:
json.dump(output_report, f, indent=2)
print(f"\n[+] Report saved to {args.output}")
elif args.verbose:
print(json.dumps(output_report, indent=2))
if __name__ == "__main__":
main()