A remotely exploitable hole in bash
From: | Florian Weimer <fw-d32yF4oPJVt0XxTmqZlbVQ-AT-public.gmane.org> | |
To: | oss-security-ZwoEplunGu1jrUoiu81ncdBPR1lH4CV8-AT-public.gmane.org | |
Subject: | Re: CVE-2014-6271: remote code execution through bash | |
Date: | Wed, 24 Sep 2014 17:03:19 +0200 | |
Message-ID: | <87d2alf4co.fsf@mid.deneb.enyo.de> |
* Florian Weimer: > Chet Ramey, the GNU bash upstream maintainer, will soon release > official upstream patches. http://ftp.gnu.org/pub/gnu/bash/bash-3.0-patches/bash30-017 http://ftp.gnu.org/pub/gnu/bash/bash-3.1-patches/bash31-018 http://ftp.gnu.org/pub/gnu/bash/bash-3.2-patches/bash32-052 http://ftp.gnu.org/pub/gnu/bash/bash-4.0-patches/bash40-039 http://ftp.gnu.org/pub/gnu/bash/bash-4.1-patches/bash41-012 http://ftp.gnu.org/pub/gnu/bash/bash-4.2-patches/bash42-048 http://ftp.gnu.org/pub/gnu/bash/bash-4.3-patches/bash43-025 Someone has posted large parts of the prenotification as a news article, so in the interest of full disclosure, here is what we wrote to the non-vendors (vendors also received patches): Debian and other GNU/Linux vendors plan to disclose a critical, remotely exploitable security vulnerability in bash this week, related to the processing of environment variables. Stephane Chazelas discovered it, and CVE-2014-6271 has been assigned to it. The issue is currently under embargo (not public), and you receive this message as a courtesy notification because we assume that you have network-based filtering capabilities, so that you can work on ways to protect a significant number of customers. However, you should not yet distribute IPS/IDS signatures, publicly or to customers. At present, public disclosure is scheduled for Wednesday, 2014-09-24 14:00 UTC. We do not expect the schedule to change, but we may be forced to revise it. The technical details of the vulnerability follow. Bash supports exporting not just shell variables, but also shell functions to other bash instances, via the process environment to (indirect) child processes. Current bash versions use an environment variable named by the function name, and a function definition starting with “() {” in the variable value to propagate function definitions through the environment. The vulnerability occurs because bash does not stop after processing the function definition; it continues to parse and execute shell commands following the function definition. For example, an environment variable setting of VAR=() { ignored; }; /bin/id will execute /bin/id when the environment is imported into the bash process. (The process is in a slightly undefined state at this point. The PATH variable may not have been set up yet, and bash could crash after executing /bin/id, but the damage has already happened at this point.) The fact that an environment variable with an arbitrary name can be used as a carrier for a malicious function definition containing trailing commands makes this vulnerability particularly severe; it enables network-based exploitation. So far, HTTP requests to CGI scripts have been identified as the major attack vector. A typical HTTP request looks like this: GET /path?query-param-name=query-param-value HTTP/1.1 Host: www.example.com Custom: custom-header-value The CGI specification maps all parts to environment variables. With Apache httpd, the magic string “() {” can appear in these places: * Host (“www.example.com”, as REMOTE_HOST) * Header value (“custom-header-value”, as HTTP_CUSTOM in this example) * Server protocol (“HTTP/1.1”, as SERVER_PROTOCOL) The user name embedded in an Authorization header could be a vector as well, but the corresponding REMOTE_USER variable is only set if the user name corresponds to a known account according to the authentication configuration, and a configuration which accepts the magic string appears somewhat unlikely. In addition, with other CGI implementations, the request method (“GET”), path (“/path”) and query string (“query-param-name=query-param-value”) may be vectors, and it is conceivable for “query-param-value” as well, and perhaps even “query-param-name”. The other vector is OpenSSH, either through AcceptEnv variables, TERM or SSH_ORIGINAL_COMMAND. Other vectors involving different environment variable set by additional programs are expected. Again, please do not disclose this issue to customers or the general public until the embargo has expired.
Posted Sep 24, 2014 20:41 UTC (Wed)
by corsac (subscriber, #49696)
[Link] (2 responses)
Posted Sep 24, 2014 22:14 UTC (Wed)
by riking (subscriber, #95706)
[Link]
Wed, 24 Sep 2014 17:03:19 +0200
17:03:19 - 0200 = 15:03:19 is after 14:00
Posted Sep 24, 2014 22:58 UTC (Wed)
by mjw (subscriber, #16740)
[Link]
Posted Sep 24, 2014 23:11 UTC (Wed)
by cesarb (subscriber, #6266)
[Link]
It mentions several possible exploitation contexts, including DHCP clients (update bash on your laptop before leaving home!).
Posted Sep 24, 2014 23:37 UTC (Wed)
by Trelane (subscriber, #56877)
[Link] (1 responses)
Posted Sep 25, 2014 7:13 UTC (Thu)
by tititou (subscriber, #75162)
[Link]
Posted Sep 25, 2014 0:53 UTC (Thu)
by luto (guest, #39314)
[Link] (2 responses)
[1] http://article.gmane.org/gmane.comp.security.oss.general/...
Posted Sep 25, 2014 9:21 UTC (Thu)
by osma (subscriber, #6912)
[Link]
http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-...
Posted Sep 25, 2014 18:55 UTC (Thu)
by proski (subscriber, #104)
[Link]
Posted Sep 25, 2014 6:55 UTC (Thu)
by Karellen (subscriber, #67644)
[Link] (9 responses)
If it's perl, python, or a compiled binary, Apache should set the up the environment and then exec(3) your script directly, yes? The kernel will then decide to start executing perl/python/your ELF binary, based on its magic number file header, yes? It doesn't do the equivalent of "bash -c 'yourscript'" instead, injecting bash into every CGI call?
Posted Sep 25, 2014 8:03 UTC (Thu)
by intgr (subscriber, #39733)
[Link] (5 responses)
I don't know whether Apache does or not, but invoking other programs via /bin/sh is pretty common; for example, git does it as well when using SSH: env TERM='() { :;}; echo vulnerable' git pull
That's why this vulnerability is so scary, there are so many ways to influence environment variables and so many places that invoke /bin/sh, it's hard to tell for sure if it's exploitable in your applications or not.
Posted Sep 25, 2014 9:26 UTC (Thu)
by eru (subscriber, #2753)
[Link] (4 responses)
Anything that calls system(3) is!
Posted Sep 25, 2014 9:46 UTC (Thu)
by job (guest, #670)
[Link] (3 responses)
Anything that puts externally supplied data in the environment, and then calls system(3). Which are probably quite a few things, such as vpn clients and dhcp clients, but I don't expect it to be anything on the scale of Heartbleed.
Posted Sep 25, 2014 10:28 UTC (Thu)
by eru (subscriber, #2753)
[Link] (2 responses)
Posted Sep 25, 2014 12:13 UTC (Thu)
by job (guest, #670)
[Link] (1 responses)
Posted Sep 25, 2014 16:25 UTC (Thu)
by raven667 (subscriber, #5198)
[Link]
Posted Sep 25, 2014 8:06 UTC (Thu)
by avheimburg (guest, #75272)
[Link]
Posted Sep 25, 2014 9:43 UTC (Thu)
by job (guest, #670)
[Link]
Posted Sep 25, 2014 16:23 UTC (Thu)
by raven667 (subscriber, #5198)
[Link]
No, the way that the httpd passes any variables to the CGI is through the environment, which is inherited across sub-processes, so a CGI in any language that forks a shell due to running system() or `backticks` or implicitly as part of file globbing, even if you are just running a fixed command, is vulnerable.
Posted Sep 25, 2014 10:57 UTC (Thu)
by gb (subscriber, #58328)
[Link] (21 responses)
Posted Sep 25, 2014 11:57 UTC (Thu)
by eru (subscriber, #2753)
[Link] (20 responses)
Posted Sep 25, 2014 14:58 UTC (Thu)
by jem (subscriber, #24231)
[Link] (19 responses)
Posted Sep 25, 2014 15:08 UTC (Thu)
by gb (subscriber, #58328)
[Link]
Posted Sep 25, 2014 15:24 UTC (Thu)
by bronson (subscriber, #4806)
[Link] (17 responses)
Posted Sep 25, 2014 15:28 UTC (Thu)
by thedevil (guest, #32913)
[Link] (16 responses)
If "sounds dangerous" was a reason not to use something, I don't think I'd be typing this now on my computer ...
Posted Sep 25, 2014 15:48 UTC (Thu)
by cortana (subscriber, #24596)
[Link] (1 responses)
Posted Sep 25, 2014 15:57 UTC (Thu)
by cortana (subscriber, #24596)
[Link]
> curl -H 'foo: () { evil; }' http://foo.example/cgi-bin/somebashscript
Now somebashscript has an attacker-supplied shell function, HTTP_foo. I am deeply uncomfortable with the fact that the script is only one typo away from running it. I would prefer this feature to be ripped out entirely, or at least disabled unless a script runs 'shopt -p terrifying_code_injection'.
Posted Sep 25, 2014 15:51 UTC (Thu)
by foom (subscriber, #14868)
[Link] (8 responses)
If one actually WANTS to eval code from an env var, it's trivial to do so, either by setting BASH_ENV to point to a file you want run, or by starting your subscript with a call to 'eval "$BASH_EVAL_ME_FIRST"'. There's no need for it to be part of bash at all.
I'd really vote for simply killing this misguided "export -f" feature entirely.
But if not, the best way to implement this feature is probably to have bash itself call 'eval "$BASH_EVAL_ME_FIRST"' at startup, and have "export -f" simply append all exported functions into a shell script fragment in that one variable.
Then at least it's clear that allowing that variable to be set allows arbitrary code execution (like BASH_ENV being set to a filename does). Don't need to worry about parser vulnerabilities, or potentially overriding existing functions/binaries.
And it's unlikely that remote users will be able to set such a varible.
Posted Sep 25, 2014 16:21 UTC (Thu)
by gb (subscriber, #58328)
[Link] (7 responses)
$ export A='() { echo "My func"; }'
Thus make me think that way of the storage is implementation detail and it _may be_ backdoor since day 1 15 years ago.
Posted Sep 25, 2014 17:43 UTC (Thu)
by gb (subscriber, #58328)
[Link] (5 responses)
$ cat /proc/$$/environ |xargs -0 -n1|grep -w A
$ env|grep -w A
Means that if someone sets such function in HTTP or something.. you would never see it if you just do $ABCD, only if you do env|grep ABCD
Posted Sep 25, 2014 17:52 UTC (Thu)
by gb (subscriber, #58328)
[Link] (2 responses)
Posted Sep 25, 2014 18:15 UTC (Thu)
by madscientist (subscriber, #16861)
[Link] (1 responses)
The typical functional API to the environment provided by C and other languages treats the environment as a set of key/value pairs, so using those functions it's usually not possible to have two variables with the same name. But, if you start a program with execve() for example you give your own list of strings as the environment for the child process, and the members of that list can be whatever you want.
Posted Sep 25, 2014 20:31 UTC (Thu)
by gb (subscriber, #58328)
[Link]
Posted Sep 26, 2014 11:05 UTC (Fri)
by marcH (subscriber, #57642)
[Link] (1 responses)
Just found this in the standard:
http://pubs.opengroup.org/onlinepubs/7908799/xbd/envvar.html
"If more than one string in a process' environment has the same name the consequences are undefined."
Posted Sep 26, 2014 14:15 UTC (Fri)
by gb (subscriber, #58328)
[Link]
Posted Sep 29, 2014 10:34 UTC (Mon)
by nye (subscriber, #51576)
[Link]
$type A
>Thus make me think that way of the storage is implementation detail
Almost certainly. This behaviour looks exactly like if the function had been defined in the subshell in the traditional way - functions aren't variables, so variable substitution isn't a meaningful thing to do, but 'type' knows exactly what's up, and so does 'set'.
The implementation leaks slightly though, in that the definition is visible in the environment unlike a locally defined function.
Posted Sep 26, 2014 16:32 UTC (Fri)
by bronson (subscriber, #4806)
[Link] (4 responses)
http://seclists.org/oss-sec/2014/q3/741
I don't see any way the benefit of the feature can outweigh all this effort.
Posted Sep 26, 2014 16:59 UTC (Fri)
by raven667 (subscriber, #5198)
[Link] (3 responses)
This is an instance of what is a hard and fast rule in the kernel, "Don't Break Userspace(tm)" It doesn't matter how dumb the feature is in retrospect, it has to continue working even after you refactor the implementation, someone out there could be depending on it, probably without even being aware of it.
Posted Sep 27, 2014 23:28 UTC (Sat)
by bronson (subscriber, #4806)
[Link] (2 responses)
Posted Sep 28, 2014 4:25 UTC (Sun)
by raven667 (subscriber, #5198)
[Link] (1 responses)
Posted Sep 28, 2014 7:25 UTC (Sun)
by bronson (subscriber, #4806)
[Link]
Linux's backward compatibility is nothing short of stellar. It's part of what makes using Linux such a pleasure. But, on the rare occasion that a mistake is made, we don't have to live with it forever. It can be fixed.
Posted Sep 26, 2014 8:46 UTC (Fri)
by sitaram (guest, #5959)
[Link] (5 responses)
Posted Sep 26, 2014 16:35 UTC (Fri)
by cesarb (subscriber, #6266)
[Link] (1 responses)
So it should probably be (untested): /^\(\) \{/.
Posted Sep 26, 2014 23:04 UTC (Fri)
by sitaram (guest, #5959)
[Link]
Posted Sep 29, 2014 11:08 UTC (Mon)
by k8to (guest, #15413)
[Link] (2 responses)
Posted Sep 29, 2014 17:05 UTC (Mon)
by mathstuf (subscriber, #69389)
[Link] (1 responses)
FTFY :) . Apparently some implementations just unset the first instance of the variable in the environment, not all of them.
Posted Oct 5, 2014 4:39 UTC (Sun)
by k8to (guest, #15413)
[Link]
Posted Sep 26, 2014 11:30 UTC (Fri)
by marcH (subscriber, #57642)
[Link] (12 responses)
So, they were drunk.
Security rule number 1: sanitize your inputs. CGI's interpretation: let's dump all this random and unfiltered input into the highly sensitive process environment.
Like most accidents this is not caused by just one mistake but a combination of them. I'm still not convinced bash is the most to blame. People running bash scripts through CGI should definitely blamed too.
Posted Sep 26, 2014 11:41 UTC (Fri)
by niner (subscriber, #26151)
[Link] (11 responses)
Posted Sep 26, 2014 15:08 UTC (Fri)
by marcH (subscriber, #57642)
[Link] (10 responses)
Posted Sep 26, 2014 17:03 UTC (Fri)
by raven667 (subscriber, #5198)
[Link] (7 responses)
Posted Sep 26, 2014 17:36 UTC (Fri)
by marcH (subscriber, #57642)
[Link] (6 responses)
I think it all comes down to this: when CGI was invented (20 years ago already?!) had people generally realized that some people on the Internet were not going to be nice? This is a genuine question.
(Answering it might reveal your age, sorry)
> but it's harder to say that given the constraints of the system and the knowledge of the time that you wouldn't have made the same decisions given the same inputs.
Based on the beat... feedback I usually get to "get it done" I could still be reasonably optimistic :-)
More revelant: why the hell is CGI still in use in the same sorry state 20 years and a millions of (not related) security scandals later? OK: now I guess I just need to google "Worse is Better" and do some reading.
Posted Sep 26, 2014 18:06 UTC (Fri)
by mpr22 (subscriber, #60784)
[Link]
Posted Sep 26, 2014 21:00 UTC (Fri)
by raven667 (subscriber, #5198)
[Link]
That viewpoint was out there but wasn't a widely heeded, what we consider normal security engineering today would be considered high paranoia at the time. Packet-filtering firewalls were a new technology at the time and adding DMZs to networks was a radical new thing that people argued about. Having open SMTP relays was considered good form as well 8-)
> feedback I usually get to "get it done"
Yep.
Also passing data in environment variables is a very UNIX-y way to do things which was dominant at the time.
Posted Sep 28, 2014 14:29 UTC (Sun)
by kleptog (subscriber, #1183)
[Link] (3 responses)
Offhand I can't think of any other case of something being executed out of an environment variable. Most programs just look at the variables they're interested in and ignore the rest. What bash is doing here (looping over variables to find those whose *value* match a particular pattern) is I think pretty rare.
There is no other interface that is anywhere near as easy to use. Stuff like FastCGI has traction in certain areas, but it's already much more complicated.
Posted Sep 28, 2014 16:09 UTC (Sun)
by marcH (subscriber, #57642)
[Link] (1 responses)
There is no doubt that insecure is always more convenient, actually most of the time insecure is *much* more convenient. The question was: how many more security scandals are required before secure coding starts being seriously rewarded and laziness punished by the market place? No simple answer I'm afraid.
> Offhand I can't think of any other case of something being executed out of an environment variable. Most programs just look at the variables they're interested in and ignore the rest.
"Most" does not work a security perspective. All details here:
Posted Sep 29, 2014 10:55 UTC (Mon)
by nye (subscriber, #51576)
[Link]
Imagine the alternative: that there is no standardised way to pass variables across processes and every program needs to implement its own custom parser. That would be a nightmare, and you'd be making pretty much the same complaint, probably suggesting that the only sensible thing to do is to have it done exactly as it is now, so that the parsing is implemented in one shared implementation.
You're a very judgemental person, but in the real world it's likely that anyone reading code you've written would be bitching just as much about your scandalous laziness.
Posted Sep 28, 2014 18:29 UTC (Sun)
by mathstuf (subscriber, #69389)
[Link]
I've found using spawn-fcgi works really nicely for keeping CGI services in a separate jail from the webserver itself. So you can write your CGI program then just use the wrapper.
Posted Sep 26, 2014 21:24 UTC (Fri)
by foom (subscriber, #14868)
[Link] (1 responses)
It is not "drunk" to expect that passing arbitrary values in controlled names is a perfectly reasonable thing to do.
I mean, same issue occurs with SSH -- it sets SSH_ORIGINAL_COMMAND to the command that the remote user presented to a restricted command. How could that be insecure?
*Clearly* nothing would be trying to eval that as code! That'd be insane!
Posted Sep 26, 2014 23:51 UTC (Fri)
by marcH (subscriber, #57642)
[Link]
A remotely exploitable hole in bash
A remotely exploitable hole in bash
vs
Wednesday, 2014-09-24 14:00 UTC
A remotely exploitable hole in bash
A remotely exploitable hole in bash
A remotely exploitable hole in bash
A remotely exploitable hole in bash
A remotely exploitable hole in bash
A remotely exploitable hole in bash
I would not say the patch for the original issue is buggy. It's a separate issue that requires a separate patch. The new issue doesn't involve passing functions through the environment. It is the parser recovery after invalid function definitions.
A remotely exploitable hole in bash
A remotely exploitable hole in bash
A remotely exploitable hole in bash
it's hard to tell for sure if it's exploitable in your applications or not.
A remotely exploitable hole in bash
localhost:.../~$ gcc bug.c
localhost:.../~$ env TERM='() { :;}; echo vulnerable' a.out
vulnerable
#include <stdlib.h>
int main(void)
{
return system("cat bug.c");
}
A remotely exploitable hole in bash
But suppose a program that is not itself vulnerable receives "infected" environment variables and then execs a program that eventually calls system()?
A remotely exploitable hole in bash
A remotely exploitable hole in bash
A remotely exploitable hole in bash
A remotely exploitable hole in bash
A remotely exploitable hole in bash
A remotely exploitable hole in bash
A remotely exploitable hole in bash
Other popular shells do not have the feature, so removing it would affect only very bash-specific scripts.
A remotely exploitable hole in bash
The bug is not the feature itself, but in the implementation of it. Disabling the feature can only be done by patching bash, so why not fix the real bug instead?
A remotely exploitable hole in bash
A remotely exploitable hole in bash
A remotely exploitable hole in bash
A remotely exploitable hole in bash
A remotely exploitable hole in bash
A remotely exploitable hole in bash
A remotely exploitable hole in bash
A remotely exploitable hole in bash
$ bash
$ A
My func
$ echo $A
[nothing here]
$ bash
$ A
My func [still???]
$ export A=3
$ bash
$ A
My func
$ echo $A
3
And how does bash passed both A and My func to subshell here?
A remotely exploitable hole in bash
A=() { echo "My func"
A=3
A=() { echo "My func"
A remotely exploitable hole in bash
A remotely exploitable hole in bash
A remotely exploitable hole in bash
A remotely exploitable hole in bash
A remotely exploitable hole in bash
$ bash
$ f() { aaa; }
$ export -f f
$ export f=3
$ ksh
$ cat /proc/$$/environ |xargs -0 -n1|grep -w f
f=3
f=() { aaa
$ echo $f
3
A remotely exploitable hole in bash
>$ bash
>$ A
>My func
>$ echo $A
>[nothing here]
A is a function
A ()
{
echo "My func"
}
A remotely exploitable hole in bash
A remotely exploitable hole in bash
A remotely exploitable hole in bash
A remotely exploitable hole in bash
A remotely exploitable hole in bash
I took David Wheeler's quote to heart and added one more layer of indirection while the big boys figure out what is the correct patch.A remotely exploitable hole in bash
Copy /bin/bash to /bin/oldbash, put this script in as /bin/bash, and fix up permissions:
#!/usr/bin/perl
# env safe bash
use strict;
use warnings;
for (keys %ENV) {
delete $ENV{$_} if $ENV{$_} =~ /^\s*\(\s*\)\s*\{/;
}
exec "/bin/oldbash", @ARGV;
A remotely exploitable hole in bash
A remotely exploitable hole in bash
A remotely exploitable hole in bash
A remotely exploitable hole in bash
A remotely exploitable hole in bash
A remotely exploitable hole in bash
A remotely exploitable hole in bash
A remotely exploitable hole in bash
A remotely exploitable hole in bash
A remotely exploitable hole in bash
Remote exploits were (in principle) already a known thing, since the Morris worm was unleashed in 1988.
A remotely exploitable hole in bash
A remotely exploitable hole in bash
A remotely exploitable hole in bash
A remotely exploitable hole in bash
http://www.dwheeler.com/secure-class/Secure-Programs-HOWT...
A remotely exploitable hole in bash
>There is no doubt that insecure is always more convenient, actually most of the time insecure is *much* more convenient. The question was: how many more security scandals are required before secure coding starts being seriously rewarded and laziness punished by the market place? No simple answer I'm afraid.
A remotely exploitable hole in bash
A remotely exploitable hole in bash
A remotely exploitable hole in bash