« Back to the main CSCI1660 website
This guide is designed to help you get started with setting up the environment you'll use for the Flag project.
The primary component of the project is the "Flag portal," a very insecure website that you will attack in order to give you practice discovering some real vulnerabilities and proposing fixes. In order to let you conduct attacks in a safe, repeatable way, we provide the website to you as a container image–you will run this container on your computer, which will host a version of the Flag portal for you to attack.
This guide will provide instructions on how to set up the flag container environment and how to work with it for the project.
New to docker? Before you can start download the Flag container environment, you'll need Docker installed on your system. If you do not have Docker installed from the last project, you can do so using this guide.
Before continuing, now is a good time to check in and make sure your container setup is performing optimally. If your container ran slowly or had issues during Project 1, take a look at the following notes and recommendations:
If you experienced exceptionally slow filesystem performance on MacOS, see here for instructions on how to update your docker settings for a fix.
If you still encounter poor filesystem performance, or you have issues after the fix, please let us know!
See these instructions for a full writeup of the problem and a list of workarounds that we think will help. If you encountered issues with Docker during project 1, we strongly recommend that you do the following steps from this guide now:
The instructions also list some workarounds you can use at times to help reduce Docker/WSL's memory usage when they start to get problematic–skim these over and then keep them in mind in case you run into issues!
To get started, we can download the flag container and start working with the project! We'll be using more features of Docker containers in this project, so first it's important to understand some background on how containers work.
As you attack the flag website, you will inevitably make changes to the website's state (like the server's filesystem, database, etc.) in ways that will break it. This is okay–and, in fact, encouraged! This is how you'll learn about the system and how it's vulnerable.[1]
What this means is that we need an easy way to make changes to the flag webserver and then revert it to a clean state, which is exactly the kind of workflow that containers were designed to do.
Up to this point, we've abstracted away some of the details of how containers work–now that we'll be using them for their primary purpose, here's some important terminology we'll use as we work with the flag container:
After testing, Docker makes it easy to discard the container instance and start over from the image, which is what we'll use in the project!
While working on this project, you'll have at least two containers on your system:
We've provided scripts for managing each container–you'll gain some practice with them in this guide.
To make development easier, we recommend cloning your stencil code for this project so you can access files in it from your development container. To do this, we recommend cloning the stencil in your DEV-ENVIRONMENT/home
directory, where DEV-ENVIRONMENT
is the name of the folder you used when you cloned the development container.
Here's an example of what your filesystem might look like (based on what you might have from project 1):
- ...
|--DEV-ENVIRONMENT
| |--docker/
| |--home/
| | |--pr01-cryptography-yourname/
| | |--pr02-flag-yourname/ # <----------- Clone your stencil here!
| |--run-container
| |-- ...
...
In the stencil repository, we've provided another script called run-container
, which automates downloading the flag container image and starting an instance of the webserver.
Note: the flag container runs separately from the "development container" container you used in the previous project, though you'll interact with it in a similar way. Both containers have a run-container
script–these scripts essentially do the same things, but they operate on different containers. For example:
DEV-ENVIRONMENT/run-container
controls your development containerpr02-flag/run-container
controls the flag containerSince the run-container
scripts need to interface with Docker, always make sure that you run ./run-container
from a terminal on your host system (or a WSL terminal, for Windows).
The rest of this guide will demonstrate how to work with everything, but keep the differences in mind as you read the instructions!
To download the flag container image, do the following:
cd
to the flag project stencil directory and run the following:# Download the container image
$ ./run-container setup
Windows users: If you get errors running this script the first time, you may need to run dos2unix
on the script. See here for more info.
This will download the latest version of the container image from our repository, which may take a few minutes. If we push updates to the image while the project is out, you can run this command again to pull the latest version (we'll post an announcement on Ed if this happens).
Now that the image is setup, we can launch an instance of the container, which starts up the flag portal webserver.
In a terminal on your host machine (or a WSL terminal on Windows), run the command ./run-container
. This should produce output that looks like this:
$ ./run-container # Start an instance of the flag webserver container!
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
Found network net-cs1660, skipping creation
***************************************************************************************
Container version: flag-webserver cs1660-flag-dev-d66e411-2023-02-24T20:13:22-05:00
Starting webserver at http://localhost:8888
Note: any warnings you see after this are safe to ignore if the URL
works--if not, include this log when posting about errors
*** Container network info ***
This container's internal IP: 172.19.0.2
This container's internal hostname: flag-webserver
***************************************************************************************
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.19.0.2. Set the 'ServerName' directive globally to suppress this message
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.19.0.2. Set the 'ServerName' directive globally to suppress this message
[Sun Feb 26 18:46:38.172735 2023] [mpm_prefork:notice] [pid 23] AH00163: Apache/2.4.54 (Debian) PHP/8.2.3 configured -- resuming normal operations
[Sun Feb 26 18:46:38.172818 2023] [core:notice] [pid 23] AH00094: Command line: 'apache2 -D FOREGROUND'
Running ./run-container
with no arguments starts up an instance of flag container, which runs a webserver that hosts the portal. Once started, the container prints out some information about how to connect to it, as well as a log of the webserver's operation. As you work on the project, you may find this information useful.
What to expect: After starting the container, your terminal should look like the example above and appear to hang–this indicates the webserver is running normally and waiting for you to connect to it, which we'll do in the next step.
Unlike your container for project 1, this container does not launch a shell: the point of this project is to attack the flag portal by exploiting vulnerabilities in the flag portal website, so you won't have access to a terminal unless you exploit a web vulnerability to acquire one!
If you receive an error when launching the container, or the container otherwise quits and returns you to your terminal, please post on Ed and include this log output so we can help you debug.
This issue might occur if another program on your system is using port 8888, the default port used by the webserver. If this occurs, do the following:
Ctrl+C
in the terminal../run-container clean; ./run-container
and try again.run-container
script and find the line webserver_port=8888
near the top. Change the port number (8888) to another number, like 8889–it should look like this:maindir=""
container_name=flag-webserver
network_name=net-cs1660
webserver_port=8889 # <---- Change this to a number not 8888 (in the range 1024-65535)
Save the script and try running ./run-container
again. If there is no error, connect to the webserver using http://localhost:<NEW PORT>
, where <NEW PORT>
is the new number you picked. Note: When the webserver starts, it will still tell you to connect on port 8888–this is a known issue (the value is hard-coded in the startup info)–you should connect with your new port anyway.
If the issue still persists, please check Ed for any similar issues, or feel free to make a new post.
(Don't do this now, but take note for later) You can stop the webserver by pressing Ctrl+C
in this terminal. By default, any changes made to the server's database or filesystem are preserved–for instructions on how to reset the webserver to clean state, see here.
If you lose the terminal where you ran ./run-container
for some reason, you can also stop it by running ./run-container stop
from another terminal. Once stopped, you can restart the webserver again by running ./run-container
.
Now we can connect to the flag portal website! To do this:
If you are unable to connect to the site, make sure your webserver is running from the previous step and has not exited. As a quick fix, try restarting it with ./run-container --clean
. If the issue persists, please check or post Ed to let us know!
Once you can connect to the flag portal, you can begin to poke around and start attacking the site! This guide will demonstrate the most important mechanics you should know as you work on discovering vulnerabilities.
The Flag portal is part of a fictional grading system at Blue University (think like Gradescope, but more insecure). You've managed to obtain the login credentials for one student (or maybe you are the student? you decide…):
Username: qmei
Password: iamqmei
Given this information, your job is to explore the flag portal website and see what vulnerabilities you can find. For more information on the types of vulnerabilities we expect you to find, and specific requirements for the project and grading, please see the handout and the wiki.
Remember: for this project, your goal is to find vulnerabilities in the flag portal website itself, any attacks on the container infrastructure itself are out of scope and will receive no credit.
The point of this project is to help you lean about web vulnerabilities, meaning we want you to behave as if you are a remote attacker who can only access the portal website. Since the container runs on your own computer, you can easily use docker
commands or other methods to "break in" and get a root shell, view files, etc.–these are outside the capabilities of the attacker we want to guard against (called the "threat model") and thus are NOT considered vulnerabilities.
Remember that you are being graded based on the web vulnerabilities you find (and your explanations of them)–attacks out of this scope will not receive credit, and are not in your best interest for learning about web vulnerabilities. (We'll learn about more OS vulnerabilities in the next project–and maybe Nick will talk about attacks on containers.)
As you attack the flag website, you will inevitably make changes to the website's state (like the server's filesystem, database, etc.) in ways that will break it–this is okay, and encouraged!
During this process, you'll find it useful to reset your website to its default configuration to test out attacks once you've figured out a procedure, and to conduct different attacks that may conflict with each other.
To try this out, let's alter the website to demonstrate how this works:
Now let's see how to reset the webserver and erase this change to show you how it works. To do this:
Stop your flag webserver container by pressing Ctrl+C
in the terminal. Alternatively, you can run ./run-container stop
from another terminal
Run ./run-container --clean
. This will delete your container instance and start a new container from a fresh copy of the image.
Refresh your tab with the portal website, or go to http://localhost:8888. You'll be prompted to log in again–your profile should be the same as before!
This guide has provided an overview of the most important mechanics you need to work with the container for this project. As you work on the project, keep in mind our Useful tools and resources
)
If you have questions, please feel free to come to hours or post on Ed. Have fun, and happy hacking!
If you are doing the CS1620/CS2660 part, Bob's router, see the next section for more guides and instructions for using the extra tools required for this component.
Now that you are done, please fill out this form to let us know you can access the webserver! This will help us make sure everyone can access these critical tools.
Bob's router uses an additional container, which is provided as part of your stencil repo. This extra container (which we'll call the "Bob container") performs all tasks ascribed to "Bob" in the handout. You don't know everything that Bob is doing, but here are the most important parts:
The Bob container has a separate run-container
script in the bob-router
directory of your stencil repo. You can use this run-container
script the same way you use the flag container (ie, downloading the image, starting/resetting the container, etc). This guide describes the most important parts.
First, we need to download the container image for the Bob container. To do this:
cd
to the bob-router
directory of the stencil repository# Download the container image
user@host-or-wsl:../flag-stencil/bob-router$ ./run-container setup
Windows users: If you get errors running this script the first time, you may need to run dos2unix
on the script. See here for more info.
This should download the container image, similar to how you set up the flag container.
Now we can start up Bob. To do this:
cd
to the bob-router
directory of your stencil repo./run-container
. This should produce output that looks like this:user@host-or-wsl:../flag-stencil/bob-router$ ./run-container # Start an instance of the Bob container!
*************************************************************************
Container version: bob-router cs1660-bob-0f23b83-2023-02-28T19:
Bob starting ...
In your flag container's main terminal, you should see log entries
this container's internal IP showing that Bob is fetching the w
every 10 seconds.
If not, restart this container (possibly with --clean) to reset
*** Container network info ***
This container's internal IP: 172.19.0.3
This container's internal hostname: bob-router
*************************************************************************
Starting Bob's "router"
Starting Bob's auto-refresh script
Xvfb: no process found
AH00558: apache2: Could not reliably determine the server's fullmain name, using 172.19.0.3. Set the 'ServerName' directive globss this message
AH00558: apache2: Could not reliably determine the server's fullmain name, using 172.19.0.3. Set the 'ServerName' directive globss this message
<br />
<b>Deprecated</b>: Directive 'allow_url_include' is deprecated /b> on line <b>0</b><br />
[Sun Mar 05 17:52:20.145075 2023] [mpm_prefork:notice] [pid 26] e/2.4.54 (Debian) PHP/8.2.3 configured -- resuming normal operat
[Sun Mar 05 17:52:20.145147 2023] [core:notice] [pid 26] AH00094: 'apache2 -D FOREGROUND'
BOB: Started firefox
What to expect: Bob takes several seconds to start. Once you see BOB: Started firefox
, Bob should be running successfully! Like the flag container, note that this container does not start a shell–there is no terminal for you to access. After Bob has started, you won't see any further output in this terminal until you've accessed the router. For more info on how to tell if Bob is running, see the next section.
While working with the Bob container, you should have terminals open to both the flag webserver and the Bob container–-both of these containers need to be running for Bob to work.
Normally, Bob's container doesn't print anything. However, you can check that Bob is fetching the flag portal regularly by looking at the log in your main flag webserver container–you should see requests for GET /
from the IP address of Bob's container every 10 seconds. Here's an example of what this should look like:
If your terminals look like this, Bob is running normally, yay! To begin attacking Bob's router, see the handout for a high-level description of the attack you'll be trying to perform. For more details, see the Gearup slides and recording. If you're ever concerned the Bob container isn't running normally, see Resetting Bob.
"What does Bob's container print?" Just like the flag webserver container shows a log of requests made to the flag portal's webserver, the Bob container shows a log of requests for the router's webserver. You can't access this webserver normally, but if the CSRF phase of your attack is successful, you'll see output here once Bob successfully fetches the router's webpage!
(This is more information than you'd actually have while performing this kind of attack, but it's available to you for debugging purposes.)
If you stop seeing regular requests from Bob, it's likely Bob is broken. To reset Bob:
Ctrl+C
in the Bob container terminal to shut down the container./run-container --clean
. This should reset the Bob container to its original state and restart it.There are three extra tools within the container environment you may find useful with this project, most especially for Bob's router:
These aren't the only ways to accomplish these tasks. However, we'll describe methods you can use that work within the container environment, meaning that they don't require access to other web hosting services or platforms.
webhook.site
)Sometimes, you may want to have your exploit code make a web request to some location that you control. This is useful when you want to exfiltrate some information from a user's browser, like stealing a cookie or revealing some other information about their browser or location.
This is particularly useful in scenarios where you are unable to directly view the HTTP response, but have the capability to redirect the response to a different endpoint.
To do this, we need a URL for your exploit to connect to–this is a common way for web applications to communicate. While we could do this by setting up a custom webserver to receive and process requests in a certain way, for this project we really just need a way to print out a list of who connects and any data they send. An easy tool for this is webhook.site, which creates unique URLs we can use for this. To use it:
netcat
)To receive web requests or other connections, we can use a program called netcat
to "listen" for connections on a particular port and print out the result. This allows us to read the content (headers, body, URL) of a web request and see the results. To do this:
run-container
)Warning: We're observing a known bug where the dev container's internal IP doesn't show up for all users like in this picture. If you don't see this info an need it later, you can run:
cs1660-user@661ad4fcfe8e:~$ hostname --ip-address
from the dev container to print its IP address. The container's internal hostname is always cs1660-dev
–this should always work too.
cs1660-user@661ad4fcfe8e:~$ nc -l -p 7169
This tells the netcat (nc
) command to listen for connections on port 7169.[2] After running the command, your terminal will hang–this is okay, it means that netcat is waiting for something to connect to it!
http://SERVER-ADDRESS:7169
. Due to come quirks with how containers interact with the network, the value for SERVER-ADDRESS
depends on how you're connecting to it:This container's internal hostname
" or "This container's internal IP
" from the network info you printed in Step 2. (For example, http://cs1660-dev:7169/
)localhost
, ie http://localhost:7169
. If this doesn't work, something may have gone wrong with the container's port forwarding–see this section for how to debug it.Once something has connected to your port, you should see netcat
print some output like this:
GET / HTTP/1.1
Host: localhost:7169
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
DNT: 1
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Sec-GPC: 1
This example shows a browser attempting to fetch http://localhost:7169/
with GET /
, as well as any headers sent during the request.
To close netcat, or try again, press Ctrl+C
. This will drop you back to a shell so you can try again!
You may find it useful to host a file at a URL so you can use it in an exploit. That is, you want to redirect an attacker to http://your-site.com/do-some-thing
, you need to control your-site.com
. To do this within the container environment on our systems, we don't need a .com
domain, we just need another place to run a webserver!
We've packaged a tiny container that will run a webserver for you (called the simple webserver) for this purpose. The next sections will show you how to set it up and use it.
Note: This webserver only hosts files–it does not run PHP or any other server-side code, which should not be necessary for the project. If you want to try out stuff with PHP, try out the web demo code from lecture.
To set up the simple webserver container image:
$ git clone https://github.com/brown-csci1660/simple-webserver.git
cd
to the simple-webserver
directory./run-container setup
to build the image for this containerWindows users: If you receive errors about newlines, you may need to run dos2unix
again–see this section for details.
./run-container
. You should see the same sort of webserver startup info you've seen for the flag webserver container, like the image below. As it starts, take note of the "container network info" section (highlighted in red below), which you'll need later.What to expect: Just like the flag webserver container, this container does not run a shell–instead, it shows a log of all requests to the webserver. To stop it, just press Ctrl+C
.
Due to come quirks with how containers interact with the network, the URL you'll use to connect to the webserver will differ depending on what system will be connecting:
This container's internal hostname
" or "This container's internal IP
" from the network info you printed in Step 2. (For example, http://simple-webserver/index.html
)If you're able to connect successfully, you should be able to view any page in the webroot
directory of the webserver.
Here's an example when connecting from the browser on a host system:
…and from another container (in this case, from the development container, using curl
):
The server hosts all files in the webroot
directory of the repository–placing a file here makes it available at the server's address, relative to the webroot
directory. For example, if you create webroot/exploit.php
, it will be available at http://<server address>/exploit.php
.
If you have questions or run into issues with this, please ask us or post on Ed!
A "reverse shell" is mechanism for obtaining a shell on a remote system, but instead of connecting to the system with SSH or telnet, the remote system connects to you!
A reverse shell is often used in exploits once you've found a way to execute arbitrary code on the system. Usually, whatever method you find to execute arbitrary code is pretty clunky to use, so it's easiest to use this to start a reverse shell so you can poke around just like you'd use any other terminal.
The security community has found many ways to build a reverse shell using different types of server-side code execution capabilities. If you find a way to execute arbitrary PHP code in this project, we recommend using this reverse shell, which is a PHP script: https://github.com/pentestmonkey/php-reverse-shell
For details on how to use it, see the PHP file in this repository. To use it with this project, you will need to listen on a port for the shell to connect to you–see Listening on a port for instructions how to do this. (We'll also demo this in class soon.)
If you see errors along the lines of bash: '\r': command not found
or bash: /home/cs1660-user/.bash_profile: line 5: syntax error: unexpected end of file
, see this section for common fixes.
By default, containers live in a separate network inside your system–they can't access your host machine without extra setup called port fowarding. Our container scripts use port forwarding to allow you to connect to the container from your host system. For example, the flag webserver container forwards port 8888 on your system to the container, which allows you to access the flag portal at http://localhost:8888.
If you're having issues accessing any forwarded ports, you can check if Docker setup the port forwarding rules correctly. On Windows or Mac, you can do this from Docker's desktop interface, as follows:
The figure above shows what the entry should look like for the flag portal webserver (highlighted in red): here, port 8888 on the local system (localhost:8888
) is forwarded to port 80 on the container, which is the container webserver's default port.
If you don't see an entry for a port that you expect to be forwarded, try the following:
./run-container --clean
netstat
command is installed on your host system (or in WSL, if you're on Windows). If your WSL is missing netstat
, install it with sudo apt-get install netstat
and then try starting the container again with --clean
.Breaking things isn't the only way to test the security of a system. It's possible to study a system in a stealthy manner, but this is much more difficult and beyond the scope of this course. ↩︎
While we can technically pick any port number 1025–65536 here, we choose 7169 because it's pre-configured with a forwarding rule so we can access it outside the container. This isn't relevant unless we want to connect to this port from our host system. ↩︎