This week's article is on the chrooting of apache. I also recommend reading Brad Marshall's articles
on other aspects of securing apache. If you haven't read any of Brad's articles yet, please take the time to do so; they're super.
Chrooting apache is no easy task and has a tendency to break things. Before we embark on this, we need to first decide whether it is beneficial for you to do so. Some pros and cons are (but most certainly not limited to):
- If apache is ever compromised, the attacker will not have access to the entire file system. Also make sure apache is running as its own unique user/group, and not something that's overly used, such as "nobody." Consider the scenario where a web server is running as nobody (or any other overly used UID/GID) and compromised. The cracker can now access any other processes running as nobody from within the chroot.
- Poorly written CGI scripts that may, for example, allow someone to email your /etc/passwd file will not work.
- The extra libraries you'll need to have in the chroot. Using hardlinks or compiling your binaries statically will help here. Static binaries are also nifty because they eliminate the possibility -- however infinitesimal it may be -- of someone replacing your libc or other shared library with some hostile wrapper lib and having apache run it unknowingly.
- Generally speaking, the more nifty stuff your web server does, the more difficult it will be to not break that functionality. For example, if you use any Perl/CGI, you will need to copy the needed binaries and perl libraries to the appropriate spot within the chroot space.
Have you decided? Yes? Good, lets embark on our mission. Mosey over to Apache's site
and pick up the latest copy, compile, and install it. I'm using the default location of /usr/local
in this paper. Adding gcc -static to CC= in src/Configuration.tmpl
or specifying on the command line will compile apache statically. However, apparently in newer versions of glibc I am unable to get a true statically compiled binary, as shared NSS libraries are called by some libraries that would be compiled statically. If you've compiled statically and encounter problems, this is likely the case. You can still hardlink your libraries if apache is on the same partition.
OK, now we're all compiled and have an apache waiting to be installed. Before we can do that we need to create the chroot structure. I use /usr/local/chroot for all my chrooted services. So, pick a location you're fond of and make a 'chroot' dir. Within the chroot dir, do mkdir -p httpd/usr/local/apache. The httpd is just a directory where I've decided to put apache. We need the /usr/local/apache directories because, from the point of the chroot, we're sitting at / and we need a /usr/local/apache since apache will be expecting to find itself there. Next, make a symbolic link from where apache installs to normally (/usr/local/apache in my case) to the chroot dir (/usr/local/chroot/httpd/usr/local/apache). Ugly, I know. Now make install and then go check and make sure everything installed ok.
Here comes the fun part: we get to muck up apache's start/stop script for chroot! Load /usr/local/apache/bin/apachectl in your favorite editor (as opposed to one you hate, I guess).
- add CHROOTDIR=/usr/local/chroot/httpd under the "start configuration section."
- change PIDFILE=/usr/local/apache/logs/httpd.pid to PIDFILE=$CHROOTDIR/usr/local/apache/logs/httpd.pid
- change HTTPD=/usr/local/apache/bin/httpd to HTTPD="/usr/bin/chroot $CHROOTDIR /usr/local/apache/bin/httpd"
Be sure to check that your chroot binary location is correct.
If you compiled apache to use shared libraries, you need to install them into the chroot directory structure. Use ldd /usr/local/apache/bin/httpd
to find out which libraries are needed. The output will be something similar to:
[/usr/local/chroot(root@ootganootga)948]: ldd /usr/local/apache/bin/httpd
libm.so.6 => /lib/libm.so.6 (0x00129000)
libcrypt.so.1 => /lib/libcrypt.so.1 (0x00146000)
libc.so.6 => /lib/libc.so.6 (0x00173000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x00110000)
Copying the libraries:
cp -a /lib/libm* /usr/local/chroot/httpd/lib
cp -a /lib/libcrypt* /usr/local/chroot/httpd/lib
cp -a /lib/libc-* /lib/libc.so* /usr/local/chroot/httpd/lib
cp -a /lib/ld-* /usr/local/chroot/httpd/lib
You'll also need the following extra libraries for some network functions like resolving. If you're compiling statically, remember to include the resolver libs in your compile.
/lib/libnss_compat* /lib/libnsl* /lib/libnss_dns* /lib/libresolv* /lib/libnss_files*
We now need to make /etc inside the chroot for a few files like passwd and group. The concept here is similar to how ftpd uses passwd and group files. mkdir /usr/local/chroot/httpd/etc
, and copy /etc/passwd
there. Next, remove all entries except for the user that apache runs as in both files. Do remember to remove passwords as well; replacing them with !! will be sufficient. You will also need /etc/resolv.conf
. Lastly, run ldconfig -r /usr/local/chroot/httpd
to create a cache for any libraries that may be in the chroot
Whew, we're finished! Try it out. /usr/local/apache/apachectl start. If you don't get any errors, do a ps auwx|grep http and see if we're running. If so, lets check to make sure it's chrooted by picking out one of the process numbers of httpd and doing ls -al /proc/that_process_number/root. If you see /usr/local/chroot/httpd, congratulations! If you're using the older 2.0.x kernels, you'll only see numbers there. Those are inodes. You'll have to do ls -i /usr/local/chroot/httpd and compare the number from proc with it.
A couple of side notes you should be aware of:
- As mentioned above, if you use Perl, you'll need to copy or hardlink any system libraries, perl libraries (/usr/lib/perl5), and binaries into the chroot area.
- User home directories (the /~user stuff) is a bit tricky. You'll need to make a /home directory in the chroot, something like CHROOTDIR/home/aphzen/public_html, and give the user the ability to write to the public_html directory. Then add that user the the fake passwd/group files. This has some semi-neat side effects, such as being able to add/remove users without really doing it system wide. Be sure and remove passwords in these files too.
- Lastly, you'll want to keep only the bare minimum inside any chroot. The more you put in there, the more someone can do to possibly leverage their privileges to do something other than what the web server runs as. Definitely never put any suid files or anything that runs as root there, including running apache itself as root. Being root in a chroot is a Bad Thing (tm) and could conceivably be broken out of.
Comments, suggestions, or additions are welcome. Just point them to firstname.lastname@example.org
jh is a freelance UNIX Systems Administrator with over 4 years of experience maintaining machines and networks throughout the south-east.