edit: Yes, this feature works when formatted correctly for zsh as "function ls () { echo vulnerable }". However, I was wrong in that zsh -c will not run the function (of course running "ls" in the same session will). I'm going to call this not a problem.
edit: When trying this one-liner in zsh: "env x='() { :;}; echo vulnerable' zsh -c 'echo hello'" (as suggested by https://superuser.com/questions/816622/does-the-shellshock-b...), the output indicates my shell is vulnerable. Could someone please try and replicate?
This is how you define a shell function and then use it in sub-scripts.
As the author noted, using this as an exploit requires control of the variable names, and common tools (httpd, dhclient, etc) that set variables in environment have explicit naming conventions in place to prevent this.
To be clear: I'll change my tune if someone finds a way to exploit this remotely.
I don't see how this qualifies as much of a vulnerability. Maybe now that bash's imported-function feature is better known we'll see it leveraged as part of a multi-step attack though.
Do you mean that you run bash -c in zsh, or that you run zsh -c ?
[RHEL-6.5 tmp]$ uname -a
Linux hostname1 2.6.32-431.23.3.el6.x86_64 #1 SMP Wed Jul 16 06:12:23 EDT 2014 x86_64 x86_64 x86_64 GNU/Linux
[RHEL-6.5 tmp]$ bash --version
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
[RHEL-6.5 tmp]$ ls
file1 file2 file3
[RHEL-6.5 tmp]$ env ls='() { echo vulnerable; }' bash -c ls
file1 file2 file3
Linux hostname2 3.8.0-44-generic #66~precise1-Ubuntu SMP Tue Jul 15 04:01:04 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
Ubuntu 12.04:~/tmp$ bash --version
GNU bash, version 4.2.25(1)-release (x86_64-pc-linux-gnu)
Ubuntu 12.04:~/tmp$ ls
file1 file2 file3
Ubuntu 12.04:~/tmp$ env ls='() { echo vulnerable; }' bash -c ls
vulnerable
Is this a basic difference in the feature sets of Bash 4.1 and Bash 4.2? Like several posters, I was unaware of this feature and have certainly never used it. Perhaps it should be off by defaults? How big of a mess would that make? I would also like to see more distributions use something other than bash as /bin/sh, but that's another discussion, I guess. s/vulnerable/working/
Fixed that for you. :)EDIT: I tested on CentOS 6.5 and Fedora 18 (for which we'd manually backported the Fedora 19 patches).
env ls='() { echo vulnerable; }' bash -c ls
on my recently patched CentOS box. If I'm reading that right, if I was vulnerable, I'd get the output 'vulnerable'? But, instead, I got the correct output of the `ls` command.
The linked article was pertinent because RedHat did patch bash in a different way than upstream. Here's the relevant quote:
> Our patch addresses the CVE-2014-7169 issue in a much better way than the upstream patch, we wanted to make sure the issue was properly dealt with.
That help?
$ env 'BASH_FUNC_ls()=() { echo myls; }' bash -c ls
myls
But as others mention, this is not really a bash issue anymore, rather a general problem of sanitizing environments.The post's proposed exploit path is not possible on Linux and most OS's, because you cannot have a setuid script.[1]
[1] http://unix.stackexchange.com/questions/364/allow-setuid-on-...
However the fact that the script isn't setuid isn't really the concern for these shellshock, since a setuid program could indirectly run /bin/sh.
Again, though, this doesn't seem to another shellshock problem. In shellshock you only needed to control the value of an environment variable, not its name. If you can control the name and the value then there are plenty of other ways you can attack programs.
A setuid program which runs any child process without having first cleared the environment or authenticated the caller for root access is already broken by means of LD_PRELOAD.
Not a vulnerability.
There is some misunderstanding though regarding the suid shell script. I can't think of any modern unix other than solaris that allows those by default any more. It's just not a concern anymore unless an admin twiddles some sysctl or what not. And in the case of solaris /bin/sh is not bash. Also /bin/sh does it's own setuid after comparing to 100 (unless the -p option is passed) so often if people are not adding users to a group or sudo, they would create a ksh or perl script instead. Anyway that's just rambling, sorry, the short answer is that I would be really surprised if there was any modern system that used bash as /bin/sh and also allowed suid interpreter scripts.
My thinking is that at this point the whole exporting functions (and anything else other that environment variables, like arrays) is just a bad idea in the default case. I actually do do it, but for a stupid reason and can totally see how I should just put those functions in bashrc for the same effect anyway.
So I really would like to see that all disabled by default in bash and a shellopt added to enable it if anyone really needed it.
I've heard about other ideas like prefix, suffix the name, or add a BASH_FOOBARBAZ that lists exported functions, but it's just not something most people do, and it would be a pita for the people that do need it now needing to change how they do it cause I can totally see people that made use of this having done it in C and perl knowing that if they did added to ENV 'cat=() { ...' or what not it would change what they needed in the subshell after they called system. That would really be annoying for those people to have all that break in a way they would need to change all that baroque code instead of just adding an option, something like system("exec /bin/bash --foobarbaz ... ") now.
Plus there are other programs like sudo that already know how to deal with the '() {' style env vars and clear them-out by default, people would have to update all those (plus what ever ancient suid C launcher programs they already had doing this kind of env var clean-up in their own broken ways from before the time sudo became the way to do this stuff) now too.
It's the second half of the security fix, so I recommend upgrading.
There is a small potential for breakage as you mention, but less than ripping the feature entirely out.
Which languages would those be? There are a few languages with a concept of "taint" (Perl, Ruby), but I've never actually seen a language where everywhere untrusted input could come from actually starts tainted, and every secure function actually disallows tainted input. Especially where third-party-native-FFI library calls are involved.
The problem here, as anon1385 pointed out is that shells in general, and Bash in particular, were designed to execute things and maintained at best weak separation between code and data – in no small part because the concept originated 40 years ago when computing was a much more trusted place and network connections were rare and not seen as a conduit for never-ending attacks. As a class, makes shells a bad idea for anything which crosses a privilege boundary; almost any normal language would avoid this particular exploit.
Shells are designed primarily as human interfaces. They try quite hard to execute data they receive, because when used interactively that is what you want. Passing around data that you don't want to be executed involves a lot of careful escaping because everything is done in-band. That's why the history of shell scripting contains countless examples of people accidentally executing file names, abuse of control characters and things like that.
That's not the "shock" part of "shellshock"; that's a long known issue. Applications which pass arbitrary variables from the network through environment variables already add a unique prefix to the variables, to prevent this kind of problem. That unique prefix also prevents them from accidentally conflicting with the name of an actual executable for this case.
Now, there are still going to be bugs with suid executables not sanitizing their environment, but those apply in many other ways, such as via PATH and LD_PRELOAD.
The "shock" part of shellshock was that it was possible to execute arbitrary code, upon just loading a variable in Bash, regardless of what its name was, depending only on the contents, which in many cases can be attacker controlled.
Forget bash. LD_PRELOAD by design lets you load arbitrary code into any child process. Many other environment variables affect libc and other common libraries in arbitrary ways. setuid programs must clear their environment at startup to be safe. Programs like sudo can restore that environment once the user is authorized for root access.
Christos Zoulas from NetBsd has the arguments that I really like: it's a "feature" that was widely unknown and that should be disabled by default: