Tool Release – Enumerating Docker Registries with go-pillage-registries

Containerization solutions are becoming increasingly common throughout the industry due to their vast applications in logically separating and packaging processes to run consistently across environments. Docker represents these processes as images by packaging a base filesystem and initialization instructions for the runtime environment. Developers can use common base images and instruct Docker to execute a set of commands to build a new image. To organize and deploy these images in central repositories, organizations use Docker registries. Registries allow developers to build their images locally and push a tagged image to a project’s repository. Tags allow for multiple versions of an image to be referenced in the repository.

The infrastructure supporting containers has become a significant area of focus to security professionals who realize their importance. Very frequently while assessing such environments, NCC Group consultants come across read access to private Docker registries full of potentially useful information. In order to take full advantage of compromised Docker registries, NCC Group has developed go-pillage-registries. This repository contains a tool called pilreg, which provides a pentester-focused interface for these registries. pilreg allows attackers to easily enumerate images stored in a registry in order to obtain their metadata and filesystems.

What’s in a Docker registry?

Docker registries are used as a version control system for the development and deployment of container images. Docker images provide attackers with insights into the inner workings of an organization’s containers and the services running within them.

Any values compiled into the container during build time will be available through the image’s filesystem and metadata. As a result, if the image creator chose to supply any secret or sensitive values at build time rather than at runtime, then these values will be readable to attackers who simply obtain the container’s image from a compromised registry.

If the images are properly stripped of secrets, attackers may still find use in the application logic and configuration files stored in the image. This information can be extremely helpful to attackers who no longer need to make assumptions and discoveries about the application’s behavior.

What can go-pillage-registries do?

pilreg can be used as easily as the regular Docker tools by taking advantage of Google’s container registry library which utilizes Docker’s authentication semantics (run docker login and you can authenticate!).

You can simply provide a registry, and pilreg will enumerate all repositories and their tags using Docker’s /v2/_catalog and /v2/<name>/tags/list APIs. If the target registry does not support these APIs, or if you just don’t want to pillage their entire registry, then you can supply a list of known/desired repositories and tags. For registries with invalid TLS configurations, pilreg also has the option to ignore TLS verification (only suggested for security professionals)

When pilreg finds images, it automatically requests their manifest and configuration and outputs the results. There is also the option to store these results in an output directory for inspection. If an output directory is specified, then attackers also have the option to pull the filesystems for each image and store the resulting archives.

Demo

In the below demonstration, we will create an image with a secret set in an environment variable at build time to demonstrate an attacker’s ability to retrieve the value from the image’s configuration stored on a remote registry:

  1. Start registry:
docker run -d -p 5000:5000 registry
  1. Create the Docker image and push it to the registry
mkdir /tmp/example
cd /tmp/example

cat <<EOF > Dockerfile
FROM ubuntu
ENV "SUPERSECRET" "123456"
CMD ["uname", "-a"]
EOF

docker build -t 127.0.0.1:5000/test/test .
docker push 127.0.0.1:5000/test/test
  1. Install pilreg
git clone https://github.com/nccgroup/go-pillage-registries.git

cd go-pillage-registries
go install ./...
  1. Pillage the registry:
pilreg 127.0.0.1:5000 | tee pillaged.json
[
  {
    "Reference": "127.0.0.1:5000/test/test:latest",
    "Registry": "127.0.0.1:5000",
    "Repository": "test/test",
    "Tag": "latest",
    "Manifest": "{...}",
    "Config": "{...}",
    "Error": null
  }
]
  1. Search for the secret:
jq .[].'Config' pillaged.json -r | jq . | grep SECRET
      "SUPERSECRET=123456"
      "SUPERSECRET=123456"
      "created_by": "/bin/sh -c #(nop)  ENV SUPERSECRET=123456",

Special Thanks

NCC Group’s COSS practice provided the direction and motivation to create this tool and has additionally supplied me with a variety of interesting projects which helped inspire this tool. COSS is NCC Group’s new practice dedicated to projects relating to containerization and orchestration. Mark Manning is the director of this practice and served as a mentor to this research project as well.

I would also like to thank the maintainers of https://github.com/google/go-containerregistry for their collaboration in updating their library to include functionality required for this tool and for creating the library in the first place.