Docker Setup

Go up to the NWS HW page (md) | view one-page version

Overview

In this assignment you will configure your computer to use Docker, which we will be using throughout this course. Docker is an operating system level virtual machine. We are providing a configuration that we are expecting to work for all the homeworks in this course. This docker setup has been tested on three platforms:

It worked correctly on all three systems. As those systems span the three operating systems in use, as well as the two major chip types in use, it is expected that it will work on your system as well. If you run into problems, please let us know.

You will be submitting an edited version of the docker.py (src) file.

We realize you may not know any Linux commands – that’s fine, as a Linux usage tutorial is forthcoming. For this assignment, all the Linux commands that you need are given herein.

This assignment has very little in terms of the deliverable – in fact, you could easily skip to the ‘Submission’ section, make up answers, and get full credit on this assignment. HOWEVER, this assignment is going to be necessary to complete before doing any other assignment in this course, as pretty much all the assignments will be using this docker setup.

If you get stuck, or are unable to proceed past a certain point, don’t panic. Try to get help from the course staff. You can also ask fellow students for this assignment. If it still does not work, still submit the file at the end, and indicate (in the comments field therein) where you got stuck. As long as you make a sincere effort to complete this assignment, you will still get full credit.

Changelog

Any changes to this page will be put here for easy reference. Typo fixes and minor clarifications are not listed here.

Step 1: Pre-requisites

After reading the background section below, you should choose the particular setup specific to your operating system. This tutorial assumes you have administrator (or sudo) access on your machine.

Background

Your computer is running a given operating system – this is the host operating system. Whatever else you run on your machine, that OS will always be the host. When you run a virtual machine (VM), that VM may run a different OS – and you may be running many of these VMs at once. These are called the guests (or guest OSes). For docker, the guest OS is always Linux, even if you are running on a Windows host or a Mac host.

The way Docker works is you download or build an image. An image is like a hard drive – it has all the files necessary to boot a version of Linux, whether it be Ubuntu, Kali, Debian, or any other Linux flavor. When you want to run such an image, you instruct docker to launch a container. A container is just a running image. From one image, you can have a dozen containers running. You can also have containers of different images running as well. So it is analogous to an executable file (the image) and a running process (the container) – given a single executable file, you can have it running a dozen times, each time being a separate process.

Windows host setup

You will need to install WSL (Windows Sub-system for Linux); you can see how to install that here

Once you have installed WSL, you need to install the x11-xserver-utils package: sudo apt update followed by sudo apt install x11-xserver-utils.

Mac OS X host setup

You will need to install Homebrew; the directions for how to install that are here.

One homebrew is installed, you should install two packages: socat and xquartz. The commands to install these packages are: brew install socat and brew install xquartz. Note that one of them (likely socat) needs to listen to network connections in the background; OS X will pop up a warning, although that may not occur until it is run. The use of these two programs will be explained below.

Linux host setup

No further installation steps are necessary.

Step 2: Installation

Note that there are two things to install on this page – don’t forget the second one (docker-compose).

Install docker

The installation varies by operating system and chip type. Docker is both the virtual machine software that we will be using, as well as company that helps to develop and market it. Docker the company wants to sell you subscriptions and what-not, but that is not needed for what we will be using it for in this course. There is no need to create Docker accounts nor to pay for anything Docker related.

The installation instructions are here.

One installed, you can check to see if it works by running docker pull hello-world and then docker run hello-world. You should see output similar to the following:

$ docker pull hello-world
Using default tag: latest
latest: Pulling from library/hello-world
478afc919002: Pull complete 
Digest: sha256:4bd78111b6914a99dbc560e6a20eab57ff6655aea4a80c50b0c5491968cbc2e6
Status: Downloaded newer image for hello-world:latest
docker.io/library/hello-world:latest

What's Next?
  View a summary of image vulnerabilities and recommendations → docker scout quickview hello-world

$ docker run hello-world

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (arm64v8)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

$ 

If that is not working properly for you, then you will need to fix that before you continue.

Install docker-compose

docker-compose is a command that makes it much easier to manage complicated docker setups. It probably installed with the installation of Docker itself. To check, run docker-compose help. If you get “command not found”, or similar, then you will need to install it – you can see the installation instructions here.

Step 3: Configuration

A mini tutorial for how to use docker is coming shortly – we first want to set up the course environment, which will give us something to work through for the mini tutorial.

Edit docker-compose.yml

Download the docker-compose.yml file. This file contains part of the course Docker setup. Although it is quite long, it’s not as complicated as it looks, but we’ll get into that later.

You will need to configure that file for your particular setup:

  1. Create a directory to hold your course materials. This can be any directory, and any files that are in that directory will be visible (but read-only) when inside docker. This will allow you to use your favorite editor, and then use the updated version of the program inside docker. Make this anywhere you want; we’ll call it /path/to/cs4760/docker/ herein.
  2. Edit the docker-compose.yml file. The line - DIRECTORY:/mnt:ro appears throughout (a total of 8 tines). You need to change DIRECTORY on that line to the the path from above. This allows the various docker containers to see that directory. In the example here, you would change it to - /path/to/cs4760/docker/:/mnt:ro. Be sure to keep the initial - before the line, as well as the indentation! There also needs to be the :ro suffix (that makes the directory read-only so malware on the docker container cannot write to your files). You will want to do a global search-and-replace rather than changing each one by hand.
  3. Edit the docker-compose.yml file some more. The line - DISPLAY=MYDISP also appears throughout (also 8 times). This has to be changed for some systems, based on the host operating system that is running on your computer.
    • Linux & Windows: No change is necessary; the default - DISPLAY=:0 is what is needed for Linux and Windows hosts.
    • Mac OS X: You will need to change it to something such as DISPLAY=192.168.1.100:0, where 192.168.1.100 is your IP address. Unfortunately, you will have to make this change if your IP address changes. There are a few ways to find your IP address:
      • Via ifconfig. Your network interface is probably called en0, so you can run ifconfig en0. You should see a line such as, inet 192.168.1.100 netmask 0xffffff00 broadcast 192.168.1.255 – the 192.168.1.100 is your IP address.
      • Via system settings -> network -> wifi -> details (for the current wireless connection) -> TCP/IP.
    • Make sure you put the :0 after the IP address

Platform notes: Windows hosts

Note that for the docker command to work in WSL, the Docker Engine has to be loaded.

If you have a Windows host, you may have to enable WSL bindings in the Docker Engine application. When in WSL, try entering docker help – if the command is not found, then you need to enable it. In the Docker Engine application, in settings (gear wheel on the top bar), it’s the WSL setting therein. See https://docs.docker.com/desktop/wsl/ for more details about using Docker with WSL.

Windows Defender, or whatever firewall you have enabled, will likely complain when you start the Docker containers, as it notices that the network configuration has changed due to the Docker networks that are created as part of the container start-up. You will have to allow this in order to use this Docker setup on your machine.

For the path of your docker/ directory, that you edited above, you should enter it slightly differently. From WSL, your C:\ drive is visible as /mnt/c. So if your Windows docker directory is c:\Users\mst3k\docker\, you should enter your path as /mnt/c/Users/mst3k/docker/.

Docker Desktop seems to go to sleep. If none of your commands in WSL work, try waking up Docker Desktop, which will reactivate the Docker Engine.

Lastly, in Windows, note that when you have to enter “Dockerfile” on the command line (or “Dockerfile.metasploit2”) in the commands below, you may have to do it all lower-case (“dockerfile” or “dockerfile.metasploit2”). This only applies to Windows hosts, and has been found to be inconsistent between Windows installations (some need lower-case, some don’t).

Build the image

First, check to see what images are on your machine – this is done via docker images. You should see the following:

$ docker images
REPOSITORY                  TAG                 IMAGE ID       CREATED        SIZE
hello-world                 latest              ee301c921b8a   8 months ago   9.14kB
$

The hello-world image is what you used to test that your docker install worked.

There are two images that need to be built, and each has their own configuration file. You will need to download both Dockerfile and Dockerfile.metasploit2. The nws-exec.sh (src) file must also be present, as it is needed to build the image.

There are four commands you need to enter, in succession, to build the course image:

One those completed, and assuming they completed successfully, you should run docker images again, and you will see something simnilar to the following:

$ docker images
REPOSITORY                  TAG                 IMAGE ID       CREATED        SIZE
metasploit2                 latest              930661a2090e   4 seconds ago   1.62GB
nws                         latest              c8a670c446df   4 minutes ago   2.81GB
ubuntu                      22.04               da935f064913   4 weeks ago     69.3MB
hello-world                 latest              ee301c921b8a   8 months ago    9.14kB
tleemcjr/metasploitable2    latest              db90cb788ea1   5 years ago     1.51GB
$

Your hash values (the “IMAGE ID” column), created dates, and sizes may vary. All told, the images are taking up about 6 Gb of disk space.

Step 4: Learn

We have a docker reference (md) available; the descriptions below will be using those commands.

You will be using docker extensively throughout the semester, so you should experiment with these commands. There really isn’t much you can break – if you kill a few containers, just restart the setup via docker compose down followed by docker compose up.

Launch the containers

At this point, you have built the images, but nothing is running. To run the images, you should enter: docker compose up. This will launch the course setup in a series of 8 docker containers. The setup looks like the following; this looks complicated now, but it will all become clear in time. You can click on the image below for a larger version.

Each square box represents a container. The bold name is the hostname for that container, and the IP values are fixed for each node on each network. The wide ovals are the three networks that are configured. All the nodes route their Internet traffic through the firewall node. The inner and other nodes route through gateway as well. There are two paths from other to the Internet – the correct route is through gateway, but one of our assignments will hijack that route and send it through outer1, which is why outer1 is also connected to the othernet network. Lastly, the metasploit container is the intentionally vulnerable container that we will practice exploits on.

Docker commands: creation and running

We have already seen a few commands to create the containers and start them running:

The new command is:

Docker commands: inspection

There are a few commands that you can use to see what is running, what images you have, etc. The command we have seen:

The new commands are:

Docker commands: clean-up

If you experimented with these commands, you should re-launch the containers: docker compose down followed by docker compose up.

docker exec

This is what this party is all about! We can manipulate the images, but we haven’t actually used them yet.

When the containers are running, you can connect to a container via docker exec -it <cid> /bin/bash. This is running a command (here /bin/bash, the shell) on a given image (which is <cid>). The image name is either the left-most value (the hash) or right-most value (the container name) column of docker ps -a. The -it command allows this docker exec command to be both interactive (i) and output to the terminal (t). You can attach to a container in as many shell windows as you would like – there will be times we will have half a dozen shells connected to the same container.

The hostnames are shown above in the diagram. When connecting to an image, the images all have “nws-” prefixed. Thus, to connect to outer1, you would use the image name nws-outer1 as such: docker exec -it nws-outer1 /bin/bash.

Here is an example usage:

$ docker exec -it nws-outer1 /bin/bash
root@outer1:/# hostname
outer1
root@outer1:/# hostname -I
192.168.100.101 192.168.150.3 
root@outer1:/# ls /mnt/
notes.txt
root@outer1:/# exit
exit
$

This connected to outer1, and ran a few commands therein to see the hostname and the IP addresses. The last command, ls /mnt looked at the files in /mnt, which is mapped to the directory you created and chose above (in step 3: /path/to/cs4760/docker/).

We will be using this command a lot, including later in this tutorial.

Other commands

If you have a Docker Hub account (not necessary for this course), you can run docker login. The Docker Hub is the source where docker pull gets the images from. Note that logging in is not necessary. If you want to login to another docker repository, you would use docker login <server>:5000.

If you want to copy a file to or from a container, you would use docker cp. Note that if you have a file in your /path/to/cs4760/docker/ directory, then you don’t need to copy it into the container, as you can view it in /mnt/.

Step 5: GUI

Command line usage is great, but we also want to be able to run GUI programs from Docker. The directions for this vary by operating system, and are also included on the docker reference (md) page. Note that most of the “one-time installation” steps on that page have already been run.

As before, pick the set of instructions particular to your host.

Mac OS X hosts

Running a GUI from docker is a bit tricky in OS X. Docker can’t directly access the display, so we have to send the GUI over a docker network to the host machine; this is what the socat and xquartz programs, that you installed above, are used for. socat is what transfers the GUI graphical image to OS X, and xquartz is what receives that data and displays it.

You will have to log out and then log back in (or restart) after you installed xquartz, and before you do this step – part of xquartz runs in the background, and that is only started on a login.

The docker reference (md) page lists a number of troubleshooting tips to try if things are not working correctly.

When you are done, the commands to shut down xquartz and socat are:

You can also quit the docker engine, if desired.

Linux hosts

When shutting down, you can remove the xhost permission (via xhost -local:docker), but it does not seem to be a security issue if you leave it as-is. If you do remove it, you will have to re-add it the next time you use a GUI from Docker.

Windows hosts

To shut down, in WSL, you can remove the xhost permission (via xhost -local:docker), but it does not seem to be a security issue if you leave it as-is. If you do remove it, you will have to re-add it the next time you use a GUI from Docker. You can also quit the docker engine, if desired.

Step 6: Exploit

We are going to exploit a vulnerability in vsFTPd version 2.3.4; this is CVE 2011-2523. This had a CVE score of 10.0, which is the highest level of vulnerability that exists.

FTP, which stands for file transfer protocol, is a means of efficiently transferring files from a server to a client. While it’s mostly been replaced by http and https these days, you will still find it around, as it is more efficient than http and https.

There were many implementations of the FTP server, and vsFTPd (“Very Secure FTP Daemon”) is a GPL (meaning open-source) implementation of an FTP server. Sometime in 2011, an unknown person put in a back door into the vsFTPd code where any username that ends with :), followed by any password, will open up a backdoor on port 6200.

The metasploit container has this vulnerability.

To exploit it:

If you are interested in seeing how this works (not necessary for this assignment), see this page, under the “Why It Works” header. Lines 12 and 13 check if the last two characters are : and ), and then – if they are – launches the backdoor via the vsf_sysutil_extra() function call.

Submission

You will be submitting an edited version of the docker.py (src) file. The comments therein explain what values you should fill in. We are interested in honest answers, not sycophantic answers. The assignment is auto-graded, so you will get full credit as long as you fill in the values in that file correctly.

That file is the only file you should submit to Gradescope.

As mentioned above, if you get stuck, or are unable to proceed past a certain point, don’t panic. Try to get help from the course staff. You can also ask fellow students for this assignment. If it still does not work, still submit that file, and indicate (in the comments field therein) where you got stuck. As long as you make a sincere effort to complete this assignment, you will still get full credit.