mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-30 07:56:52 +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,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Anthropic Agent Skills Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,74 @@
|
||||
# API Reference: Detecting Container Escape Attempts
|
||||
|
||||
## Common Escape Vectors (MITRE ATT&CK)
|
||||
|
||||
| Vector | Technique | MITRE ID |
|
||||
|--------|-----------|----------|
|
||||
| Privileged container | Mount host FS, load modules | T1611 |
|
||||
| Docker socket mount | Create privileged container | T1610 |
|
||||
| Kernel exploits | CVE-2022-0185, Dirty Pipe | T1068 |
|
||||
| Capability abuse | SYS_ADMIN, SYS_PTRACE | T1548 |
|
||||
| Sensitive mounts | /proc/sysrq-trigger, cgroup release_agent | T1611 |
|
||||
| Namespace escape | nsenter, unshare | T1611 |
|
||||
|
||||
## Docker CLI Inspection
|
||||
|
||||
```bash
|
||||
# Check if container is privileged
|
||||
docker inspect --format='{{.HostConfig.Privileged}}' <container>
|
||||
|
||||
# Check added capabilities
|
||||
docker inspect --format='{{.HostConfig.CapAdd}}' <container>
|
||||
|
||||
# Check PID namespace mode
|
||||
docker inspect --format='{{.HostConfig.PidMode}}' <container>
|
||||
|
||||
# Check volume mounts
|
||||
docker inspect --format='{{range .Mounts}}{{.Source}}:{{.Destination}} {{end}}' <container>
|
||||
```
|
||||
|
||||
## Falco JSON Alert Format
|
||||
|
||||
```json
|
||||
{
|
||||
"time": "2024-01-15T10:30:00.000Z",
|
||||
"rule": "Container Escape via Privileged Mode",
|
||||
"priority": "Critical",
|
||||
"output": "Container escape attempt...",
|
||||
"output_fields": {
|
||||
"container.name": "attacker-pod",
|
||||
"container.image.repository": "alpine",
|
||||
"proc.cmdline": "nsenter -t 1 -m -u -i -n"
|
||||
},
|
||||
"tags": ["container", "escape", "T1611"]
|
||||
}
|
||||
```
|
||||
|
||||
## Linux Audit Rules for Escape Detection
|
||||
|
||||
```bash
|
||||
# /etc/audit/rules.d/container-escape.rules
|
||||
-a always,exit -F arch=b64 -S setns -S unshare -k container_escape
|
||||
-a always,exit -F arch=b64 -S mount -S umount2 -k container_mount
|
||||
-a always,exit -F arch=b64 -S init_module -S finit_module -k kernel_module
|
||||
-w /var/run/docker.sock -p rwxa -k docker_socket
|
||||
```
|
||||
|
||||
## Dangerous Linux Capabilities
|
||||
|
||||
| Capability | Escape Risk |
|
||||
|------------|-------------|
|
||||
| CAP_SYS_ADMIN | Mount filesystems, manage cgroups |
|
||||
| CAP_SYS_PTRACE | Trace/debug any process |
|
||||
| CAP_NET_ADMIN | Network namespace manipulation |
|
||||
| CAP_SYS_MODULE | Load/unload kernel modules |
|
||||
| CAP_DAC_READ_SEARCH | Bypass file read permissions |
|
||||
|
||||
## CLI Usage
|
||||
|
||||
```bash
|
||||
python agent.py --falco-log /var/log/falco/events.json
|
||||
python agent.py --audit-log /var/log/audit/audit.log
|
||||
python agent.py --check-containers
|
||||
python agent.py --container-id abc123
|
||||
```
|
||||
@@ -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