Don’t let anyone shock your shells

by in Security

It’s been the better part of a month since the ShellShock vulnerability disclosure, and the whole Internet has been buzzing ever since. There are probably more posts, POCs, and FUD articles right now than vulnerable systems. Why write another post about it, you ask? Well, most of the posts I have read so far describe the bug, how to verify whether your systems are vulnerable, or how to patch to a “safe” version, along with a growing list of attack vectors that include CGI scripts, SSH ForceCommand and authorized_keys’s command directives, DHCP, Qmail, SIP, and some FTP clients. The list is constantly growing and there are sites keeping track of the different attack vectors and POCs, such as those described by Mubix.

 

Although these vectors and POCs increase awareness and pressure your developers and administrators to quickly patch all the systems, my guess is that many enterprise systems will remain unpatched due to excuses like:

 

“We don’t want to touch this critical server and, after all, we are not running CGIs on it, just a bunch of web applications or services that have nothing to do with CGIs and, hey, we are not using SSH ForceCommand or anything similar, so we must be safe, right?”

 

It turns out this may not be the case, since your applications may interact with the underlying system shell (which normally defaults to bash) in ways that are no longer safe. Here are some vulnerable examples:

 

C/C

The system() function executes a system command using a shell. In the GNU C Library, it always uses the default shell /bin/sh to run the command, thus if an attacker can control any environment variable, they will be able to compromise the server:

 

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
 
int run_command(char* cmd) {
   …
   char *lang[100];
   int size = sizeof(lang);
   int bytes_read = read(socket, lang, size, 0);
   …
   putenv(lang);   // Eg: LANG=() { :;}; echo pwned
   …
   return system(cmd);
}

 

 execve() executes a program or a script spawning a new process with no shell interaction, and does it in a safe way:

 

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

int run_command(char* cmd) {
   …
   char *argv[] = { cmd, 0 };
   char *lang[100];
   int size = sizeof(lang);
   int bytes_read = read(socket, lang, size, 0);
   …
   char *envp[] = { lang, 0 };     // Eg: LANG=() { :;}; echo pwned
   execve(argv[0], &argv[0], envp);
   fprintf(stderr, "Oops!\n");
   return -1;
}

 

 

Note that the exec family won’t run the command through a shell and therefore is safe in principle, as long as the command is not forced to be executed through the shell as it is in the following example (assuming that /bin/sh is a redirect to /bin/bash):

 

 

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

int run_command(char* cmd) {
   …
   char *argv[] = { "/bin/sh", "-c", cmd, 0 };  
   char *lang[100];
   int size = sizeof(lang);
   int bytes_read = read(socket, lang, size, 0);
   …
   char *envp[] = { lang, 0 };   // Eg: LANG=() { :;}; echo pwned
   execve(argv[0], &argv[0], envp);
   fprintf(stderr, "Oops!\n");
   return -1;
}

 

 

PHP

Similar to C/C the PHP functions such as system(), passthru(), exec(),shell_exec(), `cmd` (back quoted commands) … will use a shell to run the commands, thus if an attacker can control any environment variable the application will be vulnerable:

 

<?php
…
$lang = $_GET[‘lang’];   // Eg: () { :;}; echo pwned
putenv("LANG=$lang");
system(cmd);
…
?>

 

 

Python

Python recommends using subprocess module functions instead of the deprecated os popen family and similar functions, so let’s focus on subprocess functions here.

 

The subprocess module functions normally take a shell argument. If shell is True, the specified command will be executed through the shell. This can be useful if you want convenient access to other shell features such as shell pipes, filename wildcards, environment variable expansion, and expansion of ~ to a user’s home directory. On Unix, with shell=True, the shell defaults to /bin/sh which normally symlinks to bash shell. So, in the case of an attacker being able to control an environment variable, in scenarios like the ones shown below, the application and underlying system could be compromised:

 

 

…
lang = request.GET[‘lang’]   # Eg: "() { :;}; echo pwned”
os.putenv("LANG", lang)
subprocess.call(cmd, shell=True)
…

 

 or

 

…
lang = request.GET[‘lang’]   # Eg: "() { :;}; echo pwned”
subprocess.Popen(cmd, env={"LANG":lang}, shell=True)
…

 

How can I verify my applications are running commands in a secure way?

The obvious recommendation is to patch all your systems, and not just the ones with well-known vulnerable services, such as CGIs scripts. If patching every box is not feasible, focus on the ones running vulnerable services and those running applications interacting with system commands.

The above examples may be found with manual code review, but if the code is not that simple and the dataflows are not that straightforward, using a Static Analysis tool is a great alternative as it can easily pinpoint places where user-controlled data reaches hazardous sinks and report Command Injection issues.

A picture is worth a thousand words, so we ran SCA on Apache httpd server code in order to detect the dataflows from the request headers to the point of the application running the CGI scripts with the tainted environment variables. We were able to find them as shown in Figure 1; however, what is more interesting and a better proof of static analysis value is that we also found a different instance of the same problem in another module.

 

Figure 1

 

mod_ext_filter

 

According to Apache Documentation, mod_ext_filter module can be used to process the response before sending it to the user. The module will run any executable or script processing the response data passed through the standard input and returning the processed response using the standard output file descriptor.

 

SCA was able to identify how Apache server reads the request headers and uses them to set the environment variables that are later used to execute the filter command. So in the case when the filter command is a bash script, attackers will be able to use a ShellShock payload to compromise the server even when it is not running any CGI scripts.

 

 

Figure 2

 

Protecting Apache server

 

SSR notified Apache about mod_ext_filter being vulnerable to ShellShock, which was known and acknowledged by their security team. While the obvious protection is to patch the underlying bash version, Apache has updated its mod_taint module to account for ShellShock. You can find more information here.

 

Stay Secure!

 

 

Anonymous