Cover V12, I09

Article
Figure 1
Figure 2
Figure 3
Figure 4

sep2003.tar

Securing Linux Systems with grsecurity

Keith McDuffee

As systems administrators know, there are a multitude of open source tools available for securing a Linux system. Most of these tools are installed and run on top of the operating system, either executing at given intervals via cron, in the background as a daemon, or directly triggered by specific activity.

grsecurity is another open source security package available for Linux, but it works quite a bit differently from applications executing in user space. Instead, grsecurity works primarily as a set of patches that are applied to the 2.4 Linux kernel, improving upon system security with more restricted process privileges, enhanced OpenBSD-like entropy pools, additional auditing capabilities, chroot and buffer overflow protections, and additions designed to thwart portscans and OS fingerprinting.

What Does It Do?

Rather than running specific tools to detect security breaches or vulnerabilities in a Linux system, grsecurity works by implementing process restrictions through the patched kernel, essentially invisible to any user. grsecurity goes further by imposing restrictions not only on basic users of a running system, but also on privileged accounts such as root.

The possibility always exists that an installed program can yield unexpected results because of programming bugs or improper configuration or implementation of features. Once these flaws are located and exposed, an attacker can use the vulnerabilities for malicious intent, sometimes gaining elevated privileges in the process. As a set of patches to the actual kernel, grsecurity attempts to thwart these attacks by applying itself to all applications.

One of the advanced features of grsecurity is protection from stack overflow exploits by including a complete implementation of non-executable pages. This feature ensures that no arbitrary code can be executed by disallowing an area of memory from ever having write and execute ability. In the past, if a malicious user was successful in causing a stack overflow on an application that stored data temporarily on the stack or heap, it was sometimes possible to cause the new stack data to execute and crash. If the original code was running at an elevated privilege, this in turn could allow the user to gain root access, and of course everything would tumble downhill from there. grsecurity prevents this scenario by prohibiting execution from unauthorized memory areas. There are several other similar improvements that prevent applications and users from executing unintentional functions, further improving the chances that familiar exploits are not located and used on your system.

grsecurity takes further steps in locking down a chroot'ed environment, beyond those that exist in default setups. For example, in the original implementation of chroot, it's possible for the root user to escape from a "chroot jail" by using a program similar to the following:

int main()
{
  chdir("/");
  mkdir("foo");
  chroot("foo");
  chdir("../../../../../../..");
  chroot(".");
  execl("/bin/sh", "sh", (char *)0);
}
One of grsecurity's options is to enforce chdir(/) on all chroots, eliminating the possibility of this behavior. There are also additional restrictions available for chroots, such as denying the use of mknod to create device entries, disallowing double-chroots to break out of chroot jails, protecting outside processes (hiding their existence to processes inside the jail), and denying chrooted processes from mounting or remounting filesystems. These options are invaluable, particularly to Web, mail, and DNS servers, where chroot'ed environments are often used, and the elimination of these abilities makes perfect sense.

There are other features that may be a bit more noticeable upfront, such as the utilization of randomized PIDs (Figure 1), IP IDs, and TCP source ports (Figure 2). Randomized PIDs are particularly effective when used in conjunction with grsecurity's /proc restrictions, disallowing users from guessing PIDs of privileged applications and daemons. In some cases, PIDs are used by applications for naming temporary files, where merely locating a given PID would help one predict the name of the next successive filename; randomized PIDs make these predictions much more difficult.

Additionally on the network side, grsecurity provides a "stealth" networking module to iptables. Essentially when this module is activated (via an iptables ruleset), it matches any UDP or TCP packets destined for unserved ports on the system. These packets are then dropped, effectively slowing down port scanners set to search for blocked ports. Although usually not all that common in secured environments, this feature is particularly useful on systems where a default rule of DROP isn't possible because of users running their own servers on ports that are difficult to track.

If you're interested in utilizing the ACL (Access Control List) system of grsecurity, you may be interested in enabling grsecurity's Sysctl support (CONFIG_GRKERNSEC_SYSCTL), as it will give you the ability to change the options that run with grsecurity at boot time without having to recompile your kernel. With this option, by echo'ing 0 (off -- the initial default for all options) or 1 (on) to the files located in /proc/sys/kernel/grsecurity, you can easily enable or disable the features you want. Once the grsec_lock file contains 1, no further configuration is possible without a reboot. Note that if you choose to enable Sysctl support, the effectiveness of grsecurity's added security can be significantly reduced without the presence of the ACL system.

Some additional enhancements of note:

  • Dmesg restriction: Denies non-root users from using dmesg(8) to view up to the last 4Kb of messages in the kernel's log buffer.
  • Larger entropy pools: Doubles the size of the Linux and grsecurity entropy pools, similar to modifying /proc/sys/kernel/random/poolsize.
  • Linking restrictions: Disables the ability to follow symlinks owned by other users in world-writable +t directories (i.e., /tmp) or hardlink to files the user does not own.
  • FIFO restrictions: Denies users from writing to FIFOs they don't own in world-writable +t directories.
  • Altered ping IDs: Ping replies will use an ID equal to the ID of the echo request, helping to confuse OS detection.
  • Logging options: Mount logging, chdir logging, IPC logging, signal logging, fork failure logging, and time change logging, among others.
  • Additional ACL options: Hiding kernel processes.
  • Kernel symbol hiding and non-executable user and kernel pages: Helps stop many exploits in the kernel itself.
Installing grsecurity

grsecurity is updated religiously to be compatible with the latest release of the 2.4 Linux kernel. You will need to download the latest 2.4 kernel sources from:

http://www.kernel.org/
before applying the patches. You'll also want to obtain the latest iptables sources from:

http://www.netfilter.org/downloads.html
For the full grsecurity package, grab the two sets of patches (grsecurity and iptables patch) and the gradm utility from:

http://www.grsecurity.net/download.php
Next, unpack the kernel and iptables sources and apply the patches:

# cd /usr/src
# tar xvfz linux-2.4.20.tar.gz
# patch -p0 < grsecurity-1.9.9f-2.4.20.patch
# bunzip2 < iptables-1.2.8.tar.bz2 | tar xvf -
# patch -p0 < grsecurity-1.2.8-iptables.patch
When you configure the newly patched kernel with make menuconfig, you'll notice a new section added to the bottom of the options list, aptly titled "grsecurity" (Figure 3). There is an additional module for Netfilter that handles the new "stealth" matching located under "Networking Options->IP: Netfilter Configuration->stealth match support", which needs to be selected separately for installation if you want this capability.

This new section contains the various options available with grsecurity. You can simply choose among the three levels of grsecurity (low, medium, and high -- see Figure 4), or you can customize with the numerous options available. If you're not experienced with grsecurity, you'll likely want to avoid starting off with using the "high" level, as it will be more difficult to determine which components are causing grief should a problem with the installation arise. In my testing, using the "medium" or "low" levels worked best, with no application or daemon startup issues. Figure 3 shows a listing of what comprises each level, however, there are a few options not included in any of the levels that must be chosen individually if desired.

Once you've chosen the grsecurity options you want and have configured the rest of the kernel to meet your needs, you can compile and install it:

# make dep && make clean && make
# make modules && make modules_install && make install
Be sure to edit your LILO or Grub configuration to allow you to choose from the new or existing kernel at boot time in case something goes wrong with the installation. If your first attempts at booting fail from the grsecurity kernel, which may happen on occasion when enabling the ACL options, try rebooting into the old kernel, then reconfigure and recompile grsecurity with different options. If you did not enable the ACL system, you can now boot into the new kernel, otherwise you'll first need to proceed through the next step.

Using the ACL system

An ACL system provides detailed control of access privileges to your system. Such a system is used to further restrict access to files, resources, sockets, or other capabilities to every user on the system, including root. While the primary features of grsecurity help protect against unauthorized access to root, the ACL system takes the next step in protecting beyond a potentially successful attack. Essentially, once a user gains root access, he or she does not have complete access to the system.

If you've chosen to enable the ACL portion of grsecurity, you'll need to build the gradm utility downloaded from the grsecurity site:

# gradm-1.9.9h.tar.gz
# cd gradm
# ./configure
# make && make install
...
Setting up grsecurity ACL password
Password:
Re-enter Password:
Password written to /etc/grsec/pw.
Note that gradm is installed into /sbin by default. gradm will automatically detect where it is being executed and auto-secure itself. Also note that once you enable the ACL system with gradm, you must use the same binary to disable or reload the system.

The configuration file for the ACL system is located at /etc/grsec/acl, containing the following structure:

<path of subject process> <optional subject modes> {
     <file object> <optional object modes>
     [+|-]<capability
     <resource name> <soft limit> <hard limit>
     connect {
       <ip>/<netmask>:<low port>-<high port> <type> <proto>
     }
     bind {
       <ip>/<netmask>:<low port>-<high port> <type> <proto>
     }
}
The configuration file must at least contain a subject ACL for /, but as you can see from the initial file created by the installation of gradm, there are far more ACLs you'll want to configure to achieve the full effect of the system.

As a brief example, consider a portion of the first subject process:

/ {
           /               r
           /opt            rx
           /home           rwx
           /var/log        r
           /dev
...
}
Simply stated, this base ACL pertains to all applications unless an exception is made. In this case, applications are only permitted to read files in /, read/execute files in /opt, read/write/execute files in /home, read files in /mnt, and have no access to files within /dev. Once we put an exception ACL in place under this, we can carefully refine which applications can go beyond these initial rules:

/sbin/syslogd {
           /dev/log rw
           /var/log w
}
With this ACL, we're allowing the syslogd daemon to make an exception to the rules put on /dev and /var/log in the first ACL. Obviously this is necessary for syslogd to function properly. There are many of these ACLs in the default file, and there's sure to be a few more you'll want to add or edit before proceeding.

The gradm utility is used to enable (gradm -E) or disable (gradm -D) the ACLs, as well as administrate the ACLs for short periods of time (gradm -a). Any action that disables the ACLs will require the password you initially entered upon installation of gradm, which can also be changed with the same utility (gradm -P).

There are far more options and capabilities that aren't mentioned here. A good place to start would be to read the ACL documentation on the grsecurity's site:

http://www.grsecurity.org/gracldoc.pdf
Make sure you fully understand the implications of enabling ACL and the full set of options that must exist in the configuration file. It's very easy to miss something and cause programs to fail if great care isn't taken in this task.

Stealth Networking Support

As previously mentioned, also packaged with the grsecurity patches is support for "stealth" packet matching. Enabling this option in the kernel configuration will drop all syn packets coming to unserved TCP ports, as well as any packets coming to unserved UDP ports on the network. To make full use of this feature, you will need to install your previously patched iptables sources:

# cd /usr/src/iptables-1.2.8
# make clean
# make && make install
This will place the new iptables user executable into /usr/local/sbin by default, so you will need to update your startup scripts to point to the new location. Once you have booted into the new grsecurity-patched kernel and have installed the stealth module, you can make use of the new feature in your iptables startup file.

If you are using your system to route any type of packets (i.e., via NAT), you should put these at the end of your ruleset, since it will drop packets that aren't going to ports that are listening on your system itself. In the case of NAT, the module doesn't take into account that the packet might be destined for someone on your internal network.

Here's an example of a portion of an iptables startup script:

---
#!/bin/csh

set IPTABLES = /usr/local/sbin/iptables

$IPTABLES -N stealth-n-log
$IPTABLES -A stealth-n-log -j LOG --log-level 4 --log-prefix
"stealth-n-log:"
$IPTABLES -A stealth-n-log -j DROP

## Input/Output accept rules go here

$IPTABLES -A INPUT -p tcp -m stealth -j stealth-n-log
$IPTABLES -A INPUT -p udp -m stealth -j stealth-n-log
---
With the above rules activated, if someone were to portscan your system (with nmap for example), you'd see something like this in your logs:

stealth-n-log:IN=eth1 OUT= MAC=00:e0:18:2e:9c:3a:00:20:78:c9:f5:b8:08:00
SRC=192.168.1.101 DST=192.168.1.108 LEN=60 TOS=0x00 PREC=0x00 TTL=51
ID=26988 DF PROTO=TCP SPT=28920 DPT=30 WINDOW=5840 RES=0x00 SYN URGP=0
stealth-n-log:IN=eth1 OUT= MAC=00:e0:18:2e:9c:3a:00:20:78:c9:f5:b8:08:00
SRC=192.168.1.101 DST=192.168.1.108 LEN=60 TOS=0x00 PREC=0x00 TTL=51
ID=33605 DF PROTO=TCP SPT=15569 DPT=366 WINDOW=5840 RES=0
x00 SYN URGP=0

If your iptables did not contain stealth rules, from the 
attacker's side, an nmap scan on your system would look something 
like this:


---
# nmap -P0 192.168.1.108 -p 5003-5009

Starting nmap V. 3.00 ( www.insecure.org/nmap/ )
All 7 scanned ports on no-grsecurity (192.168.1.108) are: close
d

Nmap run completed -- 1 IP address (1 host up) scanned in 1 second
---
While a scan on a stealth protected system would look like this:

---
# nmap -P0 192.168.1.101 -p 5003-5009

Starting nmap V. 3.00 ( www.insecure.org/nmap/ )
Interesting ports on no-grsecurity (192.168.1.101):
Port       State       Service
5003/tcp   filtered    unknown
5004/tcp   filtered    unknown
5005/tcp   filtered    unknown
5006/tcp   filtered    unknown
5007/tcp   filtered    unknown
5008/tcp   filtered    unknown
5009/tcp   filtered    unknown

Nmap run completed -- 1 IP address (1 host up) scanned in 48 seconds
---
Note the length of time the nmap scan took on both systems. These results can be somewhat unexpected on the attacker's end, causing them to at least have to reevaluate their methods.

grsecurity in Practice

Not every Linux system will necessarily benefit a whole lot from the use of grsecurity. The more exposed a system is to outside access, the more grsecurity makes sense. If a particular server can get away with the access controls put in place, it's certainly a consideration.

grsecurity helps implement file system and process protection not existing in the default 2.4 Linux kernel, and also provides ports of several 2.2 kernel enhancements. Particularly for shared use systems, the ACL system can be invaluable where many users have shell access. The enhancements to the chroot jail are particularly useful for Web, ftp, and DNS servers that are often executed chroot'ed.

For anyone who has compiled the Linux kernel before, installing the grsecurity patches should be relatively easy. One possible downside of grsecurity is lack of support for slightly earlier kernels or iptables, requiring you to update to the latest sources should you want to use the currently available version of the patches. Choosing the appropriate options for your needs and implementing the ACLs can also be tricky. The grsecurity folks did an excellent job commenting each of the configuration options, so be sure to check them all out, as well as the ACL documentation, before committing to anything.

Resources

http://www.grsecurity.org/

http://freshmeat.net/projects/grsecurity/

http://pageexec.virtualave.net/

Special thanks to Brad Spengler (spengler@grsecurity.net) of grsecurity for his assistance.

Keith McDuffee (gudlyf@realistek.com) has been a Network and Systems Administrator for more than 10 years and is currently employed as the IT Manager for Etnus in Natick, Massachusetts.