mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-16 04:35:18 +03:00
Add folder anatomy (scripts/agent.py + references/api-reference.md) for 648 cybersecurity skills
Complete skill folder anatomy across all cybersecurity skills: - scripts/agent.py: 80-150 line Python agents using real libraries (impacket, boto3, azure-mgmt-*, kubernetes, pefile, yara, scapy, shodan, stix2, etc.) - references/api-reference.md: real API documentation with method signatures - LICENSE: MIT license for all skill folders
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Container escape detection agent using Falco output parsing and audit log analysis.
|
||||
|
||||
Monitors for container escape indicators by parsing Falco JSON alerts,
|
||||
auditd logs, and Docker inspect data for privileged/vulnerable containers.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
ESCAPE_VECTORS = {
|
||||
"nsenter": {"severity": "CRITICAL", "mitre": "T1611", "desc": "Namespace escape via nsenter"},
|
||||
"unshare": {"severity": "CRITICAL", "mitre": "T1611", "desc": "Namespace manipulation"},
|
||||
"mount": {"severity": "HIGH", "mitre": "T1611", "desc": "Host filesystem mount"},
|
||||
"modprobe": {"severity": "CRITICAL", "mitre": "T1611", "desc": "Kernel module loading"},
|
||||
"insmod": {"severity": "CRITICAL", "mitre": "T1611", "desc": "Kernel module insertion"},
|
||||
"chroot": {"severity": "HIGH", "mitre": "T1611", "desc": "Chroot escape attempt"},
|
||||
}
|
||||
|
||||
SENSITIVE_PATHS = [
|
||||
"/var/run/docker.sock", "/proc/sysrq-trigger", "/proc/kcore",
|
||||
"/proc/kmsg", "/proc/kallsyms", "/sys/kernel",
|
||||
"/etc/shadow", "/etc/kubernetes/admin.conf",
|
||||
]
|
||||
|
||||
|
||||
def parse_falco_json(filepath):
|
||||
alerts = []
|
||||
with open(filepath, "r") as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
try:
|
||||
evt = json.loads(line)
|
||||
if any(tag in evt.get("tags", []) for tag in ["escape", "container"]):
|
||||
alerts.append({
|
||||
"time": evt.get("time", ""),
|
||||
"rule": evt.get("rule", ""),
|
||||
"priority": evt.get("priority", ""),
|
||||
"output": evt.get("output", ""),
|
||||
"output_fields": evt.get("output_fields", {}),
|
||||
})
|
||||
except json.JSONDecodeError:
|
||||
continue
|
||||
return alerts
|
||||
|
||||
|
||||
def parse_auditd_escape_events(filepath):
|
||||
findings = []
|
||||
escape_keys = {"container_escape", "container_mount", "kernel_module",
|
||||
"docker_socket", "process_trace"}
|
||||
with open(filepath, "r") as f:
|
||||
for line in f:
|
||||
for key in escape_keys:
|
||||
if f'key="{key}"' in line or f"key={key}" in line:
|
||||
timestamp = re.search(r'msg=audit\((\d+\.\d+):', line)
|
||||
syscall = re.search(r'syscall=(\w+)', line)
|
||||
exe = re.search(r'exe="([^"]+)"', line)
|
||||
findings.append({
|
||||
"timestamp": timestamp.group(1) if timestamp else "",
|
||||
"key": key,
|
||||
"syscall": syscall.group(1) if syscall else "",
|
||||
"exe": exe.group(1) if exe else "",
|
||||
"severity": "CRITICAL",
|
||||
"raw": line.strip()[:200],
|
||||
})
|
||||
return findings
|
||||
|
||||
|
||||
def check_privileged_containers():
|
||||
containers = []
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["docker", "ps", "--format", "{{.ID}} {{.Names}} {{.Image}}"],
|
||||
capture_output=True, text=True, timeout=10)
|
||||
if result.returncode != 0:
|
||||
return containers
|
||||
for line in result.stdout.strip().split("\n"):
|
||||
if not line.strip():
|
||||
continue
|
||||
parts = line.split(None, 2)
|
||||
cid = parts[0]
|
||||
inspect = subprocess.run(
|
||||
["docker", "inspect", "--format",
|
||||
"{{.HostConfig.Privileged}} {{.HostConfig.PidMode}} "
|
||||
"{{range .HostConfig.Binds}}{{.}} {{end}}"],
|
||||
capture_output=True, text=True, timeout=10)
|
||||
if inspect.returncode == 0:
|
||||
info = inspect.stdout.strip()
|
||||
findings = []
|
||||
if "true" in info.split()[0:1]:
|
||||
findings.append("privileged_mode")
|
||||
if "host" in info:
|
||||
findings.append("host_pid_namespace")
|
||||
if "/var/run/docker.sock" in info:
|
||||
findings.append("docker_socket_mounted")
|
||||
if findings:
|
||||
containers.append({
|
||||
"container_id": cid,
|
||||
"name": parts[1] if len(parts) > 1 else "",
|
||||
"image": parts[2] if len(parts) > 2 else "",
|
||||
"escape_risks": findings,
|
||||
"severity": "CRITICAL" if "privileged_mode" in findings else "HIGH",
|
||||
})
|
||||
except (subprocess.TimeoutExpired, FileNotFoundError):
|
||||
pass
|
||||
return containers
|
||||
|
||||
|
||||
def check_dangerous_capabilities(container_id):
|
||||
dangerous_caps = {"SYS_ADMIN", "SYS_PTRACE", "NET_ADMIN", "SYS_RAWIO",
|
||||
"SYS_MODULE", "DAC_READ_SEARCH"}
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["docker", "inspect", "--format", "{{.HostConfig.CapAdd}}", container_id],
|
||||
capture_output=True, text=True, timeout=10)
|
||||
if result.returncode == 0:
|
||||
caps = set(re.findall(r'\b([A-Z_]+)\b', result.stdout))
|
||||
found = caps & dangerous_caps
|
||||
return [{"capability": c, "severity": "CRITICAL"} for c in found]
|
||||
except (subprocess.TimeoutExpired, FileNotFoundError):
|
||||
pass
|
||||
return []
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Container Escape Detector")
|
||||
parser.add_argument("--falco-log", help="Path to Falco JSON output log")
|
||||
parser.add_argument("--audit-log", help="Path to auditd log file")
|
||||
parser.add_argument("--check-containers", action="store_true",
|
||||
help="Check running containers for escape risks")
|
||||
parser.add_argument("--container-id", help="Check specific container capabilities")
|
||||
args = parser.parse_args()
|
||||
|
||||
results = {"timestamp": datetime.utcnow().isoformat() + "Z", "findings": []}
|
||||
|
||||
if args.falco_log:
|
||||
alerts = parse_falco_json(args.falco_log)
|
||||
results["falco_alerts"] = alerts
|
||||
results["findings"].extend([{"source": "falco", **a} for a in alerts])
|
||||
|
||||
if args.audit_log:
|
||||
audit = parse_auditd_escape_events(args.audit_log)
|
||||
results["audit_events"] = audit
|
||||
results["findings"].extend([{"source": "auditd", **a} for a in audit])
|
||||
|
||||
if args.check_containers:
|
||||
priv = check_privileged_containers()
|
||||
results["privileged_containers"] = priv
|
||||
results["findings"].extend([{"source": "docker_inspect", **c} for c in priv])
|
||||
|
||||
if args.container_id:
|
||||
caps = check_dangerous_capabilities(args.container_id)
|
||||
results["dangerous_capabilities"] = caps
|
||||
results["findings"].extend([{"source": "capabilities", **c} for c in caps])
|
||||
|
||||
results["total_findings"] = len(results["findings"])
|
||||
print(json.dumps(results, indent=2))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user