77

I did apt-get update; apt-get upgrade -y on all systems I'm running. I'm not sure if my /etc/apt/sources.list is good enough on all of these systems. I would like to quickly check each system again, ideally with a one-line shell command.

Does such a one-line shell command exist and if so, what is it?

Note this question is mainly about CVE-2014-6271.

the
  • 1,841
  • 2
  • 17
  • 33
  • 1
    bash --version The bug effects versions of bash up to and including 4.3 – RoraΖ Sep 25 '14 at 11:31
  • 18
    @raz Checking the bash version is useless (except that versions after 4.3, which do not exist yet, won't be affected). Most systems will fix the hole by patching just the hole (usually by applying their distribution's normal update process), not by upgrading to a whole new version of bash (which, again, does not exist yet). – Gilles 'SO- stop being evil' Sep 25 '14 at 11:43
  • @Gilles `bash --version` will report a version number like `4.3.25` (which is the the patch which fixes the initial, although not the full, Shell Shock vulnerability). There's no reason to think that a patch- level release is any less able to fully patch the problem than some future 4.4 version. – chepner Sep 28 '14 at 13:37
  • @chepner ... which is exactly why checking the version number is useless. On most distributions, the upgrade that fixes the hole doesn't change the version number. The vulnerable version and the fixed version have the same version number. You cannot use it to tell whether the vulnerability is present. – Gilles 'SO- stop being evil' Sep 28 '14 at 14:14
  • 2
    I'd be a little miffed if my distribution is patching the code without bumping the version number *at all*. – chepner Sep 28 '14 at 15:05
  • @chepner: why? There's a difference between the version reported by the program and the package version. Well, there can be, let's put it this way. – 0xC0000022L Oct 08 '14 at 08:07
  • Yes, but the package can indicate a divergence from the upstream using revision levels. If the package manager decides to ship a version of `bash` 4.3.25 along with their own patches, the package version should be something like 4.3.25-1.0, 4.3.25-1.1, etc, *not* 4.3.26, 4.3.27 or worse, 4.3.25, 4.3.25 with *no* change in version. Changing the package version is one thing; stepping on the upstream's (at least, a sane upstream's) versioning scheme is another. The whole *point* of a version number is to indicate changes in the underlying code. – chepner Oct 08 '14 at 09:30

6 Answers6

125

Is my bash vulnerable?

This simple command is a sufficient test to see if your version of bash is vulnerable:

x='() { :;}; echo VULNERABLE' bash -c :

It's not necessary to have extra text printed to signify that the command has actually run, because patched versions of bash will report a warning when a variable in its starting environment contains exploit code for the patched vulnerability.

On a vulnerable system:

$ x='() { :;}; echo VULNERABLE' bash -c :
VULNERABLE

On a patched system:

$ x='() { :;}; echo VULNERABLE' bash -c :
bash: warning: x: ignoring function definition attempt
bash: error importing function definition for `x'

For a detailed explanation of what this does and does not test for, and why, see "Other Function Parsing Bugs" below.

Is my system vulnerable?

If your bash isn't vulnerable then your system isn't vulnerable.

If your bash is vulnerable, then your system is vulnerable inasmuch as it uses bash along attack vectors such as CGI scripts, DHCP clients and restricted SSH accounts. Check whether /bin/sh is bash or some other shell. The vulnerability is in a bash-specific feature and other shells such as dash and ksh are not affected. You can test the default shell by running the same test as above with sh instead of bash:

x='() { :;}; echo VULNERABLE' sh -c :
  • If you see an error message, then your system has a patched bash and isn't vulnerable.
  • If you see VULNERABLE, then your system's default shell is bash and all attack vectors are a concern.
  • If you see no output, then your system's default shell is not bash, and only parts of your system that use bash are vulnerable. Check for:
    • Scripts executed by bash (starting with #!/bin/bash, not #!/bin/sh) from CGI or by a DHCP client.
    • Restricted SSH accounts whose shell is bash.

How This Test Works

It runs the command bash -c : with the literal text () { :;}; echo VULNERABLE set as the value of the environment variable x.

  • The : builtin performs no action; it's used here where a non-empty command is required.

  • bash -c : creates an instance of bash that runs : and exits.

    Even this is sufficient to allow the vulnerability to be triggered. Even though bash is being invoked to run only one command (and that command is a no-op), it still reads its environment and interprets each variable whose contents start with () { as a function (at least those whose names are valid function names) and runs it so the function will be defined.

    The intent behind this behavior of bash is to run only a function definition, which makes a function available for use but doesn't actually run the code inside it.

  • () { :;} is the definition for a function that performs no action when called. A space is required after { so that { is parsed as a separate token. A ; or newline is required before } for it to be accepted as correct syntax.

    See 3.3 Shell Functions in the Bash Reference Manual for more information on the syntax for defining shell functions in bash. But note that the syntax used (and recognized) by bash as a valid exported shell function whose definition it should run is more restrictive:

    1. It must start with the exact string () {, with exactly one space between ) and {.
    2. And while shell functions occasionally have their compound statement enclosed in ( ) instead of { }, they are still exported inside { } syntax. Variables whose contents start with () ( instead of () { will not test for or otherwise trigger the vulnerability.
  • bash should stop executing code after the closing }. But (unless patched) it doesn't! This is the wrong behavior that constitutes CVE-2014-6271 ("Shellshock").

    ; ends the statement that defines the function, allowing subsequent text to be read and run as a separate command. And the text after ; doesn't have to be another function definition--it can be anything at all.

  • In this test, the command after ; is echo VULNERABLE. The leading space before echo does nothing and is present just for readability. The echo command writes text to standard output. The full behavior of echo is actually somewhat complicated, but that's unimportant here: echo VULNERABLE is simple. It displays the text VULNERABLE.

    Since echo VULNERABLE is only run if bash is unpatched and running code after function definitions in environment variables, this (and many other tests similar to it) is an effective test of whether or not the installed bash is vulnerable to CVE-2014-6271.


Other Function Parsing Bugs (and why that test and those like it don't check for them)

The patch that has been released as of this writing, and the commands described and explained above for checking vulnerability, apply to the very severe bug known as CVE-2014-6271. Neither this patch nor the commands described above for checking vulnerability apply to the related bug CVE-2014-7169 (nor should they be assumed to apply to any other bugs that may not yet have been discovered or disclosed).

The bug CVE-2014-6271 arose from a combination of two problems:

  1. bash accepts function definitions in arbitrary environment variables, and
  2. while doing so, bash continues running any code that exists after the closing brace (}) of a function definition.

As of this writing, the existing fix for CVE-2014-6271 that has been released (and rolled out by many downstream vendors)--that is, the fix you'd get by updating your system or by applying the existing patch manually--is a fix for 2.

But in the presence of other mistakes in bash's code, 1 is potentially a source of many additional parsing bugs. And we know at least one other such bug exists--specifically, CVE-2014-7169.

The command presented in this answer tests for whether or not an installed bash is patched with the existing (i.e., first official) fix for CVE-2014-6271. It tests vulnerability to that specific parsing bug: "GNU Bash through 4.3 processes trailing strings after function definitions in the values of environment variables[...]"

That specific bug is extremely severe--and the available patch does fix it--while CVE-2014-7169 appears to be less severe but is definitely still cause for concern.

As Stéphane Chazelas (discoverer of the Shellshock bug) has recently explained in an answer to When was the shellshock (CVE-2014-6271) bug introduced, and what is the patch that fully fixes it? on Unix.SE:

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.


But if that's what the exploit looks like...

Some people, here and elsewhere, have asked why x='() { :;}; echo VULNERABLE' bash -c : printing VULNERABLE (or similar) should be considered alarming. And I've recently seen the misconception circulating that because you have to have interactive shell access already to type in that particular command and press enter, Shellshock must somehow not be a serious vulnerability.

Although some of the sentiments I've heard expressed--that we should not rush to panic, that desktop users behind NAT routers shouldn't put their lives on hold to build bash from source code--are quite correct, confusing the vulnerability itself with the ability to test for it by running some specific command (such as the command presented here) is a serious mistake.

The command given in this post is an answer to the question, "Is there a short command to test if my server is secure against the shellshock bash bug?" It is not an answer to "What does shellshock look like when it's used against me by a real attacker?" and it is not an answer to the question, "What does someone have to do to successfully exploit this bug?" (And it is also not an answer to, "Is there a simple command to infer from all technical and social factors if I'm personally at high risk?")

That command is a test, to see if bash will execute code written, in a particular way, in arbitrary environment variables. The Shellshock vulnerability is not x='() { :;}; echo VULNERABLE' bash -c :. Instead, that command (and others like it) is a diagnostic to help determine if one is affected by Shellshock.

  • Shellshock has wide ranging consequences, though it is true that the risk is almost certainly less for desktop users who are not running remotely accessible network servers. (How much less is something I don't think we know at this point.)
  • In contrast, the command x='() { :;}; echo VULNERABLE' bash -c : is entirely inconsequential except insofar as it is useful for testing for Shellshock (specifically, for CVE-2014-6271).

For those who are interested, here are a few resources with information on why this bug is considered severe and why environment variables, particularly on network servers, may contain untrusted data capable of exploiting the bug and causing harm:

To further illustrate the conceptual distinction here, consider two hypotheticals:

  1. Imagine if instead of suggesting x='() { :;}; echo VULNERABLE' bash -c : as the test, I had suggested bash --version as the test. (That would actually not be particularly appropriate, because OS vendors frequently backport security patches to older versions of software. The version information a program gives you can, on some systems, make it look like the program would be vulnerable, when actually it has been patched.)

    If testing by running bash --version were being suggested, no one would say, "But attackers can't sit at my computer and type bash --version, so I must be fine!" This is the distinction between a test and the problem being tested for.

  2. Imagine if an advisory were issued suggesting that your car might have some safety problem, such as airbag failure or bursting into flames in a collision, and that factory demonstrations had been streamed. No one would say, "But I would never accidentally drive or tow my car 900 miles to the factory and have it loaded with an expensive crash dummy and slammed into a concrete wall. So I must be fine!" This is the distinction between a test and the problem being tested for.

Eliah Kagan
  • 1,315
  • 1
  • 9
  • 12
  • 10
    Hmm, but if I can run bash then can't I already execute arbitrary commands on a system? How is this a vulnerability? – Ajedi32 Sep 25 '14 at 14:08
  • 9
    @Ajedi32 `x='() { :;}; echo VULNERABLE' bash -c :` is a test to see if your bash is patched. The reason CVE-2014-6271 is a vuln at all is it gives the power to run arbitrary commands to anyone who can set the value of some environment variable (under conditions when a bash will then run with that variable set). Environment variables are commonly used to pass unsanitized, user-supplied data between processes. For example, *this is often exploitable via HTTP.* See http://seclists.org/oss-sec/2014/q3/650 under "So far, HTTP requests to CGI scripts have been identified as the major attack vector." – Eliah Kagan Sep 25 '14 at 14:31
  • 1
    @Ajedi32 `/bin/sh -c` is a used heavily to start child-processes. If the environment can be controlled by an attacker then there's a problem - the most common case is a web server using the environment as a form of [IPC](http://en.wikipedia.org/wiki/Inter-process_communication) when running a CGI scripts. – mr.spuratic Sep 25 '14 at 14:32
  • @mr.spuratic Your example is `/bin/sh -c` which is not `bash` but just the basic vanilla shell process. So I am still not getting the true risk here. Granted this is all unintended usage. But if the user cannot get elevated privileges past what the parent process has, the risk is what exactly? – Giacomo1968 Sep 25 '14 at 15:26
  • If bash isn't the default shell, wouldn't it be easier to use the: bash -c "env x='() { :;}; echo vulnerable' bash -c echo this is a test" oneliner? – somelooser28533 Sep 25 '14 at 14:30
  • 2
    @JakeGould The worst thing about this vulnerability is that to exploit it you don't need to have an account at all. Even if (for example) your web server runs under a strictly limited user account, it would be very bad for an attacker to be able to run arbitrary commands as that limited user, completely controlling your web server (and more). See [the explanation here](http://seclists.org/oss-sec/2014/q3/650). The most convenient ways to *test* for a vulnerability are not always of the same form as the most devastating ways to *exploit it in the wild.* – Eliah Kagan Sep 25 '14 at 15:36
  • 1
    @JakeGould It's true `sh` is only sometimes `bash`. This may be expected to mitigate the risk/harm somewhat. But even when not the system sh, bash is widely used for scripting, so arbitrary code execution is still possible. Commands after a function definition in an environment variable get executed when a bash script is run (as running a bash script, particularly from a shell or other process that isn't bash, involves running the bash executable to interpret it). Degree of risk for desktop users is unknown but malicious data (e.g., specially crafted files) processed via bash are still a risk. – Eliah Kagan Sep 25 '14 at 15:41
  • @somelooser28533 The caller needn't be bash for `env x='() { :;}; echo vulnerable' bash -c 'echo ...'`, just any [Bourne-style (POSIX) shell](https://en.wikipedia.org/wiki/Unix_shell#Bourne_shell_compatible) or some other shell that accepts `VARIABLE=value` command syntax. With `env`, the shell could be just about anything, which may be why [the test BadSkillz quotes](http://security.stackexchange.com/a/68169) uses it. `sh -c "env x='() { :;}; echo vulnerable' bash -c 'echo ...'"`, whether or not sh is bash, also works. Even in a non – Bourne-style shell, you don't need both `env` and `sh -c`. – Eliah Kagan Sep 25 '14 at 15:51
  • @EliahKagan I see the risk for servers under certain conditions, but if you look at Mac user forums—for example—there is this absolute panic that Mac OS X on a client level is at risk. And I honestly don’t see that. But appreciate your POV. – Giacomo1968 Sep 25 '14 at 15:59
  • @EliahKagan `“It's true sh is only sometimes bash.”` No, it is not a “sometimes” issue. `bash` is bash and `sh` is the standard Unix shell. If you do not understand that incredibly simple fact you really should not be advising anyone o security issues. – Giacomo1968 Sep 25 '14 at 16:38
  • 10
    @JakeGould There's no one program that's "the standard Unix shell." Different OSes uses different shells for `/bin/sh`. On GNU/Linux `sh` is usually a link to, or copy of, some other shell. [In Ubuntu and Debian, `dash` provides `sh`, though `bash` did in years past.](https://wiki.ubuntu.com/DashAsBinSh) On some OSes, `sh` remains `bash`. (I believe Slackware is an example, though I haven't used it recently.) A quick web search, [or Wikipedia](https://en.wikipedia.org/wiki/Bourne_shell#Usage), would have saved you from your misconception and saved me from your false accusation of ignorance. – Eliah Kagan Sep 25 '14 at 17:12
  • @EliahKagan I stand corrected. But `dash` is simply not `bash` and I honestly think the panic around “shellshock” will cause more problems than the exploit itself. – Giacomo1968 Sep 25 '14 at 17:14
  • I just patched my server and now I get the error after running the command above. Does this mean that I am still vulnerable to CVE-2014-7169 which claims the fix for 6271 shell shock is incomplete? – user53029 Sep 25 '14 at 19:04
  • 6
    @user53029 The released fix for CVE-2014-6271 doesn't fix the underlying design flaw that makes it so bash must parse function definitions from the environment *just right* or suffer potential security bugs. In that sense the fix is incomplete. But it does (as far as is known) completely fix the bug of executing trailing code after a function definition. So it largely makes sense to consider CVE-2014-7169 a separate vulnerability. **The patch for 6271 and the test in this answer for determining if that patch is effectively applied do not test for 7169.** I've expanded this answer with details. – Eliah Kagan Sep 25 '14 at 20:07
  • 1
    @Eliah Kagan -So to get an idea of the degree of security that has been mitigated with the patch, what can an attacker do while exploiting the bug in 7169 that he could no longer do on a 6271 patched system? – user53029 Sep 25 '14 at 21:07
  • @user53029 Exactly. A tree is fixed. But is the forest in any true practical danger? – Giacomo1968 Sep 25 '14 at 21:26
  • Suggestion for a small improvement. If you prefix the test command with `env` it'll work from csh/tcsh as well. – arielf Sep 27 '14 at 08:43
  • I use mac os x, and it shows up as vulnerable -- but there is nothing I can do about it for the time being, right? – Andreas Bonini Sep 27 '14 at 10:09
  • 2
    With the last patch (which avoids `eval`s on random environment variables) the original test should do fine, printing _nothing_ on a completely patched system. – Matteo Italia Sep 29 '14 at 08:01
  • I do not get anything when I type this – Trect Nov 26 '18 at 17:17
12

You can check if you're vulnerable by running the following lines in your default shell, which on many systems will be Bash. If you see the words "busted", then you're at risk. If only the second command prints “busted”, then your bash is vulnerable, but the vulnerability only impacts the parts of your system that invoke bash explicitly, not the parts that run the default shell (sh). If neither command prints “busted” then your system is patched.

env X="() { :;} ; echo busted" /bin/sh -c "echo completed"
env X="() { :;} ; echo busted" bash -c "echo completed"

Source

After patching, your system may still be vulnerable:

env X='() { (a)=>\' bash -c "echo echo vuln"; [[ "$(cat echo)" == "vuln" ]] && echo "still vulnerable :("

Source and another source

BadSkillz
  • 4,444
  • 25
  • 29
  • 3
    I'm not sure what `\`which bash\`` is supposed to accomplish that `bash` wouldn't: both run whichever `bash` appears first in `PATH`, and it's not as though `env` needs fully qualified names. (Also, you don't need `env` at all for this.) – Eliah Kagan Sep 25 '14 at 12:41
  • 1
    @BadSkillz, can you add some clarification to `env X='() { (a)=>\' sh -c "echo date"; cat echo`? What is that supposed to do or show me? – the Sep 25 '14 at 13:18
  • 1
    @Eliah, it'd be great if you can come up with a better answer. – the Sep 25 '14 at 13:18
  • `which bash` might get you past a sanitized input restricting shell command path literals. – zedman9991 Sep 25 '14 at 13:19
  • @KasperSouren, I think it just demonstrates a bug in bash function parsing as mentioned [here](https://twitter.com/taviso/status/514910129557610496)... so this is no valid bash syntax. – 0x80 Sep 25 '14 at 13:30
  • Does X remain in my environment forever? what if I already have a environment variable called X? – Nzall Sep 25 '14 at 14:33
  • @NateKerkhofs No, it won't remain, and you can use another variable if you like – BadSkillz Sep 25 '14 at 14:38
  • @NateKerkhofs Environment variables are per-process. `VAR=value some-command` (or `env VAR=value some-command`) runs `some-command` with `VAR` set to `value` in *its* environment. The `x` belonging to the shell in which you run that command [is itself unaffected](http://paste.ubuntu.com/8425978/), even though [the variable is set in the child process's environment](http://paste.ubuntu.com/8425989/). Anyway, even if you did set it for the current shell's environment, as BadSkillz says it would be nonpersistent and cause no harm, and you can choose a different variable name if you want to. – Eliah Kagan Sep 25 '14 at 14:57
  • Is `which` safe? What's to stop: `export which='() { echo /bin/bash;}`? (A complete one would test the argument). Bash executes functions before built-ins. You could also doctor `declare -f` and `env` in a similar way to hide the functions. – cdarke Sep 26 '14 at 05:15
11

If you need a method to check several servers at once that are on the same subnet, you can use Masscan to send a request to all of them: https://github.com/robertdavidgraham/masscan

An example configuration file can be found at http://blog.erratasec.com/2014/09/bash-shellshock-scan-of-internet.html:

target = 0.0.0.0/0 //CHANGE THIS TO THE PROPER SUBNET
port = 80
banners = true
http-user-agent = shellshock-scan (http://blog.erratasec.com/2014/09/bash-shellshock-scan-of-internet.html)
http-header[Cookie] = () { :; }; ping -c 3 209.126.230.74
http-header[Host] = () { :; }; ping -c 3 209.126.230.74
http-header[Referer] = () { :; }; ping -c 3 209.126.230.74
//change the above 3 Ip addresses to the IP of the machine you send it from.

The machines that are vulnerable will send you a ping back. According to the followup blogpost by the author, there might be some configuration required.

Nzall
  • 7,373
  • 6
  • 30
  • 45
  • How can I check just one server? – CharlesB Sep 26 '14 at 10:30
  • @CharlesB just remotely connect to the server and execute one of the oneliners on this page. or enter the full IP of the server with subnetmask /32. – Nzall Sep 26 '14 at 10:45
  • Thanks; couldn't edit it, but it must be `target-ip` instead of `target`. If I test my router, the ping command isn't detectable... Is there another command to prove that exploit – CharlesB Sep 26 '14 at 10:57
  • SSH into the router and do what Eliah Khan recommends in his answer. You need to do this directly through the router terminal. – Nzall Sep 26 '14 at 11:06
  • I have no SSH access to it, it's a closed box from our ISP. So no way to check it? – CharlesB Sep 26 '14 at 11:40
  • If it is a closed box, what are you going to do when it turns out the exploit is active? I doubt you'll be able to fix it, since you can't upgrade Bash. – Nzall Sep 26 '14 at 12:43
  • Sure I won't be able to fix it, but it's just for knowing, and asking my ISP about it. – CharlesB Sep 26 '14 at 12:51
0

You can try ShellShocker, which is a CLI utility which can check a CGI script as so:

python shellshocker.py http://example.com/cgi-bin/possibly-vulnerable-cgi.cgi
0

You can check your server submitting a CGI URL to the following online test:

http://shellshock.iecra.org

Roger
  • 1
0

I wrote a quick test which either prints "vulnerable" or "not vulnerable":

env x='() { :;}; echo vulnerable; exit;' bash -c 'echo not vulnerable' 2>/dev/null

It also returns with an exit code of 2 if your version of bash is vulnerable, if you want to use it as part of a script.

colevk
  • 101
  • Tested with versions `3.2.51(1)-release (x86_64-apple-darwin13)` and `3.2.53(1)-release (x86_64-apple-darwin13)`. – colevk Sep 27 '14 at 00:12