ImperialViolet

I was a technical reviewe... (26 Jan 2003)

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.