I was a technical reviewer for UNIX Power Tools (3rd Ed) and, while cleaning out an old drive today, I found the sketch I did for the security chapter. For those who own the book, I thought that chapter 48 needed serious work and did a sketch to show what I would have liked in it's place. Anyway, the editor disagreed so I might as well post that sketch here.
* Attack Models Any discussion of security must first at least give a passing nod to the idea of who your attacker is. The decisions you make concerning security will largely be based on how well funded, motivated and powerful your attacker is. The security needs of government computers are very different to the Amstrad that someone occasionally uses to type a letter. For a computer connected to the Internet the profile of your average attacker will be a mostly unmotivated, largely unskilled individual (unless you have special reason to think you are a high profile target). Unfortunately there are many attackers on the Internet using automated tools which exploit vulnerable software automatically. For this reason all networked computers should be secured against this kind of threat and prepared in the event of a breach. * Least-Privilege The principle of least-privilege states that something should have the ability to carry out its task and no more. This seems like a simple idea and easily obtainable but in practice is often violated. All processes run with a UID, GID and are members of certain groups. For example when you (say, UID=1000) run /bin/ls a process is created which inherits your UID, GID and groups and the image of /bin/ls is loaded and executed. The ls process may then do anything which you could do. This is an example of a violation of least privilege as there is no need, for example, for ls to be able to alter any files. No security model is perfect and we have to live with the limitations of the UNIX security model on UNIX based systems. * Physical Security A comprehensive coverage of this topic is outside the scope of this book, but if you cannot secure the physical computer then no amount of clever software is going to help. Ideally the computer will be in a locked room with dedicated power and air conditioning but, unless you are cohosting, this is very unlikely. Most physical situations are far from ideal and you should always keep this in the back of your mind. You may wish to read Security Engineering by R. Anderson for an interesting and detailed coverage of physical security (among other topics). ** Booting Security The first vulnerable point is before the operating system has even loaded. Most computers will boot from a floppy disk first, by default. It requires physical access, but if an attacker can boot off their own kernel they have free reign over the system. At the very least you should change the booting options to only boot from the hard disk and set a BIOS password. Remember that a BIOS password can usually be cleared by shorting a jumper on the motherboard, however. The next stage to be concerned with is the boot loader which actually loads a kernel from the disk and runs it. At this point an attack may be able alter the boot sequence and bypass normal protections. For example, passing the option "init=/bin/sh" to a Linux kernel will cause it to drop to a root shell after the kernel has loaded. Boot loaders vary with the flavour of UNIX, investigate the man-page for yours to find what security features it has. * Unneeded services Many default installs are guilty of running far too many unneeded services by default. These generally remain unused and serve no purpose except to provide more possible entry points for an attacker. The first place to look is in /etc/inetd.conf. As a general rule of thumb you should comment out every service which you don't know that you require. Once you have done this (and every time you edit inetd.conf) you should send a SIGHUP to the inetd process. Often inetd will not be running any services in which case you can disable it. You should also check for other services with `ps auxw`, `netstat -l` and `lsof -i`. These services will have been started by your init scripts and you should consult the documentation for your system for disabling them. * Securing needed services Most systems will have a number of services which need to be running in order to function. Given that they are a necessity we must now turn to making them as secure as possible. The first question is which software are you going to use to perform the required tasks. Many services have a de-facto daemon that is usually installed to provide them. However, these de-facto choices often are not the most secure and you may wish to investigate others. For example, sendmail is the de-facto daemon to provide email services. However, it has a long history of security problems and a fundamentally bad design which violates least-privilege. If you need some advanced mail handing capability it might be that only sendmail will do. However, in nearly all cases packages such as qmail and postfix will do the job and these have been designed from the ground up with security in mind. ** Dropping root Many daemons will give you the option of switching to a non-root user once they have started up (setuid). This gives it the ability to perform some root tasks at startup and then prevent itself from issuing any more. If the server is compromised in operation the attacker gains control of a process running as a dummy user - much less damaging than a root compromise. For example a daemon may bind to a low numbered port (which requires root privileges) and then switch to a non-root user while retaining the socket in its file descriptor table. When offered you should always use a setuid option. You should, however, create a different user for each service. Many systems have an account called nobody that services often run under. But if nobody owns processes (and possibly files) then nobody is somebody! By confining each process to its own user you contain the service. * Chroot and jails The chroot system call changes the root directory for a process. Normally the root directory for a process is the systems root directory with the path "/". However by chrooting a process you can confine a process's view of the file-system so a given subdirectory. Note: After a chroot the current directory of a process may still be outside the new root file-system. ** Example chrooting Apache There are 2 stages to chrooting a daemon. The first is to reconfigure the daemon for the new paths. The second is to setup a minimal environment for the daemon to run in. For this example I'll be configuring apache in a temporary directory in my home. For a real server you'll want to put it a different directory (I use /jail). This example uses the chroot system call. Your system may provide other, similar calls such as jail. See the man pages for these calls. *** Building Apache Download an apache tarball from your favourite mirror and expand it. I'm using version 1.3.26 here. % cd ~/src % tar xzf apache_1.3.26.tar.gz % cd apache_1.3.26 % ./configure --prefix=/home/agl/tmp/apache % make % make install You may wish to add other options to the configure command line to enable your favourite mod_foo. Now we reconfigure apache to expect the different path names. Since /home/agl/tmp/apache is going to be the new root apache will see paths like /htdocs. Apache's startup script is a shell script so we are going to need a shell in our root to run it. Since this is a Linux box I'm going to be using bash. If you have a real Bourne shell you may wish to use that instead. % cd ~/tmp/apache % vim /bin/apachectl We need to change 3 lines in this file and add one. Change the shebang line to expect a shell in the root directory and a couple of the paths. We also add a -f option to httpd to tell it where its config file is. #!/bin/sh -> #!/bash PIDFILE=/home/agl/tmp/apache/logs/httpd.pid -> PIDFILE=/logs/httpd.pid HTTPD=/home/agl/tmp/apache/bin/httpd -> HTTPD="/bin/httpd -f /conf/httpd.conf" Now, just before the line which reads "ERROR=0" insert a line reading "cd /". This sets the current directory to be inside the jail. We we need to remove the string "/home/agl/tmp/apache" every time it appears in conf/httpd.conf. Use your favourite text editor, or do % vim conf/httpd.conf :%s!/home/agl/tmp/apache!! You also need to find the User and Group directives in this file and change them to read User apache Group apache Now we come to the second part of setting up a chroot jail - creating the environment. Foremost in our mind are the user and group names we just told apache to use. It needs to be able to turn these into real UIDs and GIDs. For this it needs an /etc/passwd and /etc/group in the jail. However, I recommend that you also setup a user and group in the main passwd and group files with a sensible name so processes outside the jail can make sense of the httpd processes inside (for example, ps). In etc/passwd put apache:x:65534:65534:nobody:/home:/bin/sh and in etc/group put apache:x:65534: Now set the permissions % chmod 664 etc/passwd etc/group All modern systems support some kind of runtime linking of libraries. In order to run apache and bash we need to copy the libraries they require. These requirements vary greatly but the ldd command will generally reveal all the requirements. % ldd ../bin/httpd libm.so.6 => /lib/libm.so.6 (0x00136000) libcrypt.so.1 => /lib/libcrypt.so.1 (0x00158000) libc.so.6 => /lib/libc.so.6 (0x00185000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x00110000) % mkdir lib % cd lib % cp /lib/ld-linux.so.2 . % cp /lib/libc.so.6 . % cp /lib/libcrypt.so.1 . % cp /lib/libm.so.6 . % ldd /bin/bash libncurses.so.5 => /lib/libncurses.so.5 (0x00136000) libdl.so.2 => /lib/libdl.so.2 (0x00174000) libc.so.6 => /lib/libc.so.6 (0x00178000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x00110000) % cp /lib/libncurses.so.5 . % cp /lib/libdl.so.2 . % cp /lib/libnss_files.so.2 . % cd .. The last library isn't mentioned by any ldd listing, but glibc loads it on the fly to read /etc/passwd and /etc/group. Now we copy bash and cat into the jail (apachectl uses cat) and create /dev/null. % cp /bin/bash . % cp /bin/cat bin % mkdir dev % su # cp -a /dev/null dev That's the environment completed. Apache can be run by # chroot . ./bin/apachectl start * Limits Resource limits are required on any secure system - especially multi-user systems. Without them (and they are often disabled by default) users may use up so many resources that critical systems are unable to function and service is denied to others. A simple example is a fork bomb. The following line of C code will bring systems without resource limits to their needs - sometimes requiring a power cycle to recover. for (;;) fork (); There are two many types of resource limit - quota and limits.conf ** Limits.conf This file describes the limits placed on users for resources such as the process table and memory. The number of rules in this file should be kept to a minimum. Limits should be set on whole groups to keep the file manageable. ** Quota Quota controls the amount of disk space that users and groups may use. Quota systems vary widely between UNIXes and you may have to consult the documentation for your system for the specific commands required. Generally quota systems allow the restriction of blocks and inodes. Blocks are 512 or 1024 byte chunks and limiting this number limits the actual amount of data that a user may own. Inodes are structures that describe files and many file-systems have hard limits on the number available. Unless you limit them a user may be able to fill the inode table and prevent new files being created. * Security at more abstract levels There are many social aspects of security that also need to be considered by a poor-overworked sys admin. Much of this area of outside the scope of a book such as this. Much as been written about the security of passwords, or rather the lack of, but still insecure passwords remain. Unless your users are security-savvy you can be sure that most of their passwords will be simple to guess. Several options present themselves from seeking to educate users, setting up cracklib or providing a version of passwd which only gives out random passwords. Social Engineering is another method for attackers to gain access to a system and is very hard to defend against. It generally involves tricking users into revealing passwords or running Trojan programs. There are no good technical measures against this family of attacks. They require user education and strict guidelines.