Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-SkillsFramework mappings
MITRE ATT&CK
When to Use
- When conducting security assessments that involve performing container escape detection
- 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
- Familiarity with container security concepts and tools
- Access to a test or lab environment for safe execution
- Python 3.8+ with required dependencies installed
- Appropriate authorization for any testing activities
Instructions
Audit Kubernetes pods for container escape vectors including privileged mode, dangerous capabilities, host namespace sharing, and writable hostPath mounts.
from kubernetes import client, config
config.load_kube_config()
v1 = client.CoreV1Api()
pods = v1.list_pod_for_all_namespaces()
for pod in pods.items:
for container in pod.spec.containers:
sc = container.security_context
if sc and sc.privileged:
print(f"PRIVILEGED: {pod.metadata.namespace}/{pod.metadata.name}")Key escape vectors:
- Privileged containers (full host access)
- CAP_SYS_ADMIN capability
- Host PID/Network/IPC namespace sharing
- Writable hostPath mounts to / or /etc
- Docker socket mount (/var/run/docker.sock)
Examples
# Check for docker socket mounts
for vol in pod.spec.volumes or []:
if vol.host_path and "docker.sock" in (vol.host_path.path or ""):
print(f"Docker socket exposed: {pod.metadata.name}")Source materials
References and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 1
api-reference.md1.5 KB
API Reference: Performing Container Escape Detection
kubernetes Python Client
from kubernetes import client, config
config.load_kube_config() # or config.load_incluster_config()
v1 = client.CoreV1Api()
pods = v1.list_pod_for_all_namespaces()
for pod in pods.items:
spec = pod.spec
# Check host namespace sharing
print(spec.host_pid, spec.host_network, spec.host_ipc)
for c in spec.containers:
sc = c.security_context
if sc:
print(sc.privileged, sc.capabilities, sc.run_as_user)
for vol in spec.volumes or []:
if vol.host_path:
print(vol.host_path.path)Container Escape Vectors
| Vector | Field | Severity |
|---|---|---|
| Privileged mode | securityContext.privileged |
CRITICAL |
| SYS_ADMIN cap | capabilities.add |
CRITICAL |
| Docker socket | hostPath: /var/run/docker.sock |
CRITICAL |
| Host PID ns | hostPID: true |
HIGH |
| Host Network | hostNetwork: true |
HIGH |
| Writable / mount | hostPath: / |
CRITICAL |
| Run as root | runAsUser: 0 |
MEDIUM |
Dangerous Linux Capabilities
SYS_ADMIN, SYS_PTRACE, SYS_RAWIO, SYS_MODULE,
DAC_READ_SEARCH, NET_ADMIN, NET_RAWReferences
- kubernetes Python client: https://github.com/kubernetes-client/python
- Pod Security Standards: https://kubernetes.io/docs/concepts/security/pod-security-standards/
- Container escapes: https://blog.trailofbits.com/2019/07/19/understanding-docker-container-escapes/
Scripts 1
agent.py6.8 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Agent for detecting container escape vectors in Kubernetes."""
import json
import argparse
from datetime import datetime
from kubernetes import client, config
DANGEROUS_CAPS = [
"SYS_ADMIN", "SYS_PTRACE", "SYS_RAWIO", "SYS_MODULE",
"DAC_READ_SEARCH", "NET_ADMIN", "NET_RAW",
]
DANGEROUS_HOST_PATHS = ["/", "/etc", "/root", "/var/run/docker.sock",
"/var/run/crio", "/proc", "/sys"]
def load_kube_config():
"""Load Kubernetes configuration."""
try:
config.load_incluster_config()
except config.ConfigException:
config.load_kube_config()
def check_privileged_containers(v1):
"""Find pods running privileged containers."""
findings = []
pods = v1.list_pod_for_all_namespaces()
for pod in pods.items:
for container in pod.spec.containers or []:
sc = container.security_context
if sc and sc.privileged:
findings.append({
"namespace": pod.metadata.namespace,
"pod": pod.metadata.name,
"container": container.name,
"issue": "privileged container",
"severity": "CRITICAL",
})
return findings
def check_dangerous_capabilities(v1):
"""Find containers with dangerous Linux capabilities."""
findings = []
pods = v1.list_pod_for_all_namespaces()
for pod in pods.items:
for container in pod.spec.containers or []:
sc = container.security_context
if not sc or not sc.capabilities or not sc.capabilities.add:
continue
for cap in sc.capabilities.add:
if cap in DANGEROUS_CAPS:
findings.append({
"namespace": pod.metadata.namespace,
"pod": pod.metadata.name,
"container": container.name,
"capability": cap,
"severity": "HIGH",
})
return findings
def check_host_namespaces(v1):
"""Find pods sharing host PID, network, or IPC namespaces."""
findings = []
pods = v1.list_pod_for_all_namespaces()
for pod in pods.items:
spec = pod.spec
ns_issues = []
if spec.host_pid:
ns_issues.append("hostPID")
if spec.host_network:
ns_issues.append("hostNetwork")
if spec.host_ipc:
ns_issues.append("hostIPC")
if ns_issues:
findings.append({
"namespace": pod.metadata.namespace,
"pod": pod.metadata.name,
"host_namespaces": ns_issues,
"severity": "HIGH",
})
return findings
def check_dangerous_mounts(v1):
"""Find pods with dangerous hostPath volume mounts."""
findings = []
pods = v1.list_pod_for_all_namespaces()
for pod in pods.items:
for vol in pod.spec.volumes or []:
if not vol.host_path:
continue
path = vol.host_path.path
if any(path == dp or path.startswith(dp + "/") for dp in DANGEROUS_HOST_PATHS):
findings.append({
"namespace": pod.metadata.namespace,
"pod": pod.metadata.name,
"volume": vol.name,
"host_path": path,
"severity": "CRITICAL" if path in ("/", "/var/run/docker.sock") else "HIGH",
})
return findings
def check_docker_socket(v1):
"""Specifically detect Docker/CRI socket mounts."""
findings = []
sockets = ["/var/run/docker.sock", "/var/run/crio/crio.sock",
"/run/containerd/containerd.sock"]
pods = v1.list_pod_for_all_namespaces()
for pod in pods.items:
for vol in pod.spec.volumes or []:
if vol.host_path and vol.host_path.path in sockets:
findings.append({
"namespace": pod.metadata.namespace,
"pod": pod.metadata.name,
"socket_path": vol.host_path.path,
"severity": "CRITICAL",
})
return findings
def check_root_containers(v1):
"""Find containers running as root."""
findings = []
pods = v1.list_pod_for_all_namespaces()
for pod in pods.items:
for container in pod.spec.containers or []:
sc = container.security_context
if sc and sc.run_as_user == 0:
findings.append({
"namespace": pod.metadata.namespace,
"pod": pod.metadata.name,
"container": container.name,
"issue": "running as UID 0",
"severity": "MEDIUM",
})
elif not sc or sc.run_as_non_root is not True:
findings.append({
"namespace": pod.metadata.namespace,
"pod": pod.metadata.name,
"container": container.name,
"issue": "runAsNonRoot not enforced",
"severity": "LOW",
})
return findings
def main():
parser = argparse.ArgumentParser(description="Container Escape Detection Agent")
parser.add_argument("--output", default="container_escape_report.json")
parser.add_argument("--action", choices=[
"privileged", "capabilities", "namespaces", "mounts", "socket", "full_scan"
], default="full_scan")
args = parser.parse_args()
load_kube_config()
v1 = client.CoreV1Api()
report = {"generated_at": datetime.utcnow().isoformat(), "findings": {}}
if args.action in ("privileged", "full_scan"):
findings = check_privileged_containers(v1)
report["findings"]["privileged"] = findings
print(f"[+] Privileged containers: {len(findings)}")
if args.action in ("capabilities", "full_scan"):
findings = check_dangerous_capabilities(v1)
report["findings"]["dangerous_caps"] = findings
print(f"[+] Dangerous capabilities: {len(findings)}")
if args.action in ("namespaces", "full_scan"):
findings = check_host_namespaces(v1)
report["findings"]["host_namespaces"] = findings
print(f"[+] Host namespace sharing: {len(findings)}")
if args.action in ("mounts", "full_scan"):
findings = check_dangerous_mounts(v1)
report["findings"]["dangerous_mounts"] = findings
print(f"[+] Dangerous mounts: {len(findings)}")
if args.action in ("socket", "full_scan"):
findings = check_docker_socket(v1)
report["findings"]["socket_mounts"] = findings
print(f"[+] Container runtime socket mounts: {len(findings)}")
with open(args.output, "w") as f:
json.dump(report, f, indent=2, default=str)
print(f"[+] Report saved to {args.output}")
if __name__ == "__main__":
main()
Keep exploring