Exploiting Insecure Docker Registry

Assume you're in a situation where you can't use Docker. How would you use the remote registry to get image FS layers? This guide will walk you through using simply the curl command to interface with the Docker registry.

Exploiting Insecure Docker Registry
Photo by Daniel Leżuch / Unsplash

Hello World! When you build an image from the docker build command, it creates the files in your local registry. The path is based on the host machine you are running. For more check here. The applications packed in the images are meant to be shared, right? So docker team has decided to create a public registry containing all the images by the docker team and anyone else.

When you do docker pull, by default, it pulls the image from the docker hub registry which is public and saves it in the local storage to be used. But some organizations don't want their applications to be disclosed to the public, so docker allows you to manage a private registry that acts as the same docker hub but resides on their premises.

What would you do when there is no docker CLI, but you are provided only with docker registry and the HTTP client? It's not as difficult as you might be thinking right now, I will use the curl command to interact with the remote registry.

Interact with the Docker Registry

There is no such rule for creating any tag for the image, you can have any arbitrary string. In this lab, there is an image whose tags might contain the flag. The docker-registry service can be started on any port, so use Nmap to find out the remote port service of the registry server.

Get the docker registry port on the remote server

To find other information about the images, you need to first have the list of names of all the images in the registry. In docker's terms, they are called repositories and you can use /v2/_catalog endpoint to that list.

Get the list of all the available images

As you realized the catalog route doesn't provide the information about tags, you can retrieve that using another endpoint - /v2/<image>/tags/list. Replace the name of the image with <name> whose tags you want to fetch. In this case, that would be flag.

Get the list of all the tags for flag image

There is only one tag for the image, and yeah that is your flag.

Download and Extract Layers

In this lab, you are given the HTTP interface of the Docker registry and it requires finding the flag from the file system. I have skipped the redundant step of finding the port number of the registry so let's begin with getting image names.

You will see that there is only one image in the registry treasure-trove.

Get repositories available in the registry

There is only one tag for the image (latest). So I have skipped that step as well. Before moving forward with retrieving the filesystem layers, it is required to have the checksums of them. You can find those from the manifest endpoint – /v2/<name>/manifests/<tag>. Replace the placeholder <name> with the image name and <tag> with the image tag.

Get the file manifest details for checksums of fsLayers

To download the actual contents of the filesystem, you can use the blobs endpoint – /v2/<name>/blobs/<checksum>. Replace the <name> with the image name and <checksum> with the value of blobSum from the fsLayers array.

This will return you the archived contents in tar format.
Downloaded a file system layer from the remote registry

On extracting this archive you will find that the flag exists in the etc/network/if-post-up.d/flag.txt file. If you don't find the desired file in the current layer, keep digging into other layers.

Extract the archive and retrieve the flag.
Here is the catch, blobSums in the fsLayers array is orders chronogically in the reverse order. So the flag retrieved from the 1.tar is the overwritten flag and 3.tar is the initial flag.

Just in case you are looking for a script to download all the layers at once and extract them, I have created a script for you.

#!/bin/bash

# Download all the fsLayers from the remote registry using curl command
# Usage: ./download.bash http://registry:5000 image [tag]

URL="$1"
IMAGE="$2"
TAG="${3:-latest}"

BLOBS=( $(curl "$URL/v2/$IMAGE/manifests/$TAG" -s | python -m json.tool |  grep blobSum | cut -d '"' -f 4) )

for ((idx = 0 ; idx < ${#BLOBS[@]}; idx++)); do
        BLOB=${BLOBS[$idx]}
        SUMIDX=$(($idx + 1))
        DIR="$PWD/$IMAGE/$SUMIDX"
        rm -rf "$DIR" ; mkdir -p "$DIR/fs"

        curl -s "$URL/v2/$IMAGE/blobs/$BLOB" -o "$DIR/layer.tar"
        tar xf "$DIR/layer.tar" -C "$DIR/fs"
done
Download all the layers