3

Given that it is a frequent requirement to allow unprivileged users restricted access to privileged functions: Jobbing sysadmins sometimes provide this in the form of shellscripts, which are then invoked via a setuid wrapper, like so:

int main()
{
   setuid( 0 );
   system( "/path/to/script.sh" );

   return 0;
}

(The evidence for this assertion can be found by searching for setuid script not working on your favourite search engine, or on stack overflow. No, they shouldn't be doing this, but they are. When security advice is too hard, or too obscure, for sysadmins to follow, another solution is needed.)

Note that this may not merely be ignorance. Who would expect that a script containing only this would be dangerous?

#!/bin/bash
kill -HUP $(< /var/run/demonname.pid)

Obviously the intent is to ask demonname to re-read his configuration file. It calls nothing but bash built-ins (so shouldn't use the path), and doesn't consult the environment once. In my opinion, even an experienced sysadmin could be forgiven for thinking that a suidwrapper was OK in this case.

As previously discovered, Shellshock, and (even without it) the Function Import from Environment (FIE) feature of bash, pose privilege escalation vulnerabilities.

Assuming that:

  • such things exist in your installation, and you don't know they do, and
  • you can reliably assume new ones will be created...

Would it be advisable to:

  • dump bash and use something else forever and ever amen?
  • patch bash to rip out FIE altogether (the "nuke from orbit" option)?
  • patch bash to whitelist the full paths of scripts which are allowed to use this feature?
  • patch system and popen to clear the environment by default if running as root? (People shouldn't be using these functions).
  • Mail the admin every time someone calls system as root? Or starts a shellscript as root?
  • or what?

In other words, is FIE used in production for anything other than exploiting systems? If so can we whitelist those uses and forbid it everywhere else? If not can't we just rip the feature out?

  • This particular wrapper is incredibly dangerous. SHELL=/home/user/badprogram /path/to/wrapper --> you're box is mine. – Joshua Oct 3 '14 at 17:38
5

Such setuid wrappers are dangerous regardless of whether the script interpreter is a fixed bash, an unfixed bash, or some other shell. Reason being that script interpreters are impacted by many environment variables. Oft-cited offenders are PATH and IFS. This is the reason why sudo resets the whole environment to sane values (since shell authors are invariably creative, you cannot achieve security with just a blacklist on a few "known dangerous" environment variables; you have to kill the whole lot).

To abuse an overused metaphor, FIE is just the tip of the iceberg, not the actual ice block that rips apart the ship's hull. Environment variables are the issue, because they are a covert, indirect channel that propagates through calls, and may impact functionality in lots of ways (e.g. you could change the behaviour of the memory allocation routines by activating the "debug mode" through environment). For setuid binaries, the kernel clears the worst case (LDPRELOAD) but, really, all environment variables ought to be cleared, with the possible exception of the LC_* variables (for setting locale-dependent behaviour -- and even that is highly debatable).

Of course, patching the kernel to clear the environment whenever a setuid binary is invoked is bound to break things... Even OpenBSD, despite their "all your security belongs to us" stance, have shied away from actually implementing such a drastic change. Instead, they rely on documentation:

Don't trust your environment ! This involves simple things such as your PATH (never use system with an unqualified name, avoid execvp), but also more subtle items such as your locale, timezone, termcap, and so on. Be aware of transitivity: even though you're taking full precautions, programs you call directly won't necessarily. Never use system in privileged programs, build your command line, a controlled environment, and call execve directly. The perlsec man page is a good tutorial on such problems.

  • Shellshock FIE are capable of causing problems in Bash scripts which never refer to _any_ environment variable and never use _anything_ other than Bash intrinsics - because FIE can override the intrinsics, including cd kill. So a script containing this is dangerous: kill -HUP $(< /var/run/demonname.pid) – Ben Oct 3 '14 at 15:43
  • It's not the kernel that clears LD_PRELOAD (or LD_DEBUG, LD_LIBRARY_PATH, GCONV_MODULE_PATH, LOCPATH...), it's the dynamic linker (at least on GNU systems). The kernel has nothing to do with env vars except taking it from the execve system call and put it on the stack of the process. – Stéphane Chazelas Oct 3 '14 at 16:06
  • LOCPATH is cleared by the dynamic linker, but note that LANG/LANGUAGE/LC_* were vulnerable to CVE-2014-0475 in some contexts. Some other variables like DISPLAY, TERM, HOME, TZ, XAUTHORITY may be needed (but after sanitizing) depending on context. – Stéphane Chazelas Oct 3 '14 at 16:10
  • Not using execvp is no excuse for not sanitizing $PATH as whatever you execv (especially scripts) may rely on it for running other commands. – Stéphane Chazelas Oct 3 '14 at 16:18
  • sudo only resets the whole environment when the env_reset setting is on (which is the default). Otherwise, it blacklists some variables (like those that affect many common tools like sh, ksh, bash, python...) and does some sanitizing based on content. – Stéphane Chazelas Oct 3 '14 at 16:20
0

My wrapper looks like so:

int main()
{
   setuid( 0 );
   execve("/path/to/script.sh", "/path/to/script.sh", NULL );

   return 0;
}

Can't shellshock that even if /bin/sh is bash.

  • When PATH is unset, it defaults to something, and that something depends on who does the path look up, and for GNU libc's exec*p for instance, it's :/bin:/usr/bin, so it looks for executables in the current directory first. Luckily, most shells set PATH on startup to something saner if it's not set. But if /path/to/script.sh's interpreter is not one of those, you're screwed. An empty environment can also be unsafe. – Stéphane Chazelas Oct 3 '14 at 18:55
  • The first line of my scripts after shebang is always IFS=' ' and the second line is always PATH=/bin:/usr/bin:/usr/local/bin:/usr/sbin:/sbin. – Joshua Oct 3 '14 at 21:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.