Turning Off Services


You have likely heard this one as well. If you don't need a service, turn it off. We have to add one thing to thatif you cannot prove that you need the service, turn it off. Many of the customers we have worked with insisted that they needed a service, or at least thought that they did. They assumed that they needed the server. After all, it was on, so it must be necessary. A lot of services are turned on by default on many products that are not necessary to most users. If you aren't sure if you need a service, turn it off. If it doesn't break anything, then you don't need it. We can't think of a better way to learn about a service than by turning if off. If no one complains about it being off, you can file it away as a service to learn about when you have free time and focus your efforts on the services that your users do need. When in doubt, turn it off.

Using TCP Wrappers and Firewall Rules

What chapter on securing a system would be complete without a quick reminder that you should protect all your running services with TCP wrappers and firewall rules? For those who are not familiar with TCP wrappers, as this tool is referred to, this gives you the ability to monitor and filter TCP connections via IP address or hostname. For example, let's say that you want to allow SSH connections to your firewall but only from certain hosts. Of course, you could control this via firewall rules, but what if you don't have any firewall rules on your firewall yet or on the interface you want to filter out unwanted connections to the SSH port. The solution is simpleuse TCP wrappers.

Before diving into how to do this with SSH, a quick review of TCP wrappers is in order. Traditionally, TCP wrappers were used in conjunction with a "super server" such as inetd or xinetd. These super servers handle all the inbound connections to the servers they manage, such as telnet, ftp, gopher, and other services. TCP wrappers filter these connections by being invoked by the super server before the actual service itself is invoked, hence the name "TCP wrapper." The wrapper was placed "around" the service it is configured to protect. Here is a quick look at one such example from inetd.conf:

 telnet stream tcp    nowait root    /usr/sbin/tcpd  in.telnetd 

This describes how the inetd "super server" is to invoke the telnet daemon. The TCP wrapper is invoked first via the /usr/sbin/tcpd command. For xinetd, tcpd is called automatically for any TCP service, unless you disable this functionality explicitly in that service's xinetd configuration file.

For services such as ssh, support for TCP wrappers may or may not be compiled into the daemon. Never assume that it is. To determine if TCP wrapper support is available in your sshd binary, you can use this command:

 ldd /usr/sbin/sshd 

This command will tell you what libraries your sshd binary is "linked" against. What you will be looking for is the libwrap library, and the format of the ldd output will look something like this:

 libwrap.so.0 => /usr/lib/libwrap.so.0 (0x20706000) libutil.so.1 => /lib/libutil.so.1 (0x2070f000) libz.so.1 => /usr/lib/libz.so.1 (0x20712000) libnsl.so.1 => /lib/libnsl.so.1 (0x20720000) libcrypto.so.4 => /lib/libcrypto.so.4 (0x20735000) libcrypt.so.1 => /lib/libcrypt.so.1 (0x20827000) libc.so.6 => /lib/tls/libc.so.6 (0x20854000) libdl.so.2 => /lib/libdl.so.2 (0x2098a000) libgssapi_krb5.so.2 => /usr/kerberos/lib/libgssapi_krb5.so.2 (0x2098e000) libkrb5.so.3 => /usr/kerberos/lib/libkrb5.so.3 (0x209a1000) libcom_err.so.3 => /usr/kerberos/lib/libcom_err.so.3 (0x209ff000) libk5crypto.so.3 => /usr/kerberos/lib/libk5crypto.so.3 (0x20a02000) libresolv.so.2 => /lib/libresolv.so.2 (0x20a12000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x206c8000) 

Your output will probably look a little different, but don't worry about that. In this example, you can see on the first line that our sshd binary is linked against the libwrap library:

 libwrap.so.0 => /usr/lib/libwrap.so.0 (0x20706000) 

Therefore we can conclude that our sshd binary will be protected by TCP wrappersif we configure it accordingly. The only point of this exercise, running ldd against your binary, is to determine if the service you want to use TCP wrappers with is linked against the TCP wrapper library. Without the libwrap library or something like inetd or xinetd to "wrap" the service, TCP wrappers will not work with your service.

Now that you know how to invoke TCP wrappers and to test to see if your service supports TCP wrapper lookups internally, it's time to move on to how to configure a service to use TCP wrappers. When a connection comes into a service that is protected by TCP wrappers, the wrapper will first look in two files to determine if the inbound IP is allowed to connect to the service. These files are /etc/hosts.allow and /etc/hosts.deny. The hosts.allow file lists services and then hosts, IP addresses, or networks that are allowed to connect to a service, and the hosts.deny service would include the same information, only for denying access. These files look like this:

 # hosts.allow   This file describes the names of the hosts which are #               allowed to use the local INET services, as decided #               by the '/usr/sbin/tcpd' server. # in.telnetd: 10.10.10.100 # hosts.deny    This file describes the names of the hosts which are #               *not* allowed to use the local INET services, as decided #               by the '/usr/sbin/tcpd' server. ALL:ALL 

In the example here, we err on the side of caution and deny connections to all services from all hosts in case we forget to configure something correctly. Thankfully, TCP wrappers will allow for exceptions to the hosts.deny file if they are included in the hosts.allow file.

The format for any line in either of these files is simple:

 <service name>:<IP, hostname, or network>,<IP, hostname, or network>,<IP, hostname, or network> 

You can list as many records as you like after the service name. There is one reserved word, ALL, that bears pointing out in this chapter. Quite simply, it means what it saysall services or all hosts, depending on which position it's used in for either the hosts.allow or hosts.deny files. You can create a rule that relates to all services; for example, let's say you wanted to make sure that all TCP wrapped services were available to connections coming from 127.0.0.1. You would place in your hosts.allow file the following record:

 ALL:127.0.0.1 

Or if you wanted to make sure that all hosts could connect to the sshd service, you could use this record in the hosts.allow file:

 sshd:ALL 

As you can see, the format is thankfully very simple and easy for us humans to read. Even if you are using firewall rules, we suggest you also use TCP wrappers in case you make a mistake or for those times when you are doing maintenance on your firewall and might leave those services otherwise exposed. Remember that security done in layers is far more effective than relying on one line of defense.

Finally, if you use TCP wrappers, we don't recommend you filter by hostname, as DNS responses can be spoofed. Instead, when using TCP wrappers, try to use the IP addresses of the hosts you want to allow in to a service.

Because you are running a firewall, it probably seems silly to remind you that you need to apply firewall rules to protect the services running on your firewall. In a sense, it does seem a little redundant, but we'd like to point out a simple mistake we've seen people make with iptables-based firewallsconfusing INPUT and FORWARD rules. Simply put, with iptables, you have INPUT, OUTPUT, and FORWARD rules. We'll explore these in more depth later on in the book, but for our purposes here, the only types of rules we are interested in, to protect the firewall itself, are INPUT rules. FORWARD rules only apply to traffic moving "through" the firewall, and OUTPUT rules, while useful for protecting a firewall in other ways, only affect traffic moving out of the firewall itself. INPUT rules relate to traffic bound only to the firewall and to nothing else.

So, to protect the ssh service on the firewall and to only allow connections in from 10.10.1.100, you could use a simple rule like this:

 iptables -A INPUT -p tcp --dport 22 -s 10.10.1.100 -j ACCEPT 

And then this rule to deny all other traffic to the firewall's ssh port:

 iptables -A INPUT -p tcp --dport 22 -j DROP 

We'll explore the syntax of iptables in greater depth in Chapters 6 and 7. For this chapter, the only values you should be concerned with in these commands are:

 -p tcp 

This defines the IP protocol. In the present case for ssh, we're using the TCP protocol because ssh runs over the TCP protocol. The TCP protocol is covered in the next chapter.

 -s 10.10.1.100 

The -s switch defines the "source" of the connection, 10.10.1.100. This can either be an IP address or a network address, such as 10.10.1.0/24. If your intent was to allow all connections from any 10.10.1.0/24 address, such as 10.10.1.101, and 10.10.1.200 and any other IP address in the 10.10.1.0/24 network, you would use this instead:

 -s 10.10.1.0/24 

And finally, the destination port itself is defined with this switch:

 --dport 22 

This tells iptables to only apply this rule to connections bound to the destination port 22 on the firewall. Keep in mind that these are very simple rules and that you can expand greatly on these using the switches and techniques we describe in Chapters 6 and 7 and other chapters in this book. For instance, you could apply this rule to a specific interface, such as eth0 or eth1 to further control who has access to this rule by adding the -i <interface> switch for INPUT and FORWARD rules and for OUTPUT and POSTROUTING rules, the -o <switch>. The -i switch defines the incoming interface for a rule and the -o switch, the outgoing interface for a rule. So for the ssh rule described here, if you wanted to restrict ssh access not only to the 10.10.1.100 host, but also to ensure that those connections can only come in from the eth1 interface, you would add the -i eth1 switch to your ssh allow rule:

 iptables -A INPUT -i eth1 -p tcp --dport 22 -s 10.10.1.100 -j ACCEPT 

We suggest that whenever possible you define all your rules and chains with their respective interfaces to add an extra layer of security into your security model. IP addresses can be spoofed, and people do make mistakes with rules. By adding in an additional layer of specificity to your rules, by defining the interface that rule specifically applies to, you can help yourself with debugging rules and by making your firewall and network more secure.

Running Services with Least Privilege

The next important step with any system is to ensure that the services running it are running with the least amount of privilege they need to work. That means, for most services, they should not be running as root. Thankfully, many Linux vendors have gotten better in the last few years about configuring services to run as non-privileged users and going the extra mile to configure them to run in restricted file systems, such as chroots.

Some examples of common services you can run as non-privileged users:

Service

Example of user to Run as

Method

sshd

sshd

Set in the sshd_config file

ntpd

ntpd

ntpd -u ntpd

dhcpd

dhcpd

dhcpd -u dhcpd

apache

apache

Set in the httpd.conf file

named

named

Named -u named

postfix

postfix

Set in the main.conf file

sendmail

sendmail

Set in the sendmail.cf file

squid

squid

Set in the squid.conf file


You'll notice that we recommend you run each service as a different user. In the past the practice was to run them all as one common non-privileged user, such as nobody. We do not recommend this approach. It's literally putting all your eggs into one basket. If someone breaks in as the nobody user, he might have access to everything else of importance on your system also running as nobody. The goal is to compartmentalize. Every service, where possible, should run as its own user. We have additional recipes and instructions about running services with least privilege, as always, at our website, www.gotroot.com.

Restricting the File System

Aside from managing your file permissions and ensuring that you don't have certain critical files and directories set to be world or group -writable by untrusted groups and users, we also recommend isolating certain files and processes and mounting them within special file systems.

The first approach we recommend is the use of chroots, which is just short hand for "change root." A chroot simply changes the root directory for a process. For instance, if you create a directory named /chroot/named, and you chroot the named process to this directory, the named process will see the /chroot/named directory as its directory and should not able to reach any files outside of that directory. This essentially "traps" the named process inside the chrooted file system. We must pause at this point and warn you that the vanilla chroot in Linux kernels is not nearly as secure as our description implies. There are many known ways of escaping chroots under Linux with the vanilla Linux kernel.

The good news is that there are several security patches for Linux that close these holes, such as openwall (www.openwall.com) and grsecurity (www.grsecurity.net), but without these patches or other modifications to the kernel, the chroot is not as secure as it should be. With that said, even a vanilla kernel's chroot affords some security in the face of none, so do chroot your processes where you can and if you can patch your kernel, we recommend these patches. Also check with your Linux vendor to see if they have hardened the kernel to protect against chroot escapes.

The next element to securing your file systems is to move all your suid files to a special file system for suid files. If you do not know what suid and sgid files are, they are simply files set with a special file system bit that tells the Linux kernel to run that program with different or elevated privileges. For instance, the passwd command has the suid bit set on it, and the file is owned by root. This means that when you run the passwd command, the OS will "set the uid," or suid, of the process to root, the owner of the file. This means that passwd will now run as if root were running the command, which is what gives it permission to modify the /etc/passwd and /etc/shadow files. The security risk here is that if the passwd command or some other suid command has some flaw in it, you might be able to exploit that flaw with root privileges. sgid files are very similar; when the sgid bit is set on a file, it "sets the group" for the process. This means, similar to suid, that the process will then run with the group privileges of the group the file is owned by. In essence, every suid and sgid file is a potential hole in the system, so review those files carefully and only give access to suid and sgid files to trusted users, and remove those suid and sgid files you cannot prove that you need.

After you have isolated your suid and sgid files, move them to their own file system on which you can set the suid bit to active in /etc/fstab. Then set all your other mount points to nosuid.

 cat /etc/fstab /dev/hda3          /home         ext3   nosuid,nodev   1 2 /dev/hda1          /usr          ext3   nosuid,nodev   1 2 /dev/hda2          /trusted      ext3   suid           1 2 /dev/hda4          /tmp          ext3   nosuid,nodev   1 2 

By doing this you can set the rest of your file systems not to allow suid and sgid files to run. This also helps you to evaluate which suid/sgid files you have on your system and to remove the ones you cannot prove you need, which brings us to the final point about suid and sgid files. You want to inventory all of these files on your system and remove the suid and sgid bits from any programs you do not use.



    Troubleshooting Linux Firewalls
    Troubleshooting Linux Firewalls
    ISBN: 321227239
    EAN: N/A
    Year: 2004
    Pages: 169

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net