mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-13 22:54:53 +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
176 lines
6.3 KiB
Python
176 lines
6.3 KiB
Python
#!/usr/bin/env python3
|
|
"""Falco-based container escape detection agent.
|
|
|
|
Manages Falco rules, parses Falco alert output, and generates
|
|
escape detection reports from Falco JSON event streams.
|
|
"""
|
|
|
|
import argparse
|
|
import json
|
|
import subprocess
|
|
import sys
|
|
from datetime import datetime
|
|
|
|
ESCAPE_RULE_TAGS = ["container", "escape", "T1611", "T1610", "namespace",
|
|
"docker_socket", "cgroup", "kernel_module", "privileged"]
|
|
|
|
SEVERITY_MAP = {
|
|
"Emergency": 0, "Alert": 1, "Critical": 2, "Error": 3,
|
|
"Warning": 4, "Notice": 5, "Informational": 6, "Debug": 7
|
|
}
|
|
|
|
|
|
def check_falco_status():
|
|
try:
|
|
result = subprocess.run(["falco", "--version"],
|
|
capture_output=True, text=True, timeout=10)
|
|
if result.returncode == 0:
|
|
version = result.stdout.strip()
|
|
return {"installed": True, "version": version}
|
|
except FileNotFoundError:
|
|
pass
|
|
try:
|
|
result = subprocess.run(["systemctl", "is-active", "falco"],
|
|
capture_output=True, text=True, timeout=5)
|
|
return {"installed": True, "service_status": result.stdout.strip()}
|
|
except FileNotFoundError:
|
|
pass
|
|
return {"installed": False}
|
|
|
|
|
|
def validate_rules_file(rules_path):
|
|
try:
|
|
result = subprocess.run(
|
|
["falco", "--validate", rules_path],
|
|
capture_output=True, text=True, timeout=30)
|
|
return {
|
|
"valid": result.returncode == 0,
|
|
"output": result.stdout.strip() if result.returncode == 0
|
|
else result.stderr.strip(),
|
|
}
|
|
except (FileNotFoundError, subprocess.TimeoutExpired) as e:
|
|
return {"valid": False, "error": str(e)}
|
|
|
|
|
|
def parse_falco_alerts(filepath, min_priority="Warning"):
|
|
min_level = SEVERITY_MAP.get(min_priority, 4)
|
|
alerts = []
|
|
escape_alerts = []
|
|
|
|
with open(filepath, "r") as f:
|
|
for line in f:
|
|
line = line.strip()
|
|
if not line:
|
|
continue
|
|
try:
|
|
evt = json.loads(line)
|
|
except json.JSONDecodeError:
|
|
continue
|
|
|
|
priority = evt.get("priority", "Informational")
|
|
if SEVERITY_MAP.get(priority, 6) > min_level:
|
|
continue
|
|
|
|
alert = {
|
|
"time": evt.get("time", ""),
|
|
"rule": evt.get("rule", ""),
|
|
"priority": priority,
|
|
"source": evt.get("source", "syscall"),
|
|
"output": evt.get("output", ""),
|
|
"fields": evt.get("output_fields", {}),
|
|
"tags": evt.get("tags", []),
|
|
}
|
|
alerts.append(alert)
|
|
|
|
tags = set(evt.get("tags", []))
|
|
if tags & set(ESCAPE_RULE_TAGS):
|
|
escape_alerts.append(alert)
|
|
|
|
return {"total_alerts": len(alerts), "escape_alerts": escape_alerts}
|
|
|
|
|
|
def generate_escape_rules_yaml():
|
|
rules = """# Container Escape Detection Rules for Falco
|
|
# Deploy to /etc/falco/rules.d/container-escape.yaml
|
|
|
|
- list: escape_binaries
|
|
items: [nsenter, unshare, mount, umount, pivot_root, chroot, modprobe, insmod]
|
|
|
|
- macro: container_escape_binary
|
|
condition: spawned_process and container and proc.name in (escape_binaries)
|
|
|
|
- rule: Container Escape Binary Execution
|
|
desc: Detect execution of binaries commonly used for container escape
|
|
condition: container_escape_binary
|
|
output: "Escape binary in container (user=%user.name cmd=%proc.cmdline container=%container.name image=%container.image.repository)"
|
|
priority: CRITICAL
|
|
tags: [container, escape, T1611]
|
|
|
|
- rule: Docker Socket Access from Container
|
|
desc: Container accessing Docker socket enables full host control
|
|
condition: (open_read or open_write) and container and fd.name = /var/run/docker.sock
|
|
output: "Docker socket accessed (user=%user.name container=%container.name cmd=%proc.cmdline)"
|
|
priority: CRITICAL
|
|
tags: [container, escape, docker_socket, T1610]
|
|
|
|
- rule: Cgroup Release Agent Write
|
|
desc: Writing to cgroup release_agent is a known container escape vector
|
|
condition: open_write and container and fd.name endswith release_agent
|
|
output: "Cgroup escape attempt (user=%user.name container=%container.name file=%fd.name)"
|
|
priority: CRITICAL
|
|
tags: [container, escape, cgroup]
|
|
|
|
- rule: Kernel Module Load from Container
|
|
desc: Container attempting to load kernel module
|
|
condition: spawned_process and container and proc.name in (modprobe, insmod, rmmod)
|
|
output: "Kernel module load (user=%user.name container=%container.name cmd=%proc.cmdline)"
|
|
priority: CRITICAL
|
|
tags: [container, escape, kernel_module]
|
|
|
|
- rule: Sensitive Proc Access from Container
|
|
desc: Container accessing sensitive /proc or /sys paths
|
|
condition: open_read and container and (fd.name startswith /proc/sysrq-trigger or fd.name startswith /proc/kcore or fd.name startswith /proc/kallsyms)
|
|
output: "Sensitive proc access (container=%container.name path=%fd.name cmd=%proc.cmdline)"
|
|
priority: CRITICAL
|
|
tags: [container, escape, proc_access]
|
|
"""
|
|
return rules
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Falco Container Escape Detection")
|
|
parser.add_argument("--check-status", action="store_true", help="Check Falco installation")
|
|
parser.add_argument("--validate-rules", help="Validate a Falco rules file")
|
|
parser.add_argument("--parse-alerts", help="Parse Falco JSON alert log")
|
|
parser.add_argument("--min-priority", default="Warning",
|
|
choices=list(SEVERITY_MAP.keys()))
|
|
parser.add_argument("--generate-rules", action="store_true",
|
|
help="Output escape detection rules YAML")
|
|
args = parser.parse_args()
|
|
|
|
results = {"timestamp": datetime.utcnow().isoformat() + "Z"}
|
|
|
|
if args.check_status:
|
|
results["falco_status"] = check_falco_status()
|
|
|
|
if args.validate_rules:
|
|
results["validation"] = validate_rules_file(args.validate_rules)
|
|
|
|
if args.parse_alerts:
|
|
parsed = parse_falco_alerts(args.parse_alerts, args.min_priority)
|
|
results["alert_summary"] = {
|
|
"total_alerts": parsed["total_alerts"],
|
|
"escape_alerts_count": len(parsed["escape_alerts"]),
|
|
}
|
|
results["escape_alerts"] = parsed["escape_alerts"]
|
|
|
|
if args.generate_rules:
|
|
print(generate_escape_rules_yaml())
|
|
return
|
|
|
|
print(json.dumps(results, indent=2))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|