Or how I manage lots of (vulnerable) services easily with docker-compose
If you don’t know about Capture the Flag (in computer security context), it’s a competition in which you compete to solve network & security problems in order to get a special kind of flag. Wikipedia has a good explanation here. This is a story about how Docker helps me manage the competition.
What is Docker?
Docker is a tool with many use cases. It is tightly coupled with the term “container”. In short, docker is a tool to help developers pack their software with the necessary environment and configuration together. This results in a consistent development environment in any machine, without the need to figure out what to install in order to run the software.
A Beginner-Friendly Introduction to Containers, VMs and Docker
If you’re a programmer or techie, chances are you’ve at least heard of Docker: a helpful tool for packing, shipping…
What I am trying to solve
I am currently running a Jeopardy-style Capture the Flag Competition in which I need to host a number of services for the contestants to hack into. These services obviously is unique and can be written in specific library, framework, and programming language. That’s not counting the vulnerability I put into the service, some of which give the contestants access to read any file in the system, and even execute shell.
Of course I could setup the service one by one, maybe I could use Heroku to setup web services or use a simple socat for binary services, but I’m glad I chose Docker for this purpose. I can’t even imagine setting up a chroot jail to prevent contestant from accessing my real server.
I use CTFd as my choice of scoring platform. It is simple, and is still actively maintained with great support. I can customize it to my need with its extensive support for plugins and themes. I highly recommend it.
CTFd also provides easy deployment through Docker, it’s as simple as:
When you ran docker-compose up -d, you can see that it builds the container through a series of command (specified in Dockerfile), then links the database, and run both the database and web containers together. You can see its Dockerfile and docker-compose.yml file to get the gist of it.
Hosting multiple contest? Let’s create two version of the docker-compose.yml configuration.
That’s it. A simple change to ports and volumes configuration is all we need to do to host multiple scoring platform in one machine. Then we just need to specify the compose config file to use:
Then you can just use Nginx to reverse proxy your domain to those ports.
Let’s assume I want to deploy a Node.js web service that contains a Local File Inclusion vulnerability. First step is to prepare the Dockerfile, declaring how should Docker build the environment for our service:
I just pull from the node image, copy my app, install the dependencies, and then define the entry point to run the app.
I don’t want to introduce a .git folder exposure to my problem, so let’s create a .dockerignore file to ignore our .git folder (and also files we don’t want our contestants to see):
Finally, let’s create a docker-compose.yml so we can easily manage our container through compose (+ defining our flag in the environment variable):
And then I can just run docker-compose up -d to get my service up and running! As a sidenote:
- You might want to prevent your service from breaking and went down, just specify the restart: always config in the docker-compose.yml
- You might want to run the app as some user, usually the nobody user, just specify USER nobody in Dockerfile to limit the privilege.
- You might want to see the logs for you service, just run docker-compose logs to see the logs
- You can links containers, just like CTFd do with their database, but you might want to keep the database throught volume. You can also do cool things like seeding your database with a separate service.
The beauty of this system is that I can easily manage all my services through the docker and docker-compose command, such as docker ps for seeing all my running containers, or docker-compose stop if I want to stop a service for a while. I can also create a simple script to up all my services immediately in case if the server went down for some reason (true story, btw):
Docker has many use cases, as you can see here I’m using it to manage many services to achieve easy packaging, deployment, and monitoring. While there are many tools beyond a simple Docker and Docker Compose for managing this kind of problem, I find this is sufficient and simple enough for me. I highly encourage you to learn about Docker if you are a developer and don’t already know about it. Seriously, collaborative development and continuous deployment with Docker is a breeze. Note that I’m still new to this containerization thing so feel free to add your opinion in the comments below. And also, you should try competing in a Capture the Flag competition, it’s fun and challenging!