Home » When was the shellshock (CVE-2014-6271/7169) bug introduced, and what is the patch that fully fixes it?

When was the shellshock (CVE-2014-6271/7169) bug introduced, and what is the patch that fully fixes it?

Solutons:


TL;DR

The shellshock vulnerability is fully fixed in

  • On the bash-2.05b branch: 2.05b.10 and above (patch 10 included)
  • On the bash-3.0 branch: 3.0.19 and above (patch 19 included)
  • On the bash-3.1 branch: 3.1.20 and above (patch 20 included)
  • On the bash-3.2 branch: 3.2.54 and above (patch 54 included)
  • On the bash-4.0 branch: 4.0.41 and above (patch 41 included)
  • On the bash-4.1 branch: 4.1.14 and above (patch 14 included)
  • On the bash-4.2 branch: 4.2.50 and above (patch 50 included)
  • On the bash-4.3 branch: 4.3.27 and above (patch 27 included)

If your bash shows an older version, your OS vendor may still have patched it by themselves, so best is to check.

If:

env xx='() { echo vulnerable; }' bash -c xx

shows “vulnerable”, you’re still vulnerable. That is the only test that is relevant (whether the bash parser is still exposed to code in any environment variable).

Details.

The bug was in the initial implementation of the function exporting/importing introduced on the 5th of August 1989 by Brian Fox, and first released in bash-1.03 about a month later at a time where bash was not in such widespread use, before security was that much of a concern and HTTP and the web or Linux even existed.

From the ChangeLog in 1.05:

Fri Sep  1 18:52:08 1989  Brian Fox  (bfox at aurel)

       * readline.c: rl_insert ().  Optimized for large amounts
         of typeahead.  Insert all insertable characters at once.

       * I update this too irregularly.
         Released 1.03.
[...]
Sat Aug  5 08:32:05 1989  Brian Fox  (bfox at aurel)

       * variables.c: make_var_array (), initialize_shell_variables ()
         Added exporting of functions.

Some discussions in gnu.bash.bug and comp.unix.questions around that time also mention the feature.

It’s easy to understand how it got there.

bash exports the functions in env vars like

foo=() {
  code
}

And on import, all it has to do is interpret that with the = replaced with a space… except that it should not blindly interpret it.

It’s also broken in that in bash (contrary to the Bourne shell), scalar variables and functions have a different name space. Actually if you have

foo() { echo bar; }; export -f foo
export foo=bar

bash will happily put both in the environment (yes entries with same variable name) but many tools (including many shells) won’t propagate them.

One would also argue that bash should use a BASH_ namespace prefix for that as that’s env vars only relevant from bash to bash. rc uses a fn_ prefix for a similar feature.

A better way to implement it would have been to put the definition of all exported variables in a variable like:

BASH_FUNCDEFS='f1() { echo foo;}
  f2() { echo bar;}...'

That would still need to be sanitized but at least that could not be more exploitable than $BASH_ENV or $SHELLOPTS

There is a patch that prevents bash from interpreting anything else than the function definition in there (https://lists.gnu.org/archive/html/bug-bash/2014-09/msg00081.html), and that’s the one that has been applied in all the security updates from the various Linux distributions.

However, bash still interprets the code in there and any bug in the interpreter could be exploited. One such bug has already been found (CVE-2014-7169) though its impact is a lot smaller. So there will be another patch coming soon.

Until a hardening fix that prevents bash to interpret code in any variable (like using the BASH_FUNCDEFS approach above), we won’t know for sure if we’re not vulnerable from a bug in the bash parser. And I believe there will be such a hardening fix released sooner or later.

Edit 2014-09-28

Two additional bugs in the parser have been found (CVE-2014-718{6,7}) (note that most shells are bound to have bugs in their parser for corner cases, that wouldn’t have been a concern if that parser hadn’t been exposed to untrusted data).

While all 3 bugs 7169, 7186 and 7187 have been fixed in following patches, Red Hat pushed for the hardening fix. In their patch, they changed the behaviour so that functions were exported in variables called BASH_FUNC_myfunc() more or less preempting Chet’s design decision.

Chet later published that fix as an official upstreams bash patch.

That hardening patch, or variants of it are now available for most major Linux distribution and eventually made it to Apple OS/X.

That now plugs the concern for any arbitrary env var exploiting the parser via that vector including two other vulnerabilities in the parser (CVE-2014-627{7,8}) that were disclosed later by Michał Zalewski (CVE-2014-6278 being almost as bad as CVE-2014-6271) thankfully after most people had had time to install the hardening patch

Bugs in the parser will be fixed as well, but they are no longer that much of an issue now that the parser is no longer so easily exposed to untrusted input.

Note that while the security vulnerability has been fixed, it’s likely that we’ll see some changes in that area. The initial fix for CVE-2014-6271 has broken backward compatibility in that it stops importing functions with . or : or / in their name. Those can still be declared by bash though which makes for an inconsistent behaviour. Because functions with . and : in their name are commonly used, it’s likely a patch will restore accepting at least those from the environment.

Why wasn’t it found earlier?

That’s also something I wondered about. I can offer a few explanations.

First, I think that if a security researcher (and I’m not a professional security researcher) had specifically been looking for vulnerabilities in bash, they would have likely found it.

For instance, if I were a security researcher, my approaches could be:

  1. Look at where bash gets input from and what it does with it. And the environment is an obvious one.
  2. Look in what places the bash interpreter is invoked and on what data. Again, it would stand out.
  3. The importing of exported functions is one of the features that is disabled when bash is setuid/setgid, which makes it an even more obvious place to look.

Now, I suspect nobody thought to consider bash (the interpreter) as a threat, or that the threat could have come that way.

The bash interpreter is not meant to process untrusted input.

Shell scripts (not the interpreter) are often looked at closely from a security point of view. The shell syntax is so awkward and there are so many caveats with writing reliable scripts (ever seen me or others mentioning the split+glob operator or why you should quote variables for instance?) that it’s quite common to find security vulnerabilities in scripts that process untrusted data.

That’s why you often hear that you shouldn’t write CGI shell scripts, or setuid scripts are disabled on most Unices. Or that you should be extra careful when processing files in world-writeable directories (see CVE-2011-0441 for instance).

The focus is on that, the shell scripts, not the interpreter.

You can expose a shell interpreter to untrusted data (feeding foreign data as shell code to interpret) via eval or . or calling it on user provided files, but then you don’t need a vulnerability in bash to exploit it. It’s quite obvious that if you’re passing unsanitized data for a shell to interpret, it will interpret it.

So the shell is called in trusted contexts. It’s given fixed scripts to interpret and more often than not (because it’s so difficult to write reliable scripts) fixed data to process.

For instance, in a web context, a shell might be invoked in something like:

popen("sendmail -oi -t", "w");

What can possibly go wrong with that? If something wrong is envisaged, that’s about the data fed to that sendmail, not how that shell command line itself is parsed or what extra data is fed to that shell. There’s no reason you’d want to consider the environment variables that are passed to that shell. And if you do, you realise it’s all env vars whose name start with “HTTP_” or are well known CGI env vars like SERVER_PROTOCOL or QUERYSTRING none of which the shell or sendmail have any business to do with.

In privilege elevation contexts like when running setuid/setgid or via sudo, the environment is generally considered and there have been plenty of vulnerabilities in the past, again not against the shell itself but against the things that elevate the privileges like sudo (see for instance CVE-2011-3628).

For instance, bash doesn’t trust the environment when setuid or called by a setuid command (think mount for instance that invokes helpers). In particular, it ignores exported functions.

sudo does clean the environment: all by default except for a white list, and if configured not to, at least black lists a few that are known to affect a shell or another (like PS4, BASH_ENV, SHELLOPTS…). It does also blacklist the environment variables whose content starts with () (which is why CVE-2014-6271 doesn’t allow privilege escalation via sudo).

But again, that’s for contexts where the environment cannot be trusted: any variable with any name and value can be set by a malicious user in that context. That doesn’t apply to web servers/ssh or all the vectors that exploit CVE-2014-6271 where the environment is controlled (at least the name of the environment variables is controlled…)

It’s important to block a variable like echo="() { evil; }", but not HTTP_FOO="() { evil; }", because HTTP_FOO is not going to be called as a command by any shell script or command line. And apache2 is never going to set an echo or BASH_ENV variable.

It’s quite obvious some environment variables should be black-listed in some contexts based on their name, but nobody thought that they should be black-listed based on their content (except for sudo). Or in other words, nobody thought that arbitrary env vars could be a vector for code injection.

As to whether extensive testing when the feature was added could have caught it, I’d say it’s unlikely.

When you test for the feature, you test for functionality. The functionality works fine. If you export the function in one bash invocation, it’s imported alright in another. A very thorough testing could have spotted issues when both a variable and function with the same name are exported or when the function is imported in a locale different from the one it was exported in.

But to be able to spot the vulnerability, it’s not a functionality test you would have had to do. The security aspect would have had to be the main focus, and you wouldn’t be testing the functionality, but the mechanism and how it could be abused.

It’s not something that developers (especially in 1989) often have at the back of their mind, and a shell developer could be excused to think his software is unlikely to be network exploitable.

According to the NVD database at NIST (http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-6271), ALL VERSIONS of bash from 1.14.0 onwards are vulnerable.

RedHat got wind of the bug on September 14.

Patch released by Mr.Ramey (bash maintainer) on Sep-26-2014 fixes the CVE-2014-7169 bug.

Apply these and all previous patches to corresponding bash sources:

  • http://ftp.gnu.org/pub/gnu/bash/bash-2.05b-patches/bash205b-010
  • http://ftp.gnu.org/pub/gnu/bash/bash-3.0-patches/bash30-019
  • http://ftp.gnu.org/pub/gnu/bash/bash-3.1-patches/bash31-020
  • http://ftp.gnu.org/pub/gnu/bash/bash-3.2-patches/bash32-054
  • http://ftp.gnu.org/pub/gnu/bash/bash-4.0-patches/bash40-041
  • http://ftp.gnu.org/pub/gnu/bash/bash-4.1-patches/bash41-014
  • http://ftp.gnu.org/pub/gnu/bash/bash-4.2-patches/bash42-050
  • http://ftp.gnu.org/pub/gnu/bash/bash-4.3-patches/bash43-027

Extra vulnerabilities in bash

  • https://access.redhat.com/security/cve/CVE-2014-7186
  • https://access.redhat.com/security/cve/CVE-2014-7187

A bit more about the history of the bug (courtesy of mikeserv)

Source: http://www.linuxmisc.com/12-unix-shell/e3f174655d75a48b.htm

In 1994 Chet Ramey described it as predating the old POSIX 2 spec that specified exported functions, anyway. Or, at least, he described the bash mechanism as doing so – whether or not it was as flawed then as now I don’t know. He also discusses rc’s function exports in that thread as well.

Related Solutions

Joining bash arguments into single string with spaces

[*] I believe that this does what you want. It will put all the arguments in one string, separated by spaces, with single quotes around all: str="'$*'" $* produces all the scripts arguments separated by the first character of $IFS which, by default, is a space....

AddTransient, AddScoped and AddSingleton Services Differences

TL;DR Transient objects are always different; a new instance is provided to every controller and every service. Scoped objects are the same within a request, but different across different requests. Singleton objects are the same for every object and every...

How to download package not install it with apt-get command?

Use --download-only: sudo apt-get install --download-only pppoe This will download pppoe and any dependencies you need, and place them in /var/cache/apt/archives. That way a subsequent apt-get install pppoe will be able to complete without any extra downloads....

What defines the maximum size for a command single argument?

Answers Definitely not a bug. The parameter which defines the maximum size for one argument is MAX_ARG_STRLEN. There is no documentation for this parameter other than the comments in binfmts.h: /* * These are the maximum length and maximum number of strings...

Bulk rename, change prefix

I'd say the simplest it to just use the rename command which is common on many Linux distributions. There are two common versions of this command so check its man page to find which one you have: ## rename from Perl (common in Debian systems -- Ubuntu, Mint,...

Output from ls has newlines but displays on a single line. Why?

When you pipe the output, ls acts differently. This fact is hidden away in the info documentation: If standard output is a terminal, the output is in columns (sorted vertically) and control characters are output as question marks; otherwise, the output is...

mv: Move file only if destination does not exist

mv -vn file1 file2. This command will do what you want. You can skip -v if you want. -v makes it verbose - mv will tell you that it moved file if it moves it(useful, since there is possibility that file will not be moved) -n moves only if file2 does not exist....

Is it possible to store and query JSON in SQLite?

SQLite 3.9 introduced a new extension (JSON1) that allows you to easily work with JSON data . Also, it introduced support for indexes on expressions, which (in my understanding) should allow you to define indexes on your JSON data as well. PostgreSQL has some...

Combining tail && journalctl

You could use: journalctl -u service-name -f -f, --follow Show only the most recent journal entries, and continuously print new entries as they are appended to the journal. Here I've added "service-name" to distinguish this answer from others; you substitute...

how can shellshock be exploited over SSH?

One example where this can be exploited is on servers with an authorized_keys forced command. When adding an entry to ~/.ssh/authorized_keys, you can prefix the line with command="foo" to force foo to be run any time that ssh public key is used. With this...

Why doesn’t the tilde (~) expand inside double quotes?

The reason, because inside double quotes, tilde ~ has no special meaning, it's treated as literal. POSIX defines Double-Quotes as: Enclosing characters in double-quotes ( "" ) shall preserve the literal value of all characters within the double-quotes, with the...

What is GNU Info for?

GNU Info was designed to offer documentation that was comprehensive, hyperlinked, and possible to output to multiple formats. Man pages were available, and they were great at providing printed output. However, they were designed such that each man page had a...

Set systemd service to execute after fstab mount

a CIFS network location is mounted via /etc/fstab to /mnt/ on boot-up. No, it is not. Get this right, and the rest falls into place naturally. The mount is handled by a (generated) systemd mount unit that will be named something like mnt-wibble.mount. You can...

Merge two video clips into one, placing them next to each other

To be honest, using the accepted answer resulted in a lot of dropped frames for me. However, using the hstack filter_complex produced perfectly fluid output: ffmpeg -i left.mp4 -i right.mp4 -filter_complex hstack output.mp4 ffmpeg -i input1.mp4 -i input2.mp4...

How portable are /dev/stdin, /dev/stdout and /dev/stderr?

It's been available on Linux back into its prehistory. It is not POSIX, although many actual shells (including AT&T ksh and bash) will simulate it if it's not present in the OS; note that this simulation only works at the shell level (i.e. redirection or...

How can I increase the number of inodes in an ext4 filesystem?

It seems that you have a lot more files than normal expectation. I don't know whether there is a solution to change the inode table size dynamically. I'm afraid that you need to back-up your data, and create new filesystem, and restore your data. To create new...

Why doesn’t cp have a progress bar like wget?

The tradition in unix tools is to display messages only if something goes wrong. I think this is both for design and practical reasons. The design is intended to make it obvious when something goes wrong: you get an error message, and it's not drowned in...