This article discusses a few of the many procedures we must take after the install is done, so that the system will not be trivial to hack.
Installing a Linux system is a relatively easy task. Most of the distributions provide automatic installation tools; these tools take care of the installation procedure from beginning to end. The problem with these automatic installation tools is that they tend to make the wrong assumptions about your system. When it comes to security considerations, these wrong assumptions can cause problems.
Securing Linux is not an easy task. You never know who is trying to gather information from your servers or even from your desktop. Some people do not even try to gather information; they just love it when they bring your web server down or have it show their latest work of art.
The first thing to do after installation is remove unneeded kernel features and services. The Linux kernel has many nice networking features; some of these features are needed by our system, some are not. Here are some kernel networking features we should compile into our kernel: IP-firewalling, Tcp Syn Cookies, Drop Source routed frames. The IP-firewalling option enables the setup of IP access lists from the command line. The Tcp Syn Cookies helps to prevent the known SYN flooding denial-of-service attack. Source-routed frames allow an attacker to bypass the normal routing decisions by specifying the routers the packet should go through within the packet data: this is a very bad idea but is sometimes needed. When compiling the kernel we need to go over all the options and enable only the options needed by our system. If a kernel option is needed we can compile it as a part of the kernel, or we can compile the kernel to support this option as a module. New kernels have new features; when compiling a new kernel we must make sure we know what each and every option we have enabled does.
We can view what processes run in our system by typing ps aux. The network sockets that are open in our system, can be displayed by typing netstat -an. Listing 1 shows some of the open sockets on a Linux machine.
The fewer services our system gives, the better. The inetd process listens on the TCP/UDP sockets specified by its configuration file. The configuration file, /etc/inetd.conf by default, tells inetd what sockets it should open and what processes it should execute once a connection is made on the socket. We should go through all services in the /etc/inetd.conf and disable those that we don't need on our system. The best way to disable a service is to put a comment sign # at the beginning of the line that configures the service we want to disable. It is a good idea to comment all /etc/inetd.conf services and use secure services instead. As an example, we can disable TELNET and FTP and enable ssh and FTP through ssh.
If we must enable a service, we should configure the service in the most secure way it can be provided. The Linux system has many tools to help an administrator provide services securely.
One of these tools is the IP-Firewalling that the kernel supports. Another tool is the tcpd, a program that monitors requests for services on the system. It logs and checks the request, and if all the checks show the client can receive the service, it will open the right service for the client. There are two files that tcpd consults when it checks for authorization: /etc/host.allow and /etc/hosts.deny. To enable tcpd checks before a service begins, we simply tell inetd to run tcpd in the configuration file. Most Linux distributions are configured to run inetd with tcpd for most services by default. Here is a line from an inetd.conf that enables the tcpd checks whenever a TELNET connection request from a client arrives:
telnet stream tcp nowait root\ /usr/sbin/tcpd /usr/sbin/in.telnetd
Whenever a telnet connection request arrives, tcpd is activated by inetd. tcpd logs the connection request via the syslogd service, then consults the hosts.allow file. If the hosts.allow file contains a match of telnetd and the requesting client, the telnet connection is considered authorized and the connection is established. If there is no such line, the /etc/hosts.deny file is consulted. There must be a line specifing telnetd and client X in the /etc/hosts.deny files if we don't want client X to be answered by our system.
There are more complicated options available in the tcpd configuration files, such as running shell commands after a certain connection request occurs. For further information on the format of the files, look at Section 5 of the manual for hosts_access and hosts_options.
Another way to disable services run via inetd is to run a shell script instead of the process. Let's have a look at a simple shell script. Please note that it is not always safe to use this method
$ cat > /usr/sbin/telnetd.new #!/bin/sh echo "Please do not use telnet to this computer.\ Use ssh only if you have the correct public key" $ chmod +x /usr/sbin/telnetd.new
We then edit the /etc/inetd.conf file so it will execute our new script instead of in.telnetd. The line should look like this:
telnet stream tcp nowait root /usr/sbin/tcpda\ telnet.newSend HUP signal to inetd , so it will read the new configuration:
kill -HUP 'ps -aux | grep inetd | awk '{print $2}' 'Test the new configuration:
$ telnet localhost Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Please do not use telnet to this computer. Use ssh only if you have the correct public key.We must remember that each of the processes run through inetd has its own configuration file. In these configuration files there are security settings that can be activated. We can set up these security settings so the services will get extra security. Take FTP, for example; we can use tcpd to check FTP requests, but as an extra security we can use the ftpaccess file to disable ftp access for root just in case. If our machine has more than one Network Interface Card, we may want to use daemons that enable us to specify on which NIC they should open a socket. This type of setting can't be done with inetd in a trivial way. Some of the FTP daemons enable these settings via the configuration file. There is another method to force a network daemon to listen only on a certain interface. Suppose our machine is connected to network A and network B, and it has two IP addresses: IA and IB. We want telnetd to listen only on IPA, so we write a simple program that opens port 23 on the IPB interface and make this program run just before telnetd. After telnetd is up and running, we can kill our little program. This won't work with every possible daemon, since certain daemons fail to start unless they can open the socket on each and every NIC on the system.
Some other networking programs do not run through inetd. These are mostly daemons that run through the rc files at system startup. When not needed, these daemons can be disabled by editing the system startup files. The mount daemon, for example, is the daemon that enables people to mount file systems from our Linux machine. If we want to disable the mount daemon completely, we should edit the rc files so the daemon will not run after the system reboots. If we want to let selected clients in our network work with parts of our file systems, we can run mountd with a restricted set of rules that will enforce our policy on the client. This will give the client a limited access to our system.
To configure the mountd restrictions, we should edit the /etc/exports file. The /etc/exports file is the file the mount daemon consults before it gives permissions to the client to mount our local file system. Not only can we limit the clients that can mount our local file systems, but we can also enforce options such as read-only, nosuid and more on the authorized clients.
Another often used program that listens for connections on the network is the lpd. The line-printer daemon opens port 515 to listen for connections. We can edit the /etc/hosts.equiv or the /etc/hosts.lpd files to disable and enable the service for some clients. With the port# argument, we can tell lpd to listen on a different port than 515; this is a good trick as long as it is not the only step we are taking to secure the service.
The X Window System is a network-based window system that enables other clients to send their application's display to our server. These applications can be dangerous since they can read our keystrokes and view the display of other applications on our X server. If we don't need the X networking support, we can run the X server with the option -nolisten tcp set. This option causes the X server to not listen to port 6000, and thus not accept connections from any client. To use this option, simply add it to the clientargs variable in the /usr/X11/bin/startx script.
If we need to display output from other machines on our X server, we can use the xhosts and xauth commands to limit the machines and users that can run applications on our X server. The xhost command is very simple: xhost + hostname or xhost - hostname.
The + sign indicates the client has permission to run applications on our X server, using the -display server:0.0 option from the command line on the client machine. The - sign indicates the client does not have permission to run applications on our server, and if a user on the client machine tries to run an X application on our server, he will get an error message indicating he is not authorized to do so.
DNS servers must be secured. There is a huge amount of information people can get easily, just by transferring our zone file to their systems. Sometimes our zone files contain the inner network addresses of our systems, router addresses and more.
BIND-8 has many neat security features. The latest version of BIND 8 is 8.2.1, and I recommend upgrading name servers to this version. It contains support of access lists (ACL) for zone query and zone transfers. In the BIND configuration file we can limit the machines that can transfer to each and every zone. One more thing we can do is to put our local network zone, if any, in a secure mode, so that named will only answer queries of names belonging to that zone to clients in our local network. There are built-in ACL names such as any and none which we can use in the named configuration file. One big advantage of the new bind versions is the logging. With version 8 we can tweak the logs to show anything we would like to see. And when it comes to security, the log is a very important issue. Listing 1 is an example of a configuration file allowing only local hosts from network 192.168.1/24 to query all zones; it also allows queries from anywhere on the network to query the outside zones only. One more thing to look at in this named configuration file is that zone transfers are only allowed to two other machines on the network and only for the outside zone.
We can play with these new features of named and disable “dns relaying” by allowing the world to query only zones for which our name server is authoritative, and enabling other queries only from our local networks. This kind of setting will disable the possibility that someone from the Internet will send recursive requests to our server.
Another nice feature in the BIND 8 is that the named can run in a chrooted environment; this means that if a hacker exploits the named, it will not have access to all of the file system, but to a very small part of it. To make named run in a chrooted environment, we can use the -t option from the command line.
The last thing about the DNS is we can make the name daemon run as a non-root user. This is a very good thing to do as in many other programs as in addition to named. By running a process as root, we actually give the process the permission to do anything in our system; we can accept that as long as the process does only what it was programmed to do in the first place. However, if someone can make this process run arbitrary code, for example, then this arbitrary code will run as root. This means any bug or buffer overflow found in this process can give the hacker a root privilege. Since we don't want to make the hacker's life easier, we can have the named run as a different user.
To accomplish this task, we first add the appropriate user and group to the system. Than we use the -u and -g options from the command line, to specify userid and groupid to the named process. [More discussion of “Securing Name Servers on UNIX” can be found in the article of that name in this issue.]
The problem with POP, IMAP and some other well-known protocols, such as TELNET and FTP, is the user name and password are sent from the client to the server in clear text. This means someone can tap the communication between the server and the client and get user names and passwords. It is also possible to make a brute force attack on the server trying to guess user names and passwords. We can take care of brute force attacks by running a server that checks for such things. Some POP and IMAP servers close the account after five bad passwords are entered; the account is opened only after a waiting period or it may have to be opened manually. There is an interesting solution to clear text passwords. Some of the services support challenge-response passwords as well as the trivial passwords.
For example, we can get a clear TELNET connection with the SKEY package. The SKEY package gives the user a “One Time Password”; even if someone taps the line and gets the password, he can't use this password again to enter the server. Another tool is stunnel which was reviewed by David Bandel in the July 1999 LJ. stunnel gives the ability to connect from client to server in a secure encrypted way for several purposes, such as SMTP, POP and more.
One could fill a book writing about sendmail security. I would like to mention only a few of many more things about sendmail. The first thing is there are alternatives out there that claim to be much more secure then sendmail. It might be worthwhile to test one of these applications. One more thing about sendmail is that with a very simple program a hacker can try to get many user names from our system by using the VRFY protocol command. The VRFY and the EXPN protocol commands should be disabled in the /etc/sendmail.cf file. To disable these commands, we should use the following line in the sendmail.cf file:
O PrivacyOptions=authwarnings\ noexpn novrfy
This option will prevent sendmail from answering to VRFY and EXPN commands. It will also cause sendmail to complain about weak security settings. One last thing I like to do with sendmail is to remove the version number from its HELO string, so the version number will not be known to the outside.
Much work needs to be done when it comes to security. We should check every day to see what new hacks have appeared and which software should be upgraded for security reasons. When installing a new application, we should always look at the security settings and set them as tight as possible. It will not make our system 100% cracker proof, but it will make it much harder for the cracker to get into our system.
Eddie Harari can be reached via e-mail at eddie@sela.co.il.