Aside from CGI, one overlooked use of
sh is in
exec() calls, or through the use of
popen(), on most Linux systems this means
exec() family of calls are often used with "
/bin/sh -c" to provide various features like shell redirection, pipelines or even just argument expansion when invoking processes.
Apache uses exactly this (via APR, see the use of
apr/threadproc/unix/proc.c) when you use piped logs, and also in other circumstances such as external output filters (via
ExtFilterDefine), and processing of
#exec cmd SSI includes. This behaviour almost certainly applies to many third party modules too.
The best steps to take to secure your web server:
- patch or upgrade your bash package (if you do this yourself make sure there are no stray
sh instances, check for
sh in any manually set up chroots too)
run Apache in a chroot, use a minimal
/bin/sh if and only if it is required:
- in Apache httpd 2.2 switch from using "
|" to "
||" in piped logs, this removes the need for
/bin/sh (available since Apache 2.2.12)
- in Apache httpd 2.4 make sure you're not using "
|$" in piped logs, this reverts to the httpd.2.2 behaviour. 2.4 supports
||, neither use
make sure the default CGI scripts are disabled, double check from the top-level
<Directory /> down for
mod_security if you're not already using it. Red Hat have provided some rules which can be used to log and clean up the environment in KB article 1212303.
You may also consider using "
#!/bin/sh -p" in scripts, this forces bash into privileged mode, this prevents importing functions from the environment (along with other changes). This might help if you have vulnerable CGI scripts on a system, but no patch and no compiler. This might not work on Debian and derived systems, so check carefully.
bash, don't blindly replace it with something else, it might affect your startup scripts.)
Any application code that runs via CGI (other than bash scripts), or under Apache modules (Python and PHP in your case) may also play a part in this. If any variable can be sufficiently controlled by an attacker (URI-encoding may be a challenge), and if the application uses
/bin/sh when invoking processes, and if those variables are preserved while doing so, then you might have a problem.
If you are running a contemporary Linux system, but you have not set up a chroot or some other container for apache, you should be able to use
unshare and a bind mount to replace
/bin/sh when starting Apache (or any other service).
unshare -m -- sh -c "mount --bind /usr/local/bin/bash /bin/sh &&
The advantages to this are
- less risk of breaking things, since you can selectively replace
- you can log and audit attempts to invoke
sh more easily
(What you cannot easily do with this is write a bash script as a wrapper to inspect and log suspicious variables, you'll need to use something else of course...)
If you're running
auditd on Linux, you can easily watch the use of
/bin/sh by adding a couple of rules to
audit.rules and reloading:
-w /bin/sh -p x
-w /bin/bash -p x
(I need both, since
sh is a symlink to
Red Hat have published an alternate approach, a runtime "fix" which you can use with
LD_PRELOAD, you can find that in the advisory. This could also be adapted to log dubious variables, if required. Given that there are currently questions over the completeness of the patches so far, this solution is probably a good short-term fix for Apache at least.
You can also find more general Apache hardening tips here: Apache Server Hardening