A glimpse into Shellshock

Posted by Janani Kehelwala on September 13, 2018 · 6 mins read Archived

Shellshock is a family of exploits which lets attackers execute arbitrary code through Unix Bash Shells.

What made Bash vulnerable?

A user can append commands to a function definition. And the function definition can be attached to an environment variable of the shell. Therefore, if an attacker could pass an arbitrary value to an environment variable in Bash, then any machine can be exploited.

For example, if user can set VAR to following,

VAR=() { ignored; }; /bin/id

/bin/id is executed upon the variable being imported to bash process. The execution is independent of the variable name. The execution follows the function definition, which itself could be set to any payload (within any length boundaries of the program used to initialize the variable). This allows for any arbitrary code to be executed.

Code injection with Apache CGI Scripts

Let us look at a specific exploit of this family, which allows code injection with Apache CGI Scripts. Exploit code can be found from rapid7/metasploit-framework git repository

In this particular example, the code is injected through Apache HTTP Server’s mod_cgi module, which handles execution of CGI (Common Gateway Interface) scripts, which are console-like programs executed directly on the server. CGI scripts are used to generate dynamic responses according to the HTTP requests received from clients with the URL referring to a specific script. Script is run and output is passed back as a HTTP Response. CGI scripts are capable of defining environment variables, which is where the problem lies. While the variables are limited to script environment itself, if Bash is called, they are exported to bash. This generates the perfect window for code injection.

The default HTTP header used by malicious requests to inject code is the “User-Agent” header (as defined by the default parameters in above code). A valid use case for this scenario could be outputting the headers required for a well-formed HTTP response (albeit much more secure ways to generate this response can be thought of).

Backdoors

Aforementioned exploit from Metasploit framework can be used to deliver multiple payloads to a target system running Apache HTTP server with cgi scripts enabled. It can be used in conjunction with a payload such as “reverse_tcp”, which will connect back to the attacker, and spawn a command shell, providing a very nice backdoor and the satisfaction of a successfully executed privilege escalation attack.

Why was this attack successful?

This can be attributed to multiple factors. The biggest contributor was Unix being the most common operating system used in servers worldwide in the form of various Linux flavors and MacOS. The universal use of Bash and Apache HTTP servers also did not help. But these factors are not exclusive to Shellshock.

CGI scripts being able to execute Bash if required was a big mishap. To make matters worse, Bash function definition being able to be set into any arbitrary code, which could be self-called in the trailing code, resulting in many payloads being able to be executed was another mishap. But the third and the most contributing factor for the success of this attack was the lack of input sanitization by the Bash itself.

Learning from mistakes

How could this attack have been prevented or mediated?

  • The execution of commands trailing a function definition could be sanitized prior to execution.
  • CGI scripts should not be allowed to define environment variables in Bash, which itself holds many valuable and secure information in environment variables.
  • CGI could pass such variables as a general parameter. This demonstrates how crucial function level access control is in program design.
  • CGI scripts should be run with the privileges of user assigned for Apache HTTP server, provided that that particular user only has server specific privileges.
  • If Bash shell had restricted the functionality of function definition to privileged users, then the attack could have been mediated.

To further cement above suggestions, check out an initial patch to the Shellshock vulnerability which implements the following.

  1. “Change the encoding bash uses for exported functions to avoid clashes with shell variables”
  2. “Avoid depending only on an environment variable’s contents to determine whether or not to interpret it as a shell function.”
  3. Restrict importing “functions from the environment in privileged mode”.

Takeaway?

We are never fully aware of the full functionality of an application. We only use it for what we need and then let it be. But if we are calling something else from something that is public facing, we have to sanitize the input, restrict privileges to only what needs to be done and nothing else, and keep a close eye on new vulnerabilities. To conclude while being sinfully generic, what I can say is that Input sanitization will never hurt, and that programs only need privileges to do what were meant to do, and nothing else.