Estimated Difficulty: 💜💜💜🤍🤍
I’m sure you have all heard the whispers that Security folk dislike the Developer folk… However, the time has come for the Security-Developer to be born! I don’t know about you, but I am all for making my life easier and after a dissertation full of failures, I have a new love and appreciation for Docker. But “What is Docker?” might you ask… well that is a very good question! Docker is whatever you want it to be. Docker can be the solution to your software compatibility issues. Docker can be the automation of a mundane task. Docker is only limited to your imagination.
“Docker is a tool that allows developers, sys-admins etc. to easily deploy their applications in a sandbox (called containers) to run on the host operating system i.e. Linux.“– Prakhar Srivasta
By no means am I an expert in Docker, however this is an area I would love to understand and “Develop” on. My recent work has seen me attempt to deploy a proxy solution with this software. However, this post will walk through the basics of Docker and how a container works. We will be creating a Container running an Apache2 web server, which you should be able to view on your client machine. However, I am hoping to produce more security focused “How To’s” in the future!
- Docker installed for your OS, see the following guides: Windows, Linux, Mac.
- Basic Knowledge of Linux
- Basic Knowledge of HTML
All the code discussed in this post is available in our GitHub repository. Feel free to re-use and modify the files!
What is Docker?
Docker is a virtualisation software that can be used to automate the deployment of applications and run applications with different requirements. For example you may want to create a container running Ubuntu and another or NodeJS and you would easily be able to do so, even if your host operating system was different! Docker is a lightweight solution similar to a Virtual Machine (VM), however it is slightly more lightweight, as it can re-use layers such as the base image for other containers running on your host.
A Dockerfile specifies the instructions on how to build a Docker container. It will specify the base image and any other software that needs to be installed to provide the functionality for your container. The main instructions I have listed, that we can use to build our container are also specified in Docker’s documentation.
FROM: An instruction that will specify the base image for your container. For example “FROM ubuntu:latest“ will instruct the daemon to pull the latest image of Ubuntu for the containers environment.
MAINTAINER: This is a nice way of naming your work.
COPY: Does what it says on the tin. You can use the COPY command to copy any files in your current working directory and add that file to your containers environment. This is extremely handy when you want to re-use a configuration or script you have already created.
RUN: Can be used to run bash commands such as “RUN apt-get install net-tools -y”. This would add another layer to your Docker container, by installing the software package net-tools. You can use RUN for other things such as running an executable.
CMD: Is used to provide “defaults for an executing container”. There should only be one CMD specified in the Dockerfile else the last one specified will be executed. The CMD instruction will execute the executable you want to run. For example if you want to start a service you can do so by “CMD [“apachectl”, “-D”, “FOREGROUND”]”. This will run the apachectl executable (to run the service in the container) with the two parameters “-D” and “Foreground”.
EXPOSE: Specifies the port you want to expose at run time of the container. You will need to use the “-p” flag when running the container to actually publish the port you want to expose.
WORKDIR: Specifies the directory you want to be in, inside of the container. Similar to how you may use “cd” for change directory, instead you are using this instruction.
Creating the DockerFile
We are creating a Dockerfile to build an image and then run a Docker container. One video tutorial explains this very well.
Each line of code specified in the preformatted sections below. To build your Dockerfile you can add each of these to your Dockerfile also to create your own following this tutorial. Please see the GitHub repository for all the files. This will be a working post and improvements will be made to these configurations and code.
To create this image I am using an Ubuntu Virtual Machine as it helps me to run the installation steps on a VM before creating the Dockerfile. To create the Dockerfile I run the following command in the Linux Terminal:
sudo nano Dockerfile
It is important make sure you name the file “Dockerfile” as Docker will look for this when we build the image. I will create this Dockerfile in a directory linked to my GitHub repository, so I can push and pull any changes I make remotely.
Pulling the Base Image
FROM ubuntu:latest MAINTAINER G1nGe
Here we are specifying the latest Long Time Support (LTS) Ubuntu image from Docker Hub. Whenever you use the latest tag, you will be pulling the LTS release. This is important to note as it will therefore not be pulling any new developments you might want or need for your project. If this is the case you may want to look into building your own image, see documentation on this here. There are also more lightweight OS’ you can use such as lighthttpd an original Docker image, however I have used Ubuntu because I am more familiar with it at the moment.
ENV DEBIAN_FRONTEND noninteractive
When building the container we do not want to have to specify anything on the command line. Instead it would be better to specify the build as noninteractive to make the build process as automated as possible. This should prevent any dialogue or questions from being asked and you should be able to let the build just run.
Updating the Environment
RUN apt-get -y update && apt-get -y upgrade
We want to make sure that our base image is up to date and upgraded to make sure we have the latest packages installed when we are creating and running our application. This is good practice to run in your virtual machines also, to make sure you are working with the latest software. We have used the RUN command to perform these upgrades, however another important thing to note is the “-y” element to the line in this file. We need to specify this as we will not be able to interact with the command line as the Docker Image is being built from the Dockerfile. Sometimes when installing software we see a prompt meaning we need to accept the changes or installation. An example of this can be seen below.
The “-y” accepts these changes automatically.
RUN apt-get install -y apache2
You will need to install the Apache2 software. As we are using Linux as our base image, we can use the apt-utils package to install this. We need to make sure to specify the -y command as we will not be interacting with the shell as it runs. If you are feeling daring you can do the same with other software and replace these commands.
Specifying the Working Directory
Here we are specifying the working directory of the container. By moving into this path we are then able to make changes to this directory, for example by adding files to it.
Copying the Code
COPY index.html .
Within the directory on my hosts directory I have an index.html file. By using the COPY command I am saying I would like to add my index.html file from this directory (specified by”index.html“) to that exact directory within the container (specified by a “.“). You can change where you place the files in the container by swapping out the “.“. The index.html file will replace the existing index.html file that is installed by default when installing the Apache2 software. If you would like to test your container before
Executing the Service
EXPOSE 80 COPY start.sh /start.sh RUN chmod 777 /start.sh CMD /start.sh
I have used EXPOSE to define the port that we want open when we run the Docker container. Port 80 is the default port that the Apache2 web server is defined to run on. The web server is defined to run locally on the container at address 127.0.0.1 (the loop-back address). A BASH script has also been created to specify the Apache2 service to start. An issue I had encountered was the container would run and then finish within a matter of seconds, so I needed to find a way I could get this service to run persistently. The bash script starting the Apache2 service did this. See the below file for the start.sh code:
#!/bin/sh #This is the start.sh script service apache2 start tail -f /dev/null
Within the Dockerfile I have specified the executable as chmod 777. This is specifying it to be readable, writable and executable by everyone. This is by no means best practice in security, so please play around with the permissions that you are giving your executable.
#This is the Final Dockerfile FROM ubuntu:latest MAINTAINER G1nGe ENV DEBIAN_FRONTEND noninteractive RUN apt-get -y update && apt-get -y upgrade RUN apt-get install -y apache2 WORKDIR /var/www/html COPY index.html . EXPOSE 80 COPY start.sh /start.sh RUN chmod 777 /start.sh CMD /start.sh
Building and Running the Docker Container
Building the container
sudo docker build --tag secqueens:1.0 .
To build the Docker Image I have used the build command listed for Docker. This command has been executed in the directory of the Dockerfile, where the “.” specifies to build the image here. The container has been tagged with secqueens:1.0. You will be able to see each layer being pulled. Some may use the cache than pull the layer again.
Running the Container
sudo docker images
You can list the images that you have created with the above command. From here you can check the ID of your image for future reference.
sudo docker run -d secqueens:1.0
The following command specifies the repository that we have just created to run and the -d specifies for it to run in the background. If you don’t use the -d flag then you will not be able to interact with that terminal as it will just show the process as running.
This screenshot specifies that the container is running at IP address 172.17.0.2. Since our web-server runs locally within the container, we are able to see what is running on our host machine in the browser, by going to the containers IP address.
sudo docker ps
ps standing or Process Status. It will list the status of any containers running. You can check to see if your container is running by executing this command. You can check the name of your container and use this to complete other tasks such as running a new command in another container.
Executing the Container
sudo docker exec -it <name of the container> bash
The exec command allows you to interact with your container whilst it is running. The above defined command allows you to enter into the command line of your running container. You can use this to troubleshoot any issues you might have encountered, or just have an experiment with understanding how the container is created and what you might be limited to doing. You might be able to identify any additional software you would like to install.
So far this post has covered, how to create a basic Dockerfile, how to build an image from the Dockerfile and how to run a Docker container. There is so much more you can do with Docker, especially when applying it to your own projects. Please let me know your thoughts on this post! I hope it has given you a slight introduction into what Docker is about, and I plan to work on more security focused Docker content soon. If you have anything specific you would like to see (or a project idea I can try) please let me know as I am more than open to suggestions and infatuated with learning more about this! 😀
Future work will be to change the user that the container runs as. At current for the build we have just created the container runs with the root user and this is not best practice in the security world.
How can I apply this to Security?
There are a bunch of projects that penetration testers, bug bounty hunters and others have developed and shared. Here is a list of a few of my favourites to give you some more inspiration!
- @Random_Robbie‘s Docker Hub profile fullll of containers here.
- @ZephrFish‘s Dockerfile for an Attack Deploy Server in Git.
- Similar posts have been created on how to build Apache docker containers.
Thank you for reading!