BUY THIS BOOK
Add to Cart

Print Book $29.99


Add to Cart

PDF $23.99

Safari Books Online

What is this?

Add to UK Cart

Print Book £20.99

What is this?

Looking to Reprint or License this content?


Network Security Hacks
Network Security Hacks, Second Edition Tips & Tools for Protecting Your Privacy

By Andrew Lockhart
Book Price: $29.99 USD
£20.99 GBP
PDF Price: $23.99

Cover | Table of Contents


Table of Contents

Chapter 1: Unix Host Security
Networking is all about connecting computers together, so it follows that a computer network is no more secure than the machines that it connects. A single insecure host can make lots of trouble for your entire network, because it can act as a tool for reconnaissance or a strong base of attack if it is under the control of an adversary. Firewalls, intrusion detection mechanisms, and other advanced security measures are useless if your servers offer easily compromised services. Before delving into the network part of network security, you should first make sure that the machines you are responsible for are as secure as possible.
This chapter offers many methods for reducing the risks involved in offering services on a Unix-based system. Even though each of these hacks can stand on its own, it is worth reading through this entire chapter. If you implement only one type of security measure, you run the risk of all your preparation being totally negated once an attacker figures out how to bypass it. Just as Fort Knox isn’t protected by a regular door with an ordinary dead bolt, no single security feature can ultimately protect your servers. And the security measures you may need to take increase proportionally to the value of what you’re protecting.
As the old saying goes, security isn’t a noun, it’s a verb. That is, security is an active process that must be constantly followed and renewed. Short of unplugging it, there is no single action you can take to secure your machine. With that in mind, consider these techniques as a starting point for building a secure server that meets your particular needs.
Use mount options to help prevent intruders from further escalating a compromise.
The primary way of interacting with a Unix machine is through its filesystem. Thus, when an intruder has gained access to a system, it is desirable to limit what he can do with the files available to him. One way to accomplish this is with the use of restrictive mount options.
A mount option is a flag that controls how the filesystem may be accessed. It is passed to the operating system kernel’s code when the filesystem is brought online. Mount options can be used to prevent files from being interpreted as device nodes, to disallow binaries from being executed, and to disallow the SUID bit from taking effect (by using the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Secure Mount Points
Use mount options to help prevent intruders from further escalating a compromise.
The primary way of interacting with a Unix machine is through its filesystem. Thus, when an intruder has gained access to a system, it is desirable to limit what he can do with the files available to him. One way to accomplish this is with the use of restrictive mount options.
A mount option is a flag that controls how the filesystem may be accessed. It is passed to the operating system kernel’s code when the filesystem is brought online. Mount options can be used to prevent files from being interpreted as device nodes, to disallow binaries from being executed, and to disallow the SUID bit from taking effect (by using the nodev , noexec, and nosuid flags). Filesystems can also be mounted read-only with the ro option.
These options are specified from the command line by running mount with the -o flag. For example, if you have a separate partition for /tmp that is on the third partition of your first IDE hard disk, you can mount with the nodev, noexec, and nosuid flags, which are enabled by running the following command:
# mount -o nodev,noexec,nosuid /dev/hda3 /tmp
         
An equivalent entry in your /etc/fstab would look something like this:
/dev/hda3    /tmp    ext3    defaults,nodev,noexec,nosuid    1 2
By carefully considering your requirements and dividing up your storage into multiple filesystems, you can utilize these mount options to increase the work that an attacker will have to do in order to further compromise your system. A quick way to do this is to first categorize your directory tree into areas that need write access for the system to function and those that don’t. You should consider using the read-only flag on any part of the filesystem where the contents do not change regularly. A good candidate for this might be /usr, depending on how often updates are made to system software.
Obviously, many directories (such as /home) will need to be mounted as read/write. However, it is unlikely that users on an average multiuser system will need to run SUID binaries or create device files within their home directories. Therefore, a separate filesystem, mounted with the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Scan for SUID and SGID Programs
Quickly check for potential root-exploitable programs and backdoors.
One potential way for a user to escalate her privileges on a system is to exploit a vulnerability in an SUID or SGID program. SUID and SGID are legitimately used when programs need special permissions above and beyond those that are available to the user who is running them. One such program is passwd. Simultaneously allowing a user to change her password while not allowing any user to modify the system password file means that the passwd program must be run with root privileges. Thus, the program has its SUID bit set, which causes it to be executed with the privileges of the program file’s owner. Similarly, when the SGID bit is set, the program is executed with the privileges of the file’s group owner.
Running ls -l on a binary that has its SUID bit set should look like this:
-r-s--x--x    1 root     root        16336 Feb 13  2003 /usr/bin/passwd
Notice that instead of an execute bit (x) for the owner bits, it has an s. This signifies an SUID file.
Unfortunately, a poorly written SUID or SGID binary can be used to quickly and easily escalate a user’s privileges. Also, an attacker who has already gained root access might hide SUID binaries throughout your system in order to leave a backdoor for future access. This leads us to the need for scanning systems for SUID and SGID binaries. This is a simple process and can be done with the following command:
# find / \( -perm -4000 -o -perm -2000 \) -type f -exec ls -la {} \;
         
One important thing to consider is whether an SUID program is in fact a shell script rather than an executable, since it’s trivial for someone to change an otherwise innocuous script into a backdoor. Most operating systems ignore any SUID or SGID bits on a shell script, but if you want to find all SUID or SGID scripts on a system, change the argument to the -exec option in the last command and add a pipe so that the command reads:
# find / \( -perm -4000 -o -perm -2000 \) -type f \
            -exec file {} \; | grep -v ELF
         
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Scan for World- and Group-Writable Directories
Quickly scan for directories with loose permissions.
World- and group-writable directories present a problem: if the users of a system have not set their umasks properly, they will inadvertently create insecure files, completely unaware of the implications. With this in mind, it seems it would be good to scan for directories with loose permissions. As in “Scan for SUID and SGID Programs” [Hack #2], this can be accomplished with a find command:
# find / -type d \( -perm -g+w -o -perm -o+w \) -exec ls -lad {} \;
         
Any directories that are listed in the output should have the sticky bit set, which is denoted by a t in the directory’s permission bits. Setting the sticky bit on a world-writable directory ensures that even though anyone may create files in the directory, they may not delete or modify another user’s files.
If you see a directory in the output that does not contain a sticky bit, consider whether it really needs to be world-writable or whether the use of groups or ACLs [Hack #4] will work better for your situation. If you really do need the directory to be world-writable, set the sticky bit on it using chmod +t.
To get a list of directories that don’t have their sticky bit set, run this command:
# find / -type d \( -perm -g+w -o -perm -o+w \) \
-not -perm -a+t -exec ls -lad {} \;
If you’re using a system that creates a unique group for each user (e.g., you create a user andrew, which in turn creates a group andrew as the primary group), you may want to modify the commands to not scan for group-writable directories. (Otherwise, you will get a lot of output that really isn’t pertinent.) To do this, run the command without the -perm -g+w portion.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Create Flexible Permissions Hierarchies with POSIX ACLs
When Unix mode-based permissions just aren’t enough, use an ACL.
Most of the time, the traditional Unix file permissions system fits the bill just fine. But in a highly collaborative environment with multiple people needing access to files, this scheme can become unwieldy. Access control lists, otherwise known as ACLs (pronounced to rhyme with “hackles”), are a relatively new feature of open source Unix operating systems, but they have been available in their commercial counterparts for some time. While ACLs do not inherently add “more security” to a system, they do reduce the complexity of managing permissions. ACLs provide new ways to apply file and directory permissions without resorting to the creation of unnecessary groups.
ACLs are stored as extended attributes within the filesystem metadata. As the name implies, they allow you to define lists that either grant or deny access to a given file or directory based on the criteria you provide. However, ACLs do not abandon the traditional permissions system completely. ACLs can be specified for both users and groups and are still separated into the realms of read, write, and execute access. In addition, a control list may be defined for any user or group that does not correspond to any of the other user or group ACLs, much like the “other” mode bits of a file.
Access control lists also have what is called an ACL mask, which acts as a permission mask for all ACLs that specifically mention a user and a group. This is similar to a umask, but not quite the same. For instance, if you set the ACL mask to r--, any ACLs that pertain to a specific user or group and are looser in permissions (e.g., rw-) will effectively become r--. Directories also may contain a default ACL, which specifies the initial ACLs of files and subdirectories created within them.
Most filesystems in common use today under Linux (Ext2/3, ReiserFS, JFS, and XFS) are capable of supporting ACLs. If you’re using Linux, make sure one of the following kernel configuration options is set, corresponding to the type of filesystem you’re using:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Protect Your Logs from Tampering
Use file attributes to prevent intruders from removing traces of their break-ins.
In the course of an intrusion, an attacker will more than likely leave telltale signs of his actions in various system logs. This is a valuable audit trail that should be well protected. Without reliable logs, it can be very difficult to figure out how the attacker got in, or where the attack came from. This information is crucial in analyzing the incident and then responding to it by contacting the appropriate parties involved [Hack #125]. However, if the break-in attempt is successful and the intruder gains root privileges, what’s to stop him from removing the traces of his misbehavior?
This is where file attributes come in to save the day (or at least make it a little better). Both Linux and the BSDs have the ability to assign extra attributes to files and directories. This is different from the standard Unix permissions scheme in that the attributes set on a file apply universally to all users of the system, and they affect file accesses at a much deeper level than file permissions or ACLs [Hack #4]. In Linux, you can see and modify the attributes that are set for a given file by using the lsattr and chattr commands, respectively. Under the BSDs, you can use ls -lo to view the attributes and use chflags to modify them.
One useful attribute for protecting log files is append-only. When this attribute is set, the file cannot be deleted, and writes are only allowed to append to the end of the file.
To set the append-only flag under Linux, run this command:
# chattr +a 
            
               filename
            
         
Under the BSDs, use this:
# chflags sappnd 
            
               filename
            
         
See how the +a attribute works by creating a file and setting its append-only attribute:
# touch /var/log/logfile
# echo "append-only not set" > /var/log/logfile
# chattr +a /var/log/logfile
# echo "append-only set" > /var/log/logfile
bash: /var/log/logfile: Operation not permitted
The second write attempt failed, since it would overwrite the file. However, appending to the end of the file is still permitted:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Delegate Administrative Roles
Let others do your work for you without giving away root privileges.
The sudo utility can help you delegate some system responsibilities to other people, without having to grant full root access. sudo is a setuid root binary that executes commands on an authorized user’s behalf, after she has entered her current password.
As root, run /usr/sbin/visudo to edit the list of users who can call sudo. The default sudo list looks something like this:
root ALL=(ALL) ALL
Unfortunately, many system administrators tend to use this entry as a template and grant unrestricted root access to all other admins unilaterally:
root ALL=(ALL) ALL
rob ALL=(ALL) ALL
jim ALL=(ALL) ALL
david ALL=(ALL) ALL
While this may allow you to give out root access without giving away the root password, this method is truly useful only when all of the sudo users can be completely trusted. When properly configured, the sudo utility provides tremendous flexibility for granting access to any number of commands, run as any arbitrary user ID (UID).
The syntax of the sudo line is:
            user machine=(effective user) command 
         
The first column specifies the sudo user. The next column defines the hosts in which this sudo entry is valid. This allows you to easily use a single sudo configuration across multiple machines.
For example, suppose you have a developer who needs root access on a development machine, but not on any other server:
peter beta.oreillynet.com=(ALL) ALL
The next column (in parentheses) specifies the effective user who may run the commands. This is very handy for allowing users to execute code as users other than root:
peter lists.oreillynet.com=(mailman) ALL
Finally, the last column specifies all of the commands that this user may run:
david ns.oreillynet.com=(bind) /usr/sbin/rndc,/usr/sbin/named
If you find yourself specifying large lists of commands (or, for that matter, users or machines), take advantage of sudo’s alias syntax. An alias can be used in place of its respective entry on any line of the sudo configuration:
User_Alias ADMINS=rob,jim,david
User_Alias WEBMASTERS=peter,nancy
Runas_Alias DAEMONS=bind,www,smmsp,ircd
Host_Alias WEBSERVERS=www.oreillynet.com,www.oreilly.com,www.perl.com
Cmnd_Alias PROCS=/bin/kill,/bin/killall,/usr/bin/skill,/usr/bin/top
Cmnd_Alias APACHE=/usr/local/apache/bin/apachectl
WEBMASTERS WEBSERVERS=(www) APACHE
ADMINS ALL=(DAEMONS) ALL
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Automate Cryptographic Signature Verification
Use scripting and key servers to automate the chore of checking software authenticity.
One of the most important things you can do for the security of your system is to make yourself familiar with the software you are installing. You probably will not have the time, knowledge, or resources to go through the source code for all of the software that you install. However, verifying that the software you are compiling and installing is what the authors intended can go a long way toward preventing the widespread distribution of Trojan horses.
Recently, Trojaned versions of several pivotal pieces of software (such as tcpdump, libpcap, sendmail, and OpenSSH) have been distributed. Since this is an increasingly popular attack vector, verifying your software is critically important.
Why does this need to be automated? It takes little effort to verify software before installing it, but either through laziness or ignorance, many system administrators overlook this critical step. This is a classic example of “false” laziness, since it will likely lead to more work for the sysadmin in the long run.
This problem is difficult to solve, because it relies on the programmers and distributors to get their acts together. Then there’s the laziness aspect. Software packages often don’t even come with a signature to use for verifying the legitimacy of what you’ve downloaded, and even when signatures are provided with the source code, to verify the code you must hunt through the software provider’s site for the public key that was used to create the signature. After finding the public key, you have to download it, verify that the key is genuine, add it to your keyring, and finally check the signature of the code.
Here is what this would look like when checking the signature for Version 1.3.28 of the Apache web server using GnuPG (http://www.gnupg.org):
# gpg -import KEYS
# gpg -verify apache_1.3.28.tar.gz.asc apache_1.3.28.tar.gz
gpg: Signature made Wed Jul 16 13:42:54 2003 PDT using DSA key ID 08C975E5
gpg: Good signature from "Jim Jagielski <jim@zend.com>"
gpg:                 aka "Jim Jagielski <jim@apache.org>"
gpg:                 aka "Jim Jagielski <jim@jaguNET.com>"
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Fingerprint: 8B39 757B 1D8A 994D F243  3ED5 8B3A 601F 08C9 75E5
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Check for Listening Services
Find out whether unneeded services are listening and looking for possible backdoors.
One of the first things you should do after a fresh operating system install is see what services are running and remove any unneeded services from the system startup process. You could use a port scanner (such as Nmap [Hack #66]) and run it against the host, but if one didn’t come with the operating system install, you’ll likely have to connect your fresh (and possibly insecure) machine to the network to download one.
Also, Nmap can be fooled if the system is using firewall rules. With proper firewall rules, a service can be completely invisible to Nmap unless certain criteria (such as the source IP address) also match. When you have shell access to the server itself, it is usually more efficient to find open ports using programs that were installed with the operating system. One option is netstat, a program that will display various network-related information and statistics.
To get a list of listening ports and their owning processes under Linux, run this command:
# netstat -luntp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address  State   PID/Program name
tcp        0      0 0.0.0.0:22    0.0.0.0:*        LISTEN  1679/sshd
udp        0      0 0.0.0.0:68    0.0.0.0:*                1766/dhclient
From the output, you can see that this machine is probably a workstation, since it just has a DHCP client running along with an SSH daemon for remote access. The ports in use are listed after the colon in the Local Address column (22 for sshd and 68 for dhclient). The absence of any other listening processes means that this is probably a workstation, not a network server.
Unfortunately, the BSD version of netstat does not let us list the processes and the process IDs (PIDs) that own the listening port. Nevertheless, the BSD netstat command is still useful for listing the listening ports on your system.
To get a list of listening ports under FreeBSD, run this command:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Prevent Services from Binding to an Interface
Keep services from listening on a port instead of firewalling them.
Sometimes, you might want to limit a service to listen on only a specific interface. For instance, Apache [Hack #55] can be configured to listen on a specific interface as opposed to all available interfaces. You can do this by using the Listen directive in your configuration file and specifying the IP address of the interface:
Listen 192.168.0.23:80
If you use VirtualHost entries, you can specify interfaces to bind to on a per-virtual-host basis:
<VirtualHost 192.168.0.23>
...
</VirtualHost>
You might even have services that are listening on a TCP port but don’t need to be. Database servers such as MySQL are often used in conjunction with Apache and are frequently set up to coexist on the same server when used in this way. Connections that come from the same machine that MySQL is installed on use a domain socket in the filesystem for communications. Therefore, MySQL doesn’t need to listen on a TCP socket. To keep it from listening, you can either use the --skip-networking command-line option when starting MySQL or specify it in the [mysqld] section of your my.cnf file:
[mysqld]
...
skip-networking
...
Another program that you’ll often find listening on a port is your X11 server, which listens on TCP port 6000 by default. This port is traditionally used to enable remote clients to connect to your X11 server so they can draw their windows and accept keyboard and mouse input; however, with the advent of SSH and X11 forwarding, this really isn’t needed anymore. With X11 forwarding enabled in ssh, any client that needs to connect to your X11 server will be tunneled through your SSH connection and will bypass the listening TCP port when connecting to your X11 server.
To get your X Windows server to stop listening on this port, all you need to do is add -nolisten tcp to the command that is used to start the server. This can be tricky, though—figuring out which file controls how the server is started can be a daunting task. Usually, you can find what you’re looking for in /etc/X11.
If you’re using
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Restrict Services with Sandboxed Environments
Mitigate system damage by keeping service compromises contained.
Sometimes, keeping up with the latest patches just isn’t enough to prevent a break-in. Often, a new exploit will circulate in private circles long before an official advisory is issued, during which time your servers might be open to unexpected attack. With this in mind, it’s wise to take extra preventative measures to contain the possible effects of a compromised service. One way to do this is to run your services in a sandbox. Ideally, this minimizes the effects of a service compromise on the overall system.
Most Unix and Unix-like systems include some sort of system call or other mechanism for sandboxing that offers various levels of isolation between the host and the sandbox. The least restrictive and easiest to set up is a chroot(  ) environment, which is available on nearly all Unix and Unix-like systems. FreeBSD also includes another mechanism called jail(  ) , which provides some additional restrictions beyond those provided by chroot(  ).
If you want to set up a restricted environment but don’t feel that you need the level of security provided by a system-call-based sandboxed environment, see “Restrict Shell Environments” [Hack #20].
chroot(  ) very simply changes the root directory of a process and all of its children. While this is a powerful feature, there are many caveats to using it. Most importantly, there should be no way for anything running within the sandbox to change its effective user ID (EUID) to 0, which is root’s UID. Naturally, this implies that you don’t want to run anything as root within the jail.
There are many ways to break out of a chroot(  ) sandbox, but they all rely on being able to get root privileges within the sandboxed environment. Possession of UID 0 inside the sandbox is the Achilles heel of chroot(  ). If an attacker is able to gain root privileges within the sandbox, all bets are off. While the attacker will not be able to directly break out of the sandboxed environment, he may be able to run functions inside the exploited processes’ address space that will let him break out.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Use proftpd with a MySQL Authentication Source
Make sure that your database system’s OS is running as efficiently as possible with these tweaks.
proftpd is a powerful FTP daemon with a configuration syntax much like Apache. It has a whole slew of options not available in most FTP daemons, including ratios, virtual hosting, and a modularized design that allows people to write their own modules.
One such module is mod_sql , which allows proftpd to use a SQL database as its backend authentication source. Currently, mod_sql supports MySQL and PostgreSQL. This can be a good way to help lock down access to your server, as inbound users will authenticate against the database (and therefore not require an actual shell account on the server). In this hack, we’ll get proftpd authenticating against a MySQL database.
First, download and build the source to proftpd and mod_sql:
~$ bzcat proftpd-1.2.6.tar.bz2 | tar xf -
~/proftpd-1.2.6/contrib$ tar zvxf ../../mod_sql-4.08.tar.gz 
~/proftpd-1.2.6/contrib$ cd ..
~/proftpd-1.2.6$ ./configure --with-modules=mod_sql:mod_sql_mysql \
--with-includes=/usr/local/mysql/include/ \
--with-libraries=/usr/local/mysql/lib/
Substitute the path to your MySQL install, if it isn’t in /usr/local/mysql/.
Now, build the code and install it:
rob@catlin:~/proftpd-1.2.6$ make && sudo make install
         
Next, create a database for proftpd to use (assuming that you already have MySQL up and running):
$ mysqladmin create proftpd
         
Then, permit read-only access to it from proftpd:
$ mysql -e "grant select on proftpd.* to proftpd@localhost \
            identified by 'secret';"
         
Create two tables in the database, with this schema:
CREATE TABLE users (
userid varchar(30) NOT NULL default '',
password varchar(30) NOT NULL default '',
uid int(11) default NULL,
gid int(11) default NULL,
homedir varchar(255) default NULL,
shell varchar(255) default NULL,
UNIQUE KEY uid (uid),
UNIQUE KEY userid (userid)
) TYPE=MyISAM;

CREATE TABLE groups (
groupname varchar(30) NOT NULL default '',
gid int(11) NOT NULL default '0',
members varchar(255) default NULL
) TYPE=MyISAM;
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Prevent Stack-Smashing Attacks
Learn how to prevent stack-based buffer overflows.
In C and C++, memory for local variables is allocated in a chunk of memory called the stack. Information pertaining to the control flow of a program is also maintained on the stack. If an array is allocated on the stack and that array is overrun (that is, more values are pushed into the array than the available space allows), an attacker can overwrite the control flow information that is also stored on the stack. This type of attack is often referred to as a stack-smashing attack.
Stack-smashing attacks are a serious problem, since they can make an otherwise innocuous service (such as a web server or FTP server) execute arbitrary commands. Several technologies attempt to protect programs against these attacks. Some are implemented in the compiler, such as IBM’s ProPolice patches for GCC (http://www.trl.ibm.com/projects/security/ssp/). Others are dynamic runtime solutions, such as LibSafe. While recompiling the source gets to the heart of the buffer overflow attack, runtime solutions can protect programs when the source isn’t available or recompiling simply isn’t feasible.
All of the compiler-based solutions work in much the same way, although there are some differences in the implementations. They work by placing a canary (which is typically some random value) on the stack between the control flow information and the local variables. The code that is normally generated by the compiler to return from the function is modified to check the value of the canary on the stack; if it is not what it is supposed to be, the program is terminated immediately.
The idea behind using a canary is that an attacker attempting to mount a stack-smashing attack will have to overwrite the canary to overwrite the control flow information. Choosing a random value for the canary ensures that the attacker cannot know what it is and thus cannot include it in the data used to “smash” the stack.
When a program is distributed in source form, the program’s developer cannot enforce the use of ProPolice, because it’s a nonstandard extension to the GCC compiler (although ProPolice-like features have been added to GCC 4.x, that version of GCC isn’t in common use). Using ProPolice is the responsibility of the person compiling the program. ProPolice is available with some BSD and Linux distributions out of the box. You can check to see if your copy of GCC contains ProPolice functionality by using the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Lock Down Your Kernel with grsecurity
Harden your system against attacks with the grsecurity kernel patch.
Hardening a Unix system can be a difficult process that typically involves setting up all the services that the system will run in the most secure fashion possible, as well as locking down the system to prevent local compromises. However, putting effort into securing the services that you’re running does little for the rest of the system and for unknown vulnerabilities. Luckily, even though the standard Linux kernel provides few features for proactively securing a system, there are patches available that can help the enterprising system administrator do so. One such patch is grsecurity (http://www.grsecurity.net).
grsecurity started out as a port of the OpenWall patch (http://www.openwall.com) to the 2.4.x series of Linux kernels. This patch added features such as nonexecutable stacks, some filesystem security enhancements, restrictions on access to /proc, as well as some enhanced resource limits. These features helped to protect the system against stack-based buffer overflow attacks, prevented filesystem attacks involving race conditions on files created in /tmp, limited users to seeing only their own processes, and even enhanced Linux’s resource limits to perform more checks.
Since its inception, grsecurity has grown to include many features beyond those provided by the OpenWall patch. grsecurity now includes many additional memory address space protections to prevent buffer overflow exploits from succeeding, as well as enhanced chroot(  ) jail restrictions, increased randomization of process and IP IDs, and increased auditing features that enable you to track every process executed on a system. grsecurity also adds a sophisticated access control list system that makes use of Linux’s capabilities system. This ACL system can be used to limit the privileged operations that individual processes are able to perform on a case-by-case basis.
The gradm utility handles configuration of ACLs. If you already have grsecurity installed on your machine, feel free to skip ahead to “Restrict Applications with grsecurity” [Hack #14].
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Restrict Applications with grsecurity
Use Linux capabilities and grsecurity’s ACLs to restrict applications on your system.
Now that you have installed the grsecurity patch [Hack #13], you’ll probably want to make use of its flexible Role-Based Access Controls (RBAC) system to further restrict the privileged applications on your system, beyond what grsecurity’s kernel security features provide.
If you’re just joining us and are not familiar with grsecurity, read “Lock Down Your Kernel with grsecurity” [Hack #13] first.
To restrict specific applications, you will need to make use of the gradm utility, which can be downloaded from the main grsecurity site (http://www.grsecurity.net). You can compile and install it in the usual way: unpack the source distribution, change into the directory that it creates, and then run make && make install. This command installs gradm in /sbin, creates the /etc/grsec directory containing a default policy, and installs the manual page.
As part of running make install, you’ll be prompted to set a password that will be used for gradm to authenticate itself with the kernel. You can change the password later by running gradm with the -P option:
# gradm -P
Setting up grsecurity RBAC password
Password: 
Re-enter Password: 
Password written to /etc/grsec/pw.
You’ll also need to set a password for the admin role:
# gradm -P admin
Setting up password for role admin
Password: 
Re-enter Password: 
Password written to /etc/grsec/pw.
Then, use this command to enable grsecurity’s RBAC system:
# /sbin/gradm -E
         
Once you’re finished setting up your policy, you’ll probably want to add that command to the end of your system startup. Add it to the end of /etc/rc.local or a similar script that is designated for customizing your system startup.
The default policy installed in /etc/grsec/policy is quite restrictive, so you’ll want to create a policy for the services and system binaries that you want to use. For example, after the RBAC system has been enabled, ifconfig will no longer be able to change interface characteristics, even when run as root:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Restrict System Calls with systrace
Keep your programs from performing tasks they weren’t meant to do.
One of the more exciting features in NetBSD and OpenBSD is systrace, a system call access manager. With systrace, a system administrator can specify which programs can make which system calls, and how those calls can be made. Proper use of systrace can greatly reduce the risks inherent in running poorly written or exploitable programs. systrace policies can confine users in a manner completely independent of Unix permissions. You can even define the errors that the system calls return when access is denied, to allow programs to fail in a more proper manner. Proper use of systrace requires a practical understanding of system calls and what functionality programs must have to work properly.
First of all, what exactly are system calls? A system call is a function that lets you talk to the operating-system kernel. If you want to allocate memory, open a TCP/IP port, or perform input/output on the disk, you’ll need to use a system call. System calls are documented in section 2 of the manual pages.
Unix also supports a wide variety of C library calls. These are often confused with system calls but are actually just standardized routines for things that could be written within a program. For example, you could easily write a function to compute square roots within a program, but you could not write a function to allocate memory without using a system call. If you’re in doubt whether a particular function is a system call or a C library function, check the online manual.
You might find an occasional system call that is not documented in the online manual, such as break(  ). You’ll need to dig into other resources to identify these calls.
break(  ) is a very old system call used within libc, but not by programmers, so it seems to have escaped being documented in the manpages.
systrace denies all actions that are not explicitly permitted and logs the rejections using syslog. If a program running under
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Create systrace Policies Automatically
Let systrace’s automated mode do your work for you.
In a true paranoid’s ideal world, system administrators would read the source code for each application on their system and be able to build system-call access policies by hand, relying only on their intimate understanding of every feature of the application. Most system administrators don’t have that sort of time, though, and would have better things to do with that time if they did.
Luckily, systrace includes a policy-generation tool that will generate a policy listing for every system call that an application makes. You can use this policy as a starting point to narrow down the access you will allow the application. We’ll use this method to generate a policy for inetd .
Use the -A flag to systrace, and include the full path to the program you want to run:
# systrace -A /usr/sbin/inetd
         
To pass flags to inetd, add them at the end of the command line.
Then use the program for which you’re developing a policy. This system has ident, daytime, and time services open, so run programs that require those services. Fire up an IRC client to trigger ident requests, and telnet to ports 13 and 37 to get time services. Once you have put inetd through its paces, shut it down. inetd has no control program, so you need to kill it by using the process ID.
Checking the process list will show two processes:
# ps -ax | grep inet
24421 ??  Ixs     0:00.00 /usr/sbin/inetd 
12929 ??  Is      0:00.01 systrace -A /usr/sbin/inetd
Do not kill the systrace process (PID 12929 in this example); that process has all the records of the system calls that inetd has made. Just kill the inetd process (PID 24421), and the systrace process will exit normally.
Now check your home directory for a .systrace directory, which will contain systrace’s first stab at an inetd policy. Remember, policies are placed in files named after the full path to the program, replacing slashes with underscores.
Here’s the output of ls:
# ls .systrace
usr_libexec_identd   usr_sbin_inetd
systrace created two policies, not one. In addition to the expected policy for
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Control Login Access with PAM
Seize fine-grained control of when and from where your users can access your system.
Traditional Unix authentication doesn’t provide much granularity in limiting a user’s ability to log in. For example, how would you limit the hosts that users can come from when logging into your servers? Your first thought might be to set up TCP wrappers or possibly firewall rules [Hack #44].
But what if you want to allow some users to log in from a specific host, but disallow others from logging in from it? Or what if you want to prevent some users from logging in at certain times of the day because of daily maintenance, but allow others (e.g., administrators) to log in at any time they wish? To get this working with every service that might be running on your system, you would traditionally have to patch each of them to support this new functionality. This is where pluggable authentication modules (PAM) enters the picture.
PAM allows for just this sort of functionality (and more) without the need to patch all of your services. PAM has been available for quite some time under Linux, FreeBSD, and Solaris and is now a standard component of the traditional authentication facilities on these platforms. Many services that need to use some sort of authentication now support PAM.
Modules are configured for services in a stack, with the authentication process proceeding from top to bottom as the access checks complete successfully. You can build a custom stack for any service by creating a file in /etc/pam.d with the same name as the service. If you need even more granularity, you can include an entire stack of modules by using the pam_stack module. This allows you to specify another external file containing a stack. If a service does not have its own configuration file in /etc/pam.d, it will default to using the stack specified in /etc/pam.d/other.
There are several types of entries available when configuring a service for use with PAM. These types allow you to specify whether a module provides authentication, access control, password change control, or session setup and teardown. Right now, we are interested in only one of the types: the account type. This entry type allows you to specify modules that will control access to accounts that have been authenticated.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Restrict Users to SCP and SFTP
Provide restricted file-transfer services to your users without resorting to FTP.
Sometimes, you’d like to provide file-transfer services to your users without setting up an FTP server. This leaves the option of letting them transfer files to and from your server using SCP or SFTP. However, because of the way OpenSSH’s sshd implements these subsystems, it’s usually impossible to do this without also giving the user shell access to the system. When an SCP or SFTP session is started, the daemon executes another executable to handle the request using the user’s shell, which means the user needs a valid shell.
One way to get around this problem is to use a custom shell that is capable of executing only the SCP and SFTP subsystems. One such program is rssh (http://www.pizzashack.org/rssh/), which has the added benefit of being able to chroot(  ), enabling you to limit access to the server’s filesystem as well.
To set up rssh, first download the compressed archive from program’s web site and unpack it. Then, run the standard ./configure and make:
$ tar xfz rssh-2.3.2.tar.gz 
$ cd rssh-2.3.2 
$ ./configure && make
            
Once rssh has finished compiling, become root and run make install. You can now create an account and set its shell to rssh. Try logging into it via SSH. You’ll notice that the connection is closed before you’re able to completely log in. You should also see this before the connection is closed:
This account is restricted by rssh.
This user is locked out.

If you believe this is in error, please contact your system administrator.
You should get similar results if you try to access the account with scp or sftp, because rssh’s default configuration locks out everything. To enable SFTP and SCP, add the following lines to your rssh.conf file (the file should be located in /usr/local/etc or somewhere similar):
allowsftp
allowscp
Now, try accessing the account with sftp:
$ sftp rssh_test@freebsd5-vm1
Connecting to freebsd5-vm1...
Password:
sftp> 
This has been easy so far. Now comes the hard part: configuring
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Use Single-Use Passwords for Authentication
Use one-time passwords to access servers from possibly untrustworthy computers and to limit access to accounts.
Generally, it’s best not to use untrusted computers to access a server. The pitfalls are plentiful. However, you can mitigate some part of the risk by using one-time passwords (OTPs) for authentication. An even more interesting use for them, though, is to limit access to accounts used for file transfer.
That is, if you want to provide a file to someone or allow someone to upload a file only once, you can set up an account to use OTPs. Once the person you’ve given the password to has done her thing (and disconnected), she no longer has access to the account. This works well with rssh [Hack #18], since it prevents the user from accessing the system outside of a specified directory and from generating additional OTPs.
For this purpose, FreeBSD provides One-time Passwords in Everything (OPIE), which is thoroughly supported throughout the system. OpenBSD uses a similar system called S/Key.
Setting up an account to use OPIE under FreeBSD is fairly simple. First, run opiepasswd to create an entry in /etc/opiepasswd and to seed the OTP generator:
$ opiepasswd -c
Adding andrew:
Only use this method from the console; NEVER from remote. If you are using
telnet, xterm, or a dial-in, type ^C now or exit with no password.
Then run opiepasswd without the -c parameter.
Using MD5 to compute responses.
Enter new secret pass phrase: 
Again new secret pass phrase: 

ID andrew OTP key is 499 fr8266
HOVE TEE LANG FOAM ALEC THE
The 499 in the output is the OTP sequence, and fr8266 is the seed to use with it in generating the OTP. Once the sequence reaches 0, you’ll need to run opiepasswd again to reseed the system.
The -c option tells it to accept password input directly. Needless to say, you shouldn’t be setting this up over insecure channels; if you do, you’ll defeat the purpose of OTP. Run this from the local console or over an SSH connection only!
Then, try logging into the system remotely:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Restrict Shell Environments
Keep your users from shooting themselves (and you) in the foot.
Sometimes a sandboxed environment [Hack #10] is overkill for your needs. But if you want to set up a restricted environment for a group of users that allows them to run only a few particular commands, you’ll have to duplicate all of the libraries and binaries for those commands for each user. This is where restricted shells come in handy. Many shells include such a feature, which is usually invoked by running the shell with the -r switch. While not as secure as a system-call-based sandboxed environment, a restricted shell can work well if you trust your users not to be malicious (but worry that some might be curious to an unhealthy degree).
Some common features of restricted shells are the abilities to prevent a program from changing directories, to allow the execution of commands only using absolute pathnames, and to prohibit executing commands in other subdirectories. In addition to these restrictions, all of the command-line redirection operators are disabled. With these features, restricting the commands a user can execute is as simple as picking and choosing which commands should be available and making symbolic links to them inside the user’s home directory. If a sequence of commands needs to be executed, you can also create shell scripts owned by another user. These scripts will execute in an unrestricted environment and can’t be edited within the restricted environment by the user.
Let’s try running a restricted shell and see what happens:
$ bash -r
bash: SHELL: readonly variable
bash: PATH: readonly variable
bash-2.05b$ ls
bash: ls: No such file or directory
bash-2.05b$ /bin/ls
bash: /sbin/ls: restricted: cannot specify \Q/' in command names
bash-2.05b$ exit
$ ln -s /bin/ls .
$ bash -r 
bash-2.05b$ ls -la
total 24
drwx------    2 andrew    andrew        4096 Oct 20 08:01 .
drwxr-xr-x    4 root      root          4096 Oct 20 14:16 ..
-rw-------    1 andrew    andrew          18 Oct 20 08:00 .bash_history
-rw-r--r--    1 andrew    andrew          24 Oct 20 14:16 .bash_logout
-rw-r--r--    1 andrew    andrew         197 Oct 20 07:59 .bash_profile
-rw-r--r--    1 andrew    andrew         127 Oct 20 07:57 .bashrc
lrwxrwxrwx    1 andrew    andrew           7 Oct 20 08:01 ls -> /bin/ls
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Enforce User and Group Resource Limits
Make sure resource-hungry users don’t bring down your entire system.
Whether it’s through malicious intent or an unintentional slip, having a user bring your system down to a slow crawl by using too much memory or CPU time is no fun at all. One popular way of limiting resource usage is to use the ulimit command. This method relies on a shell to limit its child processes, and it is difficult to use when you want to give different levels of usage to different users and groups. Another, more flexible way of limiting resource usage is with the PAM module pam_limits.
pam_limits is preconfigured on most systems that have PAM [Hack #17] installed. All you should need to do is edit /etc/security/limits.conf to configure specific limits for users and groups.
The limits.conf configuration file consists of single-line entries describing a single type of limit for a user or group of users. The general format for an entry is:
            domain    type    resource    value
         
The domain portion specifies to whom the limit applies. You can specify single users here by name, and groups can be specified by prefixing the group name with an @. In addition, you can use the wildcard character * to apply the limit globally to all users except for root. The type portion of the entry specifies whether it is a soft or hard resource limit. The user can increase soft limits, whereas hard limits can be changed only by root.
You can specify many types of resources for the resource portion of the entry. Some of the more useful ones are cpu, memlock, nproc, and fsize. These allow you to limit CPU time, total locked-in memory, number of processes, and file size, respectively. CPU time is expressed in minutes, and sizes are in kilobytes. Another useful limit is maxlogins, which allows you to specify the maximum number of concurrent logins that are permitted.
One nice feature of pam_limits is that it can work together with ulimit to allow the user to raise her limit from the soft limit to the imposed hard limit.
Let’s try a quick test to see how it works. First, we’ll limit the number of open files for the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Automate System Updates
Patch security holes in a timely manner to prevent intrusions.
Updating and patching your systems in a timely manner is one of the most important things you can do to help protect them from the deluge of newly discovered security vulnerabilities. Unfortunately, this task often gets pushed to the wayside in favor of “more pressing” issues, such as performance tuning, hardware maintenance, and software debugging. In some circles, it’s viewed as a waste of time and overhead that doesn’t contribute to the primary function of a system. Coupled with management demands to maximize production, the task of keeping a system up-to-date is often pushed even further down on the to-do list.
Updating a system can be very repetitive and time-consuming if you’re not using scripting to automate it. Fortunately, most Linux distributions make their updated packages available for download from a standard online location, and you can monitor that location for changes and automatically detect and download the new updates when they’re made available. To demonstrate how to do this on an RPM-based distribution, we’ll use AutoRPM (http://www.autorpm.org).
AutoRPM is a powerful Perl script that allows you to monitor multiple FTP sites for changes. It will automatically download new or changed packages and either install them automatically or alert you so that you may do so. In addition to monitoring single FTP sites, you can also monitor a pool of mirror sites, to ensure that you still get your updates if the FTP server is busy. AutoRPM will monitor busy FTP servers and keep track of how many times connections to them have been attempted. Using this information, it assigns internal scores to each of the FTP sites configured within a given pool, with the outcome that the server in the pool that is available most often will be checked first.
To use AutoRPM, download the latest package and install it like this:
# rpm -ivh autorpm-3.3.3-1.noarch.rpm
         
Although a tarball is also available, installation is a little trickier than the typical
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 2: Windows Host Security
Hacks 23–36