Some of you may have heard about the recent vulnerability in the Bourne Again Shell (bash) which is installed on nearly all Linux servers and many other systems. This vulnerability is officially labelled “CVE-2014-6271” and “CVE-2014-7169”. With such catchy names, it’s not terribly surprising that commentators have dubbed it “shellshock” for reasons which become apparent on a cursory examination of the name. Since “shellshock” is easier to say than the fancy CVE stuff, I’ll call it that here.
Before I go into more detail about just what Shellshock is, I need to first reassure everyone that Lexicom has applied the required patches to fix the vulnerability on our systems.
Now for just what Shellshock is. Warning: technical content ahead.
Bash is what is known in the Unix world as a “shell” which is just a fancy term for the program that lets you type in commands. It can also interpret files as a list of commands to run. In fact, Bash has a rather complete set of tools built into it that allow for some fairly advanced programming. This includes such useful things as functions. These programs are known as “shell scripts” or “bash scripts” if they require Bash specifically.
For historical reasons, it is possible to pass functions to a subshell (basically, another instance of Bash started by a shell script) using environment variables. To support this, bash has to examine all the environment variables that are passed into it when it starts and look for something that looks like a function definition. Then it has to parse those and turn them into functions that it can actually use. The names of these functions are derived from the name of the variable that defines them. This processing occurs even before Bash starts executing the script or commands it has been given.
While the notion of doing this is questionable for various reasons that I will not get into here, if that was as far as it went, Shellshock wouldn’t be such big news because most possible environment variable injection vectors limit the names of those variables and functions do nothing if they are not actually called. However, there are bugs in how an unpatched Bash processes these. As long as the variable contains a well formed function definition with nothing extra, no problems occur.
In this case, though, there are a couple of cases that Bash did precisely the wrong thing with. If the function definition is well formed but there is extra text following it in the variable, Bash would execute that as though it were a command given to it. Further, malformed function definitions would allow for slightly more complicated means to execute code with a higher bar to being exploitable. In the former case, anything that looked like a function declaration could be structured to allow any arbitrary shell commands to be executed no matter the name of the variable. I must confess to not quite understanding the second case well enough to make a judgement on just how difficult it is to exploit.
To understand just why this is a huge problem, you need to first know a few things about environment variables. First, when a process starts, environment variables can be provided by the process that starts it. The process itself has no control over what variables are passed into it this way. Second, most common means of starting new processes simply pass the existing set of environment variables on to the new process, usually unmodified.
Environment variables are immensely useful for passing information between processes without having to use more cumbsome means such has temporary files. The uquitous Common Gateway Interface (CGI) used to implement dynamic web sites all over the Internet makes extensive use of environment variables. There are many other situations where environment variables are used. These usually have specific names that must be used. For the remainder, I will examine the CGI situation but it is by no means the only possible vector for Shellshock.
Various bits of the HTTP dialogue get passed to a CGI program in environment variables. Much of this information is provided directly by the remote user and is passed through largely unmodified. For instance, there is the “Referer” header in the HTTP protocol which is usually provided by your web browser when you visit a site and says which page you were last on. This is provided to the CGI program as the HTTP_REFERER environment variable. Since this is provided by your browser, if you used different software, you could provide anything you wanted as the value of the Referer header, including something that Bash would interpret as a function definition. If you structured it carefully, you could arrange for Bash to run whatever commands you wanted.
Of course, your CGI programs are likely written in Perl or PHP or even C or C++ rather than as a shell script, so you’re safe from this, right? Not necessarily. Remember that environment variables are passed along unmodified by many interfaces used for running external programs. That means the external program sees the same HTTP_REFERER environment variable. Of course, if that program is not implemented using Bash, it won’t be directly vulnerable either. But what if, somewhere along the chain of calls to external programs, something launches Bash? Suddenly, the specially crafted HTTP_REFERER variable gets interpreted and the payload command executes!
You may be wondering how common that is. It’s much more common than you might think. Several common interfaces for invoking external commands actually use the system shell to invoke the command. That is, the command line is passed to the shell for interpretation and then it is the shell that actually launches the program. This is the case with the common system() call, but that is not the only call where this might happen. If the system shell happens to be Bash (like on a large fraction of Linux servers), that makes the number of steps to an exploitable situation much smaller.
Even if your program doesn’t seem to launch any external programs, it may be happening behind the scenes anyway. For instance, the PHP mail() function usually invokes an external program called “sendmail”. Even if the actual invocation of sendmail doesn’t use the shell, it’s possible for the sendmail program to be a shell script that does other processing before launching the real sendmail program. In other words, there are many dragons lurking in hidden places.
Now that you are suitably worried by Shellshock, there is another aspect that makes it just that much worse. This bug has been present in Bash since at least version 1.14 which was released in 1994. That means that every version of Bash deployed between 1994 and the release of the patches this week has been vulnerable. That means that it is nearly certain that all actual deployments of Bash in the wild were vulnerable. There were no cases where an older version still in use for some reason (the most common being that upgrading is annoying so people often don’t bother) was safe as is often the case with these sorts of bugs.
Given that the vulnerability has been around for two decades, it is impossible to know if any compromises due ot it have occurred. Very few will have audit trails going back that long and most audit trails won’t included a complete log of all inputs including environment variables passed to every program anyway. (Can you imagine the reams of data that would generate?) It also strains credulity to think that it has not previously been discovered and exploited by someone for personal gain.
All that said, until the past couple of days, there has been no obvious large scale exploitation of the bug – such activity would likely have been detected by some of the truly paranoid server operators and the problem brought to the fore much sooner. Thus, the usual precautions against data breaches should suffice: change your passwords regularly, verify the identity of sites before providing sensitive information, avoid clicking random links in emails, watch your financial statements closely, and so on.