CSE365 Lab: Shellshock Attack

1 Overview

On September 24, 2014, a severe vulnerability in bash was identified. Nicknamed Shellshock, this vulnerability can exploit many systems and be launched either remotely or from a local machine. In this lab, you will do several experiments to understand the Shellshock vulnerability. The learning objective of this lab is for you to get first-hand experience with Shellshock (and learn about reverse shells in the process), understand how it works, and think about the lessons that we can learn from this attack. Although it is most likely not still a threat to any existing systems, this type of vulnerability is still quite possible!

The bash program in Ubuntu 20.04 has already been patched, so it is no longer vulnerable to the Shellshock attack. For the purpose of this lab, we have installed a vulnerable version of bash inside the /bin folder of the docker container, and in the image_www folder of the lab setup code; its name is bash_shellshock. You will need to use this vulnerable bash in our task.

2 Environment Setup

2.1 DNS Settings

In our setup, the container’s IP address (the container will be acting as the web server to attack) is 10.9.0.80. The hostname of the server is www.seedlab-shellshock.com. We need to map this name to the IP address. Please add the following to /etc/hosts if it is not already there. Note that you need to have root (sudo) privilege to modify this file:

10.9.0.80       www.seedlab-shellshock.com 

2.2 Container Setup and Commands

Please download the Labsetup.zip file to your VM from the lab’s website (https://seedsecuritylabs.org/Labs_20.04/Software/Shellshock/), unzip it, enter the Labsetup folder, and use the docker-compose.yml file to set up the lab environment by running the following command.

$ dcbuild

Detailed explanation of the content in this file and all the involved Docker files can be found from the user manual, which is linked to on this lab website. If this is the first time you set up a SEED lab environment using containers, it is very important that you read the user manual. You will need to start the container using the command

$ dcup &

2.3 Web Servers and CGI

In this lab, we will launch a Shellshock attack on the web server (container) that we set up in 2.1 and 2.2. Many web servers enable CGI, which is a standard (if older) method used to generate dynamic content on web pages and for web applications. Many CGI programs are shell scripts, so before the actual CGI program runs, a shell program will be invoked first, and such an invocation is triggered by users from remote computers. If the shell program is a vulnerable bash program, we can exploit the Shellshock vulnerability to gain privileges on the server. In our web server container, we have already set up a very simple CGI program (called vul.cgi). It simply prints out "Hello World" using a shell script. The CGI program is put inside Apache’s default CGI folder /usr/lib/cgi-bin, and it must be executable.

#!/bin/bash_shellshock 
echo "Content-type: text/plain" 
echo 
echo 
echo "Hello World" 

The CGI program uses /bin/bash_shellshock (the first line), instead of using /bin/bash. This line specifies what shell program should be invoked to run the script. We do need to use the vulnerable bash in this lab. To access the CGI program from the Web, we can either use a browser by typing the following URL: http://www.seedlab-shellshock.com/cgi-bin/vul.cgi inside your VM, or use the following command line program curl to do the same thing. Please make sure that the web server container is running.

curl http://www.seedlab-shellshock.com/cgi-bin/vul.cgi

2.4 Vulnerable Bash

You will need to copy the vulnerable bash, (called bash_shellshock), from the image_www directory in the lab setup files you downloaded to the /bin directory in your VM. Once it is copied, link /bin/bash to the vulnerable version. To do this, first copy the good version to a backup file (1), and then link the bash_shellshock file to /bin/bash (2).

sudo mv /bin/bash /bin/bashpatched //(1)
sudo ln -s /bin/bash_shellshock /bin/bash //(2)

YOU WILL WANT TO UNDO THIS AFTER THE LAB, by moving the bashpatched back to /bin/bash. You can verify that this is successful by using the one liner test that we looked at in class! You will ALSO want to make sure that this step was successful before logging out or powering off the VM. If you accidentally remove your shell program and do not replace it, you will not be able to log back in to the VM, because it needs a shell to do so! To confirm that the link is valid, run

ls -la /bin/bash

Important

If this returns red text, or does not show it pointing to bash_shellshock, then you need to re-read section 2.4 (included the bolded text), and retry the commands.

3 Lab Tasks

3.1 Passing data to bash via environment variables

To exploit a Shellshock vulnerability in a bash-based CGI program, attackers need to pass their data to the vulnerable bash program, and the data need to be passed via an environment variable. In this task, we need to see how we can achieve this goal. We have provided another CGI program (getenv.cgi) on the server to help you identify what user data can get into the environment variables of a CGI program. This CGI program prints out all its environment variables.

#!/bin/bash_shellshock 
echo "Content-type: text/plain" 
echo 
echo 
"****** Environment Variables ******" 
strings /proc/$$/environ //(1)

3.1.1 - Using a Browser

In the code above, Line (1) prints out the contents of all the environment variables in the current process. Normally, you would see something like the following if you use a browser to access the CGI program. Please identify which environment variable(s)’ values are set by the browser. You can turn on the HTTP Header Live extension on your browser to capture the HTTP request, and compare the request with the environment variables printed out by the server.

3.1.2 - Using curl

If we want to set the environment variable data to arbitrary values, we will have to modify the behavior of the browser, which can be complicated. Fortunately, there is a command-line tool called curl, which allows users to to control most of fields in an HTTP request. Here are some of the userful options: 1. the -v field can print out the header of the HTTP request; 2. the -A, -e, and -H options can set some fields in the header request, and you need to figure out what fields are set by each of them. Please include your findings in the lab report.

Here are examples on how to use the fields:

$ curl -v www.seedlab-shellshock.com/cgi-bin/getenv.cgi 
$ curl -A "my data" -v www.seedlab-shellshock.com/cgi-bin/getenv.cgi 
$ curl -e "my data" -v www.seedlab-shellshock.com/cgi-bin/getenv.cgi 
$ curl -H "AAAAAA: BBBBBB" -v www.seedlab-shellshock.com/cgi-bin/getenv.cgi 

Based on this experiment, please describe what options of curl can be used to inject data into the environment variables of the target CGI program

Deliverables

In your lab report, include the following:

  1. The list of environment variables that are set by the browser.
  2. Which environment variables are set by the -v, -A, -e and -H options in curl.

3.2 Launching Shellshock

We can now launch the Shellshock attack. The attack does not depend on what is in the CGI program, as it targets the bash program, which is invoked before the actual CGI script is executed. Your job is to launch the attack through the URL http://www.seedlab-shellshock.com/cgi-bin/vul.cgi, so you can get the server to run an arbitrary command. If your command has a plain-text output, and you want the output returned to you, your output needs to follow a protocol: it should start with Content type: text/plain, followed by an empty line, and then you can place your plain-text output. For example, if you want the server to return a list of files in its folder, your command will look like the following:

echo Content_type: text/plain; echo; /bin/ls -l 

In this task, please use three different approaches (i.e., three different HTTP header fields) to launch the Shellshock attack against the target CGI program. You need to achieve the following objectives. For each objective, you only need to use one approach, but in total, you need to use three different approaches.

3.2.1

Get the server to send back the content of the /etc/passwd file.

3.2.2

Get the server to tell you its process’ user ID. You can use the /bin/id command to print out the ID information.

3.2.3

Get the server to create a file inside the /tmp folder. You need to get into the container to see whether the file is created or not, or use another Shellshock attack to list the /tmp folder.

3.2.4

Get the server to delete the file that you just created inside the /tmp folder.

3.2.5

HTTP GET requests typically attach data in the URL, after the ? mark. This could be another approach that we can use to launch the attack. In the following example, we attach some data in the URL, and we found that the data are used to set the following environment variable:

$ curl "http://www.seedlab-shellshock.com/cgi-bin/getenv.cgi?AAAAA" 
... 
QUERY_STRING=AAAAA 
... 

Can we use this method to launch the Shellshock attack? Please test this derive your conclusions based on your test results.

Deliverables

In your lab report, include the following:

  1. The command used to view the /etc/password file, and a screenshot of the /etc/passwd file.
  2. The command to discover the process owner, and the process owner ID of the CGI program.
  3. The command used to create the file, and a screenshot of the /tmp folder, with your file in it.
  4. The command used to delete that file.
  5. Will you be able to steal the content of the shadow file /etc/shadow from the server? Why or why not? The information obtained in Task 3.2.2 should give you a clue.
  6. The results of attempting to launch the shellshock attack using the query string in the URL.

3.3 Getting a Reverse Shell via Shellshock Attack

The Shellshock vulnerability allows attacks to run arbitrary commands on the target machine. In real attacks, instead of hard-coding the command in the attack, attackers often choose to run a shell command, so they can use this shell to run other commands, for as long as the shell program is alive. To achieve this goal, attackers need to run a reverse shell. A reverse shell is a shell process started on a machine, with its input and output being controlled by somebody from a remote computer. Basically, the shell runs on the victim’s machine, but it takes input from the attacker machine and also prints its output on the attacker’s machine (kind of like a malicious ssh session). Reverse shell gives attackers a convenient way to run commands on a compromised machine. Detailed explanation of how to create a reverse shell can be found in the SEED book. Note : when running netcat, ports up to 1024 are reserved for defined processes (we will talk about that more in networking). You can safely use any ports in the 9000 range.

Deliverables

In your lab report, include the following:

  1. The curl command you used to obtain the reverse shell.
  2. A screenshot of the reverse shell in action, showing via ifconfig that you have the reverse shell.

3.4 Attacking a setuid program with system() calls

In this section of the lab, we will look at another possible attack with shellshock, vulnerable programs on a machine that the attacker has access to, rather than a remote machine. You won’t attempt this through the reverse shell or on a remote machine - only the SEED VM is necessary for this part.

The following program is a setuid program, which simply runs the /bin/ls -l command. Please compile this code, make it a setuid program, and make root be its owner.

As we know, the system() function will invoke /bin/sh -c to run the given command, which means /bin/bash_shellshock will be invoked (important – verify that /bin/sh is mapped to /bin/bash_shellshock, and not dash or csh or another shell program. If it is not, you will need to change the symbolic link accordingly - and you’ll want to change it back afterwards). Check section 2.4 for instructions on how to do this.

To edit your /bin/sh use the following command:

sudo ln -s /bin/bash_shellshock /bin/sh

Can you use the Shellshock vulnerability to gain the root privilege?

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

void main()
{
  setuid(geteuid()); // make real uid = effective uid.
  system("/bin/ls -l");
}

$ gcc setuid.c -o setuid    
$ sudo chown root setuid               
$ sudo chmod 4755 setuid

It should be noted that using setuid(geteuid()) to turn the real uid into the effective uid is not a common practice in setuid programs, but it does happen. Now, remove the setuid(geteuid()) statement from the above program, and repeat your attack. Can you gain the root privilege? Please show us your experiment results.

In our experiment, when that line is removed, the attack fails (with that line, the attack is successful). In other words, if the real user id and the effective user id are the same, the function defined in the environment variable is evaluated, and thus the Shellshock vulnerability will be exploited. However, if the real user id and the effective user id are not the same, the function defined in the environment variable is not evaluated at all. This is verified from the bash source code (variables.c, between Lines 308 to 369).

Please pinpoint exactly which line causes the difference, and explain why bash does that.

Deliverables

In your lab report, include the following:

  1. Explain the attack you used to gain root privilege when the uid and euid were the same. Show a screenshot of the attack and the results.
  2. Specify which line(s) of variables.c prevent the attack from working when the uid and euid are NOT the same, and what part of that line prevents it. Please give us the code in question, not simply a line number.
  3. Explain why you think it works this way. (What is the security reason?)

3.5 Attacking a setuid program with execve() calls

Another way to invoke a program in C is to use execve(), instead of system(). The following program does exactly what the program in 3.4 does. Please compile the code, and make it a setuid program that is owned by root. Launch your Shellshock attack on this new program, and describe and explain your observation.

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

char **environ;

int main()
{
  char *argv[3];

  argv[0] = "/bin/ls"; 
  argv[1] = "-l"; 
  argv[2] = NULL;

  setuid(geteuid()); // make real uid = effective uid.
  execve(argv[0], argv, environ);

  return 0 ;
}

Deliverables

In your lab report, include the following:

  1. A screenshot of the results of running the attack on the execve version of the program.
  2. An explanation on why the results were either the same or different than when the program used system().

4 Submission

You will need to submit a written lab report through UBLearns, containing all of the deliverable elements above, by the due date specified in UBLearns. You are encouraged to explore beyond what is required by the lab.

4.1 Cleaning up after the lab

1) Make sure to reset /bin/sh to be a symlink to /bin/dash 2) Make sure to copy your good backup of bash (from section 2.4) to /bin/bash

Or, if possible revert your VM to your pre-shellshock state.

5 Scoring

Deliverables Points
3.1.1 3
3.1.2 3
3.2.1 3
3.2.2 3
3.2.3 3
3.2.4 3
3.2.5 3
3.2.6 3
3.3.1 5
3.3.2 5
3.4.1 3
3.4.2 3
3.4.3 3
3.5.1 1
3.5.2 3
Total 47