skip to content
Hafiz Farhad

Understanding Docker

/ 3 min read

Table of Contents

In the end of this tutorial, you will be able to work with docker files effortlessly.

Intro

When I first started playing CTFs, I used to be given zip files, ie., challenge.zip.

And in that zip file I kept seeing either Dockerfile or sometimes both, Dockerfile and docker-compose.yml.

Recently, I played a UMDCTF, and there I was given ld-linux-x86-64.so.zip, a pwn challenge:

Terminal window
hafizfarhad.com@vm:~$ ls
ld-linux-x86-64.so.zip
hafizfarhad.com@vm:~$ unzip ld-linux-x86-64.so.zip
hafizfarhad.com@vm:~$ ls
Dockerfile ld-linux-x86-64.so.2 libc.so.6 Makefile offbyone offbyone.c
hafizfarhad.com@vm:~$

When I unziped it, I could see a Dockerfile in it.

If you’re new to CTFs like me, these files might seem confusing.

Basically, these files let you recreate the exact same environment that’s running on the challenge server. This means you can test your exploits locally before trying them on the actual challenge server.

Basics

Docker helps you create “containers” - like mini virtual machines that run specific applications. The beauty is that these containers work the same way on everyone’s computer.

In most of the challenges, you’ll typically see one or two main files:

Dockerfile - This file contains Instructions to build a single container

docker-compose.yml - The file contains Instructions to build multiple containers that work together

When to use which file? Always use docker-compose.yml file if given.

Commands

When I’m given these files in a CTF, here’s what I typically do:

If you haven’t installed docker, checkout the manual.

For challenges with a docker-compose.yml file:

Terminal window
# Build the containers (the --no-cache makes sure everything is fresh)
docker compose build --no-cache
# Start the containers in the background
docker compose up -d
# See all running containers
docker ps -a
# When you're done, shut everything down
docker compose down -v

Sometimes you will only be given Dockerfile. In that case:

Terminal window
# Build the container
docker build -t challenge-name .
# Run the container (maps port 8080 on your computer to port 80 in the container)
docker run -d -p 8080:80 --name challenge-name-container challenge-name
# Stop the container when done
docker stop challenge-name-container
# Remove the container
docker rm challenge-name-container

Debugging

I’ve encountered various problems and learned useful commands along the way:

Always make sure to add sudo before commands, otherwise you might get “permission denied” errors.

If a port is already in use, change the port mapping:

Terminal window
docker run -d -p 9090:80 --name challenge-name-container challenge-name

To see container logs:

Terminal window
docker logs challenge-name-container

To find a container’s IP address:

Terminal window
docker inspect challenge-name-container | grep IPAddress

challenge-name is the Docker image (template), while challenge-name-container is the running instance created from that image. You can create multiple different containers from the same image, each with its own settings.

Cleanup

When you want to cleanup everything, use these commands:

Terminal window
# Remove all Docker images
docker rmi -f $(docker images -q)
# Remove everything - containers, networks, volumes
docker system prune -af --volumes

Wrapping Up

Being able to run challenges locally helps you test ideas quickly without worrying about challenge server timeouts or bans. As you get familiar with these commands, you’ll start to see patterns in how challenges are set up, which can give you hints about where vulnerabilities might be hiding.

Happy hacking!

Additional Resources