BUY THIS BOOK

Safari Books Online

What is this?

Looking to Reprint this content?


Network Security Hacks
Network Security Hacks 100 Industrial-Strength Tips & Tools

By Andrew Lockhart

Cover | Table of Contents | Colophon


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, as 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, 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 only implement 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 the machine, 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.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Hacks #1-20
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, as 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, 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 only implement 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 the machine, 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.
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 affect (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 may 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 will 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:
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 umask 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. Much like [Hack #2] , this can be accomplished by running the 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. A world-writable directory with the sticky bit set 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 the directories that don't have their sticky bit set, run this:
# 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 permission 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 feature that is relatively new to the Linux operating system, but has been available in FreeBSD and Solaris 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 based on the criteria you provide. However, ACLs do not abandon the traditional permission system completely. ACLs may 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 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.
To modify or remove ACLs, use the setfacl command. To modify an ACL, the -m option is used, followed by an ACL specification and a filename or list of filenames. You can delete an ACL by using the -x option and specifying an ACL or list of ACLs.
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-in.
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 #100] . 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, ls -lo can be used to view the attributes, and chflags can be used to modify them. At the time of this writing, file attributes in Linux are available only when using the ext2 and ext3 filesystems. There are also kernel patches available for attribute support in XFS and reiserfs.
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
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 giving away full root access. It 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 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 that 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), then take advantage of
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 be familiar with the software you are installing. You probably will not have the time, knowledge, or resources to actually go through the source code for all of the software that you are installing. However, verifying that the software you are compiling and installing is what the authors intended it to be can go a long way toward preventing the widespread distribution of Trojan horses. Recently, several pivotal pieces of software (such as tcpdump, LibPCap, Sendmail, and OpenSSH) have had Trojaned versions distributed. Since this is an increasingly popular vector for attack, verifying your software is critically important.
Why is this even an issue? Unfortunately, it takes a little bit of effort to verify software before installing it. Either through laziness or ignorance, many system administrators overlook this critical step. This is a classic example of "false" laziness, as 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: many times, software packages don't even come with a signature to use for verifying the legitimacy of what you've downloaded. Often, signatures are available right along with the source code, but in order to verify the code, you must then hunt through the 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 that should be done after a fresh operating system install is to 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 #42] ) 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 program that will do what we need 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:
# 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, and 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
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 #50] 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 may 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, you don't need to have MySQL listening on a TCP socket. To do this, 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
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 may be open to unexpected attack. With this in mind, it's wise to take extra preventative measures to contain the aftermath of a compromised service. One way to do this is to run your services in sandbox environments. Ideally, this lets the service be compromised while minimizing the effects 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. In addition to chroot(), FreeBSD includes another mechanism called jail( ) , which provides a few more restrictions beyond those provided by chroot().
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 UID (EUID) to 0, which is root's UID. Naturally, this implies that you don't want to run anything as root within the jail. If an attacker is able to gain root privileges within the sandbox, then all bets are off. While the attacker will not be able to directly break out of the sandbox environment, it does not prevent him from running functions inside the exploited processes' address space that will let him break out. There are many ways to break out of a chroot( ) sandbox. However, they all rely on being able to get root privileges within the sandboxed environment. The Achilles heel of chroot() is possession of UID 0 inside the sandbox.
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 proftp 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 back-end 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/
(Naturally, 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 provides), 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 an otherwise innocuous service (such as a web server or FTP server) can be made to execute arbitrary commands. Several technologies have been developed that attempt to protect programs against these attacks. Some are implemented in the compiler, such as IBM's ProPolice (http://www.trl.ibm.com/projects/security/ssp/) and the Stackguard (http://www.immunix.org/stackguard.html) versions of GCC. Others are dynamic runtime solutions, such as LibSafe (http://www.research.avayalabs.com/project/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. By choosing a random value for the canary, the attacker cannot know what it is and thus cannot include it in the data used to "smash" the stack.
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. It 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 a user to only seeing his 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 adds a sophisticated access control list (ACL) 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.
Configuration of ACLs is handled through the gradm utility. If you already have
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 patches, you'll probably want to make use of its flexible ACL 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 [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 will install gradm in /sbin, create the /etc/grsec directory containing a default ACL, and install the manpage.
After gradm has been installed, the first thing you'll want to do is create a password that gradm will use to authenticate itself to the kernel. You can do this by running gradm with the -P option:
# gradm -P
Setting up grsecurity ACL password
Password: 
Re-enter Password: 
Password written to /etc/grsec/pw.
To enable grsecurity's ACL system, use this command:
# /sbin/gradm -E
         
Once you're finished setting up your ACLs, you'll probably want to add that command to the end of your system startup. You can do this by adding it to the end of /etc/rc.local or a similar script that is designated for customizing your system startup.
The default ACL installed in /etc/grsec/acl is quite restrictive, so you'll want to create ACLs for the services and system binaries you want to use. For example, after the ACL system has been enabled, ifconfig will no longer be able to change interface characteristics, even when run as root:
# /sbin/ifconfig eth0:1 192.168.0.59 up
SIOCSIFADDR: Permission denied
SIOCSIFFLAGS: Permission denied
SIOCSIFFLAGS: Permission denied
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 new 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 manpages.
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 may 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() in particular 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 rejection 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!
Automated Systrace Policy Creation
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 every 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, 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 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
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 where your users can access your system.
In traditional Unix authentication there is not much granularity available 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 #33] and [Hack #34] . But what if you wanted to allow some users to log in from a specific host, but disallow others from logging in from it? Or what if you wanted to prevent some users from logging in at certain times of the day because of daily maintenance, but allow others (i.e., 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 PAM enters the picture.
PAM, or pluggable authentication modules, 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, an entire stack of modules can be included 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.
When configuring a service for use with PAM, there are several types of entries available. These types allow one 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. In addition to the service-specific configuration files, some modules have extended configuration information that can be specified in files within 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!
Restricted Shell Environments
Keep your users from shooting themselves (and you) in the foot.
Sometimes a sandboxed environment [Hack #10] is overkill for your needs. If you want to set up a restricted environment for a group of users that only allows them to run 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 sandbox environment, it 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 ability to prevent a program from changing directories, to only allow the execution of commands 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 a nonrestricted environment and can't be edited within the 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 `/' 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 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. Single users may be specified here by name, and groups can be specified by prefixing the group name with an @. In addition, the wildcard character * may be used to apply the limit globally to all users except for root. The type portion of the entry specifies whether the limit is a soft or hard resource limit. Soft limits may be increased by the user, whereas hard limits can be changed only by root. There are many types of resources that can be specified 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.
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 a system in a timely manner is one of the most important things you can do to help protect your systems 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, 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. We 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 in spite of a busy FTP server. This feature is especially nice in that AutoRPM will monitor busy FTP servers and keep track of how many times a connection to them has 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 install AutoRPM, download the latest package and install it like this:
# rpm -ivh autorpm-3.3-1.noarch.rpm
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
This chapter shows you some ways to keep your Windows system up-to-date and secure, thereby making your network a safer place to work (and have fun). Although many may scoff at the mention of Windows and security in the same sentence, you actually can make a Windows system fairly secure without too much effort.
One of the main reasons that Windows gets a bad rap is the poorly administered state in which Windows machines seem to be kept. The recent deluge of worm and virus attacks that have brought down many a network shows this to hold true. A lot of this can be traced back to the "ease" of administration that Windows seems to provide by effectively keeping the Windows administrator out of the loop about the inner workings of her environment—effectively wresting control from the system administrator's hands.
This chapter seeks to remedy that to some degree by showing you ways to see exactly what your server is really doing. While this may seem old hat to a Unix sysadmin, getting details on open ports and running services is often a new concept to the average Windows administrator. In addition, this chapter shows you how to disable some Windows "features," such as sharing out all your files automatically and truncating log files. You'll also learn how to enable some of the auditing and logging features of Windows, to give you early warning of possible security incidents (rather than waiting for the angry phone call from someone at the wrong end of a denial-of-service attack originating from your network).
Make sure your Windows servers have the latest patches installed.
Keeping a network of systems patched and up-to-date is hard enough in Unix, but it can be even more difficult on Windows systems. A lack of robust built-in scripting and remote access capabilities makes Windows unsuitable for automation. Nevertheless, before you even attempt to update your systems, you need to know which updates have been applied to each system; otherwise, you might waste time and effort updating systems that don't need it. Clearly, this problem gets more difficult as the number of systems that need to be managed increases. We can avoid much of the extra work of manually updating systems 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!
Hacks #21-30
This chapter shows you some ways to keep your Windows system up-to-date and secure, thereby making your network a safer place to work (and have fun). Although many may scoff at the mention of Windows and security in the same sentence, you actually can make a Windows system fairly secure without too much effort.
One of the main reasons that Windows gets a bad rap is the poorly administered state in which Windows machines seem to be kept. The recent deluge of worm and virus attacks that have brought down many a network shows this to hold true. A lot of this can be traced back to the "ease" of administration that Windows seems to provide by effectively keeping the Windows administrator out of the loop about the inner workings of her environment—effectively wresting control from the system administrator's hands.
This chapter seeks to remedy that to some degree by showing you ways to see exactly what your server is really doing. While this may seem old hat to a Unix sysadmin, getting details on open ports and running services is often a new concept to the average Windows administrator. In addition, this chapter shows you how to disable some Windows "features," such as sharing out all your files automatically and truncating log files. You'll also learn how to enable some of the auditing and logging features of Windows, to give you early warning of possible security incidents (rather than waiting for the angry phone call from someone at the wrong end of a denial-of-service attack originating from your network).
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 Servers for Applied Patches
Make sure your Windows servers have the latest patches installed.
Keeping a network of systems patched and up-to-date is hard enough in Unix, but it can be even more difficult on Windows systems. A lack of robust built-in scripting and remote access capabilities makes Windows unsuitable for automation. Nevertheless, before you even attempt to update your systems, you need to know which updates have been applied to each system; otherwise, you might waste time and effort updating systems that don't need it. Clearly, this problem gets more difficult as the number of systems that need to be managed increases. We can avoid much of the extra work of manually updating systems by using the HFNetChk tool, which was originally a standalone program from Shavlik Technologies. It is now a part of Microsoft's Baseline Security Analyzer (http://download.microsoft.com/download/8/e/e/8ee73487-4d36-4f7f-92f2-2bdc5c5385b3/mbsasetup.msi) and is available through its command-line interface, mbsacli.exe.
Not only can HFNetChk remotely check the status of Windows Server 2003 and Windows XP/2000/NT, but it can also check whether critical updates for IIS, SQL Server, Exchange Server, Media Player, and Internet Explorer have been applied. Although it can only check the update status of a system (and won't actually bring the system up-to-date), it is still an invaluable timesaving tool.
HFNetChk works by downloading a signed and compressed XML file from Microsoft that contains information on all currently available updates. This information includes checksums and versions of files covered by each update, as well as the registry keys modified by each update. Additional dependency information is also included. When scanning a system, HFNetChk will first scan the registry for the keys that are associated with the most current set of updates available for the current system configuration. If any of these registry keys are missing or do not match what is contained in the XML file, it will flag the update as not having been installed. If the registry key for an update is present and matches the information in the XML file,
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Get a List of Open Files and Their Owning Processes
Look for suspicious activity by monitoring file accesses.
Suppose you're looking at the list of processes in the task manager one day after noticing some odd behavior on your workstation, and you notice a process you haven't seen before. Well, what do you do now? If you were running something other than Windows, you might try to determine what the process is doing by looking at the files it has open. Unfortunately, Windows doesn't provide a tool to do this.
Sysinternals makes an excellent tool called Handle, which is available for free at http://www.sysinternals.com/ntw2k/freeware/handle.shtml. Handle is a lot like lsof [Hack #8] , but it can list many other types of operating resources, including threads, events, and semaphores. It can also display open registry keys and IOCompletion structures.
Running handle without any command-line arguments will list all open file handles on the system. You can also specify a filename, which will list the processes that are currently accessing it, by typing this:
C:\> handle 
            filename
         
Or you can list only files that are opened by a particular process—in this case Internet Explorer:
C:\> handle -p iexplore
Handle v2.10
Copyright (C) 1997-2003 Mark Russinovich
Sysinternals - www.sysinternals.com

----------------------------------------------------------------------------
IEXPLORE.EXE pid: 688 PLUNDER\andrew
   98: Section       \BaseNamedObjects\MTXCOMM_MEMORY_MAPPED_FILE
   9c: Section       \BaseNamedObjects\MtxWndList
  12c: Section       \BaseNamedObjects\__R_0000000000d4_SMem_  _
  18c: File          C:\Documents and Settings\andrew\Local Settings\Temporary Internet 
Files\Content.IE5\index.dat
  198: Section       \BaseNamedObjects\C:_Documents and Settings_andrew_Local 
Settings_Temporary Internet Files_Content.IE5_index.dat_3194880
  1a0: File          C:\Documents and Settings\andrew\Cookies\index.dat
  1a8: File          C:\Documents and Settings\andrew\Local Settings\History\History.IE5\
index.dat
  1ac: Section       \BaseNamedObjects\C:_Documents and Settings_andrew_Local 
Settings_History_History.IE5_index.dat_245760
  1b8: Section       \BaseNamedObjects\C:_Documents and 
Settings_andrew_Cookies_index.dat_81920
  228: Section       \BaseNamedObjects\UrlZonesSM_andrew
  2a4: Section       \BaseNamedObjects\SENS Information Cache
  540: File          C:\Documents and Settings\andrew\Application 
Data\Microsoft\SystemCertificates\My
  574: File          C:\Documents and Settings\All Users\Desktop
  5b4: Section       \BaseNamedObjects\mmGlobalPnpInfo
  5cc: File          C:\WINNT\system32\mshtml.tlb
  614: Section       \BaseNamedObjects\WDMAUD_Callbacks
  640: File          C:\WINNT\system32\Macromed\Flash\Flash.ocx
  648: File          C:\WINNT\system32\STDOLE2.TLB
  6a4: File          \Dfs
  6b4: File          C:\Documents and Settings\andrew\Desktop
  6c8: File          C:\Documents and Settings\andrew\Local Settings\
Temporary Internet Files\Content.IE5\Q5USFST0\softwareDownloadIndex[1].htm
  70c: Section       \BaseNamedObjects\MSIMGSIZECacheMap
  758: File          C:\WINNT\system32\iepeers.dll
  75c: File          C:\Documents and Settings\andrew\Desktop
  770: Section       \BaseNamedObjects\RotHintTable
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
List Running Services and Open Ports
Check for remotely accessible services the Windows way.
Unix makes it quick and easy to see which ports on a system are open, but how can you do that on Windows? Well, with FPort from Foundstone (http://www.foundstone.com/resources/index_resources.htm) it's as quick and easy as running good old netstat.
FPort has very few command-line options, and those deal mostly with specifying how you'd like the output sorted. For instance, if you want the output sorted by application name, you can use /a; if you want it sorted by process ID, you can use /i. While it may not be as full of features as