|
There have been a large number of problems with BIND because of the size and complexity of the functions it performs. As a result, a number of attacks (and here ) are beginning to emerge that target this service specifically, some of which can allow full remote access to the target host. Because systems running DNS servers are so critical to the network infrastructure, it is vital that these systems do not get compromised. To further this, I've prepared this short document that describes how to set up your BIND 8.x server in a chroot() environment under RedHat Linux (but should apply to others as well). This document is largely inspired by my friend Adam Shostack and his paper on the identical subject matter (which covers Solaris). Please read his paper (and check out his entire page which contains good reading) after you've been here. Note: This is a living document and I expect changes and small errors to be discovered over time. My DNS server is very small and handles a limited number of zones and traffic. It is quite possible that the information I supply here does not work for larger sites. If this is your case please write me and tell me what is broken so I can change it here! Your input will be given full credit and will help everyone who wishes to contain the beast we call BIND. Linux Note: Although I do all my development on RedHat Linux, my WWW/SMTP/DNS server is in fact OpenBSD. This document was originally written for OpenBSD usage, but was modified to describe the procedure under Linux (which is only slightly different). Because of this though, I openly admit that I have very little experience running BIND under Linux in a chroot() environment. While I believe the information in this area to be accurate it may in fact vary somewhat from version to version of Linux. If this is the case then please write me and tell me! I would like to make this document as accurate as possible and this can only be done with your help. Lastly, the newest versions of RedHat Linux 6.x (and others?) have broken many things with static compilation as outlined below. If you have compile errors you may wish to do a dynamic link and move the appropriate files into the chroot hierarchy. There are also RPMs on the Internet that run BIND in a chroot() environment for you. These may also be worth looking into.
Go to the ISC FTP Site and download the latest version of BIND (These directions have only been tested on BIND version 8.x, which is the version you should be running anyway). Install the software per the directions included with the package. If you are running a newer version of Linux your system probably supports the "-a" option for syslogd. Check your man pages. If your system supports this option you can skip all sections talking about the "holelogd" daemon (which is the step below this paragraph). A big thanks to the maintainers of syslogd for putting in the "-a" alternate log socket option. It is a tremendous help to everyone running chroot() daemons! Go to Obtuse Systems's FTP site where you need to download their free program called: holelogd (and some other neat utilities). This program allows you to create a /dev/log socket under a chroot environment so syslog will work from named once it has been contained. Newer Linux systems already have a feature to do this built in (i.e. "syslogd -a /chroot/dev/log"). This program will emulate this feature for older hosts. Install holelogd per the instructions (usually in /usr/local/sbin).
After the build and install you will need to make a statically linked version of the program. This is easily accomplished by going into the directory /src/port/linux under BIND and editing the file Makefile.set. Change the line:
to:
Go to the top of the BIND source directory and do a "make clean" followed by a "make". Go onto the next step where you will copy the files to the chroot() directory. For the uninitiated, a statically linked program is one that does not perform dynamic loading of libraries. For a chroot() environment it means that the executable will be "self-contained" and will not cause an error if you are missing a library file. While it is not necessary to have statically linked files in the chroot() environment, it often makes setup easier. I prefer to have all network daemons statically linked for this reason.
Create a directory for BIND to be chroot()ed in. This can be as simple as /chroot/named and will be the "pseudo" root where BIND will reside. The ultra-paranoid may even want to put this chroot jail on a separate physical volume. Under this directory you will need to create the following directory structure:
Under each directory you will need to copy the following files and/or perform the following commands:
Additionally, Bernhard Weisshuhn <bkw@weisshuhn.de>, writes that if you have custom logging directories specified, you need to be sure to make these as well (i.e. /var/log). Although named won't crash, it will complain.
Add the user named to the /etc/passwd and /etc/group files. This will be the UID/GID that the server runs under. You should now go to the /chroot/named/var/run directory and make it writable by named so that the named.pid file can be written to upon startup. This is used by the ndc command to control named's operation. At this point you may want to go into your chroot named area and chown -R named.named on the /etc/namedb directory. This allows named to dump cache and statistical information if you send it the proper signal (i.e. kill -INT <PID>). This change should not significantly effect the security of your chroot() setup. Leaving it owned as root won't allow named to write out this information (remember named now runs under a new UID and no longer root), but still allows named to function. A second option is to change the permissions to allow writing to this directory, but leaving it owned by root. This could also work but you need to be careful with doing so to ensure normal users can't modify your named records! Important: Do not use an existing UID/GID to run named under (i.e. "nobody"). It is always a bad idea to use an existing UID/GID under a chroot environment as it can impact the protection offered by the service. Make a separate UID/GID for every daemon you run under chroot() as a matter of practice.
Linux uses SYS V style init files and there are several places to put the named commands to run. The cleanest location is in the named init script located in /etc/rc.d/init.d/named. In there you will find a section where named is started. You need to add and change a couple of lines. If you have a newer version of Linux that supports the syslogd "-a" option, skip the first step and go on to step 1a. Step 1: Do this step only if your system does not support the "-a" syslogd option. Put in a line before executing named to start up holelogd. holelogd also needs to be told where to put the remote socket. This should be the chroot named dev directory that you made above. It should look something like this:
Step 1a: Do this step if your system does support the "-a" syslogd option. Edit the syslog file under the init.d directory. syslogd needs to be told to set up an extra listening socket. This area should be the chroot named dev directory that you made above. It should look something like this:
Step 2: You will also need to change the start-up flags for BIND. Version 8.x has a feature where you can change the user and group ID after binding. This is where you specify the UID/GID that you assigned to BIND above:
If you are using holelogd:
If you are using syslogd:
Go into the chroot dev directory and ls -al. You should see (the date is insignificant):
The "s" bit is set to indicate that the file is a socket. This is how named will write to syslog from within the chroot() jail. Now type:
If all goes well, named will start and your logs will indicate that named is "Ready to answer queries." Perform other DNS tests as appropriate to ensure correct operation, then reboot your system and verify the setup. BIND should have started and reported it chroot()ed to the directory and changed UID/GID. You can use a program such as lsof to list out the owner of all network sockets on the host. The owner should be your named UID/GID. When everything is working you should either rename /etc/namedb to something like /etc/namedb.orig and chmod 000 /usr/sbin/named to ensure that the old version doesn't get run by mistake. Reboot your system and, assuming everything is correct, your named will now be chroot()ed.
Thanks to the following people who made suggestions and submitted corrections:
|