The tcpwrapper program, written by Wietse Venema, is an easy-to-use utility that you can use for logging and intercepting TCP services that are started by inetd.
The tcpwrapper program can be downloaded from the Internet using anonymous FTP . The path is:
ftp://ftp.win.tue.nl/pub/security/tcp_wrapper_XXX.tar.gz
Where XXX is the current version number. The file that you FTP will be a tar archive compressed with gunzip (often called gzip ). While you are connected to the computer ftp.win.tue.nl , you might want to pick up Venema's portmapper replacement.
Another good place to look for tcpwrapper is:
ftp://coast.cs.purdue.edu/pub/tools/tcp_wrappers
While you are connected to the coast.cs.purdue.edu machine, you can find scores of other nifty security tools and papers, so don't connect if you only have a few minutes to spare!
The tcpwrapper program is shipped standard with only a few operating systems such as BSD/OS . (It is shipped standard with Linux but is rarely configured properly.) We hope that this standard will change in the future.
The tcpwrapper program gives the system administrator a high degree of control over incoming TCP connections. The program is started by inetd after a remote host connects to your computer; then tcpwrapper does one or more of the following:
Optionally sends a "banner" to the connecting client. Banners are useful for displaying legal messages or advisories.
Performs a double-reverse lookup of the IP address, making sure that the DNS [5] entries for the IP address and hostname match. If they do not, this fact is logged. (By default, tcpwrapper is compiled with the - DPARANOID option, so the program will automatically drop the incoming connection if the two do not match, under the assumption that something somewhere is being hacked.)
[5] Domain Name Service, the distributed service that maps IP numbers to hostnames, and vice versa.
Compares the incoming hostname and requested service with an access control list, to see if this host or this combination of host and service has been explicitly denied. If either is denied, tcpwrapper drops the connection.
Uses the ident protocol ( RFC 1413)[6] to determine the username associated with the incoming connection.
[6] RFC 1413 superseded RFC 931, but the define in the code has not changed.
Logs the results with syslog . (For further information, see Chapter 10, Auditing and Logging .)
Optionally runs a command. (For example, you can have tcpwrapper run finger , to get a list of users on a computer that is trying to contact yours.)
Passes control of the connection to the "real" network daemon, or passes control to some other program that can take further action.
Transfers to a "jail" or "faux" environment where you study the user's actions.[7]
[7] We won't describe this approach further. It requires some significant technical sophistication to get right, is of limited value in most environments, and may pose some potentially significant legal problems. For further information on hacker jails, see Firewalls and Internet Security by Bill Cheswick and Steve Bellovin.
The tcpwrapper thus gives you a way to add logging to services that are not normally logged, such as finger and systat . It also allows you to substitute different versions of a service daemon depending on the calling host - or to reject the connection without providing any server at all.
The tcpwrapper system has a simple but powerful language and a pair of configuration files that allow you to specify whether or not incoming connections should be accepted. The files are /etc/hosts.allow and /etc/hosts.deny . When an incoming connection is handed to tcpwrapper , the program applies the following rules:
The file /etc/hosts.allow is searched to see if this (host, protocol) pair should be allowed.
If no match if found, the file /etc/hosts.deny is searched to see if this (host, protocol) pair should be denied.
If no match is found, the connection is allowed.
Each line in the /etc/hosts.allow and /etc/hosts.deny file has the following format:
daemon_list : client_host_list [: shell_command]
Where:
Specifies the command name ( argv[0] ) of a list of TCP daemons (e.g., telnetd ). The reserved keyword " ALL " matches all daemons; you can also use the " EXCEPT " operator (e.g., " ALL EXCEPT in.ftpd" ).
Specifies the hostname or IP address of the incoming connection. You can also use the format username@hostname to specify a particular user on a remote computer, although the remote computer must implement the ident protocol.[8] The keyword ALL matches all clients; for a full list of keywords, see Table 22.1 .
[8] And as we noted in the discussion of ident , the identification returned is not something that can always be believed.
Specifies a command that should be executed if the daemon_list and client_host_list are matched. A limited amount of token expansion is available within the shell command; see Table 22.2 for a list of the tokens that are available.
Hostname as it Appears in the File /etc/hosts.allow or /etc/hosts.deny |
Has This Effect: |
---|---|
ALL |
Matches all hosts. |
KNOWN |
Matches any IP address that has a corresponding hostname; also matches usernames when the ident service is available. |
LOCAL |
Matches any host that does not have a period (.) in its name. |
PARANOID |
Matches any host for which double-reverse hostname/IP address translation does not match. |
UNKNOWN |
Matches any IP address that does not have a corresponding hostname. Also matches usernames when ident service is not available. |
.subdomain.domain |
If the hostname begins with a period (.), the hostname will match any host whose hostname ends with the hostname (in this case, " .subdomain.domain "). |
iii. iii.jjj. iii.jjj.kkk. iii.jjj.kkk.lll. (e.g.,18. or 204.17.195.) |
If the hostname ends with a period (.), the hostname is interpreted as the beginning of an IP address. The string "18." will match any host with an IP addresses 18.0.0.1 through 18.255.255.254. The string "204.17.195." will match any host with an IP addresses 204.17.195.1 through 204.17.195.254. |
a pattern EXCEPT another pattern |
Matches any host that is matched by a pattern except those that also match another pattern. [9] |
[9] The EXCEPT operator may also be used for specifying an Internet service.
Token |
Mnemonic |
Expands to: |
---|---|---|
%a |
address |
The IP address of the client. |
%A |
address |
The IP address of the server. |
%c |
client info |
username@hostname (if username is available); otherwise, only hostname or IP address. |
%d |
daemon name |
The name of the daemon ( argv [0]). |
%h |
hostname |
The hostname of the client. (IP address if hostname is unavailable.) |
%H |
hostname |
The hostname of the server. (IP address if hostname is unavailable.) |
%p |
process |
The Process ID of the daemon process. |
%s |
server info. |
daemon@host. |
%u |
user |
The client username (or unknown) |
%% |
percent |
Expands to the "%" character. |
NOTE: The tcpwrapper is vulnerable to IP spoofing because it uses IP addresses for authentication. The tcpwrapper also provides only limited support for UDP servers, because once the server is launched, it will continue to accept packets over the network, even if those packets come from "blocked" hosts.
tcpwrapper is a powerful program that can seriously mess up your computer if it is not properly installed. It has many configuration options that are set at compile time. Therefore, before you start compiling or installing the program, read all of the documentation.
Briefly, here is what the documentation will tell you to do:
You need to decide where to place the tcpwrapper program and where to place your "real" network daemons. The documentation will give you a choice. Your first option is to name the tcpwrapper program something innocuous, like /usr/local/etc/tcpd, leave the "real" network daemons in their original locations, and modify the inetd configuration file /etc/inetd.conf . Alternatively, you can move the network daemons (such as /usr/sbin/in.fingerd ) to another location (such as /usr/sbin.real/in.fingerd ), place the tcpwrapper in the location that the daemon formerly occupied, and leave the file /etc/inetd.conf as is.
We recommend that you leave your executable programs where they currently are, and modify the /etc/inetd.conf file. The reason for this recommendation is that having changes in your system configuration clearly indicated in your system configuration files is less confusing than changing the names and/or the locations of your distributed system programs. In the long run, this option is much more maintainable. This is especially important if vendor patches expect to find the binary where it was originally stored, and overwrite it.
Having followed our advice and decided that you will modify your /etc/inetd.conf file, make a copy of the file, in case you make any mistakes later:
# cp /etc/inetd.conf /etc/inetd.conf.DIST #
Edit tcpwrapper 's Makefile so that the variable REAL_DAEMON_DIR reflects where your operating system places its network daemons. Check the other options in the Makefile to be sure they are appropriate to your needs.
Compile tcpwrapper .
Read the tcpwrapper man pages host_access and host_options . These files define the tcpwrapper host access-control language that is used by the files /etc/hosts.allow and /etc/hosts.deny.
You may wish to start off with a relatively simple set of rules - for example, allowing all services to all machines except for a small group that have been known to cause problems. But you may wish to also enable complete logging, so that you can see if particular services or sites warrant further attention.
Create your /etc/hosts.allow and /etc/hosts.deny files. If you wish to allow all TCP servers through, you do not need to create these files at all ( tcpwrapper will default to rule #3, which is to pass through all connections). If you wish to deny service from a specific machine, such as pirate.net , you could simply create a single /etc/hosts.deny file, like this:
# # /etc/hosts.deny # all : pirate.net
Alternatively, you could use the following /etc/hosts.deny , which would finger the computer pirate.net and email the result to you ( [email protected] ), whenever somebody from that network tries to initiate any connection to your machine. Note that this example uses the safe_finger command that comes with tcpwrapper ; this version of the finger command will remove control characters or other nasty data that might be returned from a finger server running on a remote machine, as well as limit the total amount of data received:[10]
[10] The safe_finger program is a replacement for your system's finger program, which automatically filters out dangerous characters allowed through by the standard versions of finger . If you don't think that your standard UNIX finger program should allow data-driven attacks, you might wish to send a letter to your UNIX vendor.
# # /etc/hosts.deny with more logging! # all EXCEPT in.fingerd : pirate.net : (/usr/local/bin/safe_finger -l @%h | \ /bin/mailx -s %d-%h [email protected]) &
Note that the /etc/hosts.deny file allows continuation lines by using the backslash (\) character.
The finger command is run for all services except in.fingerd; this restriction prevents a "feedback loop" in which a finger on one computer triggers a finger on a second computer, and vice versa. Also note that the finger command is run in the background; this mode prevents tcpwrapper from waiting until the safe_finger command completes.
Check out your /etc/syslog.conf file to make sure that tcpwrapper 's events will be logged! By default, tcpwrapper will log with LOG_ERR if a program cannot be launched, LOG_WARNING if a connection is rejected, and LOG_INFO if a connection is accepted. The logging service is LOG_MAIL , but you can change it by editing the program's Makefile .
If you make any changes to the syslog configuration file, restart syslog with the command:
# kill -1 `cat /etc/syslog.pid`
Edit your /etc/inetd.conf file so that the tcpwrapper program is invoked by inetd for each service that you wish to log and control.
Modifying the /etc/inetd.conf file is easy: simply change the filename of each program to the full pathname of the tcpwrapper program, and edit the command name of each program so that it is the complete pathname of the original network daemon.
For example, if you have a line in your original /etc/inetd.conf file that says this:
finger stream tcp nowait nobody /usr/etc/fingerd fingerd
Change it to this:
finger stream tcp nowait nobody /usr/local/bin/tcpd /usr/etc/fingerd
You may need to send a signal to the inetd daemon, or restart it, to get it to note the new configuration you have added.
Test to make sure that everything works! For example, try doing a finger of your computer; does a message get written into your system's log files? If not, check to make sure that inetd is starting the tcpwrapper , that tcpwrapper can access its configuration files, and that the syslog system is set up to do something with tcpwrapper 's messages.
Instead of specifying a particular shell command that should be executed when a (daemon, host) line is matched, tcpwrapper allows you to specify a rich set of options. To use options, you compile the tcpwrapper program with the option - DPROCESS_OPTIONS . If you compile with - DPROCESS_OPTIONS , you must change the files /etc/hosts.allow and /etc/hosts.deny files to reflect that change; the format of these files when tcpwrapper is compiled with - DPROCESS_OPTIONS is incompatible with the format of the files when tcpwrapper is compiled without the options.
If you do compile with - DPROCESS_OPTIONS , the new format of the /etc/hosts.allow and /etc/hosts.deny becomes:
daemon_list : client_host_list : option : option ...
Because you may have more than one option on a line, if you need to place a colon (:) within the option, you must protect it with a backslash (\).
The options allow you considerable flexibility in handling a variety of conditions. They also somewhat obsolete the need to have separate /etc/hosts.allow and /etc/hosts.deny files, as the words "allow" and "deny" are now option keywords (making it possible to deny a specific pair (daemon, client) in the /etc/hosts.allow file, or vice versa). Although you should check tcpwrapper 's documentation for a current list of options, most of them are included in Table 22.3
Option |
Effect |
---|---|
allow |
Allows the connection. |
deny |
Denies the connection. |
Options for dealing with sub-shells: |
|
nice nn |
Changes the priority of the process to nn . Use numbers such as +4 or +8 to reduce the amount of CPU time allocated to network services. |
setenv name value |
Sets the environment variable name to value for the daemon . |
spawn shell_command |
Runs the shell_command. The streams stdin , stdout , and stderr are connected to /dev/null to avoid conflict with any communications with the client. |
twist shell_command |
Runs the shell_command. The streams stdin , stdout , and stderr are connected to the remote client. This allows you to run a server process other than the one specified in the file /etc/inetd.conf. (Note: Will not work with some UDP services.) |
umask nnn |
Specifies the umask that should be used for sub-shells. Specify it in octal. |
user username |
Assume the privileges of username. (Note: tcpwrapper must be running as root for this option to work.) |
user username.groupname |
Assume the privileges of username and set the current group to be groupname. |
Options for dealing with the network connection: |
|
banners /some/directory/ |
Specifies a directory that contains banner files. If a filename is found in the banner directory that has the same name as the network server (such as telnetd ), the contents of the banner file are sent to the client before the TCP connection is turned over to the server. This process allows you to send clients messages, for example, informing them that unauthorized use of your computer is prohibited. |
keepalive |
Causes the UNIX kernel to periodically send a message to a client process; if the message cannot be sent, the connection is automatically broken. |
linger seconds |
Specifies how long the UNIX kernel should spend trying to send a message to the remote client after the server closes the connection. |
rfc931 [ timeout in seconds ] |
Specifies that the ident protocol should be used to attempt to determine the username of the person running the client program on the remote computer. The timeout , if specified, is the number of seconds that tcpwrapper should spend waiting for this information. |
.
Don't be afraid of using these so-called "advanced" options: they actually allow you to have simpler configurations than the /etc/hosts.allow and /etc/hosts.deny files.
NOTE: The following examples use DNS hostnames for clarity. For added security, use IP addresses instead.
Suppose you wish to allow all connections to your computer, except those from the computers in the domain pirate.net , with this very simple /etc/hosts.allow file; specify:
# # /etc/hosts.allow: # # Allow anybody to connect to our machine except people from pirate.net # all : .pirate.net : deny all : all : allow
Suppose you wish to modify your rules to allow the use of finger from any of your internal machines, but you wish to have external finger requests met with a canned message. You might try this configuration file:
# # /etc/hosts.allow: # # Allow anybody to connect to our machine except people from pirate.net # # in.fingerd : LOCAL : allow in.fingerd : all : twist /usr/local/bin/external_fingerd_message all : .pirate.net : deny all : all : allow
If you discover repeated break-in attempts through telnet and rlogin from all over the world, but you have a particular user who needs to telnet into your computer from the host sleepy.com , you could accomplish this somewhat more complex security requirement with the following configuration file:
# # /etc/hosts.allow: # # Allow email from pirate.net, but nothing else: # Allow telnet & rlogin from sleepy.com, but nowhere else # telnetd,rlogind : sleepy.com : allow telnetd,rlogind : all : deny in.fingerd : LOCAL : allow in.fingerd : all : twist /usr/local/bin/external_fingerd_message all : .pirate.net : deny all : all : allow
Here's an example that combines two possible options:
# # /etc/hosts.deny: # # Don't allow logins from pirate.net, and log attempts # telnetd,rlogind : pirate.net : spawn=(/security/logit %d deny %c %p %a %h %u)&\ : linger 10 : banners /security/banners
In the file /security/banners/telnetd, you would have the following text:
This machine is owned and operated by the Big Whammix Corporation for the exclusive use of Big Whammix Corporation employees. Your attempt to access this machine is not allowed.
Access to Big Whammix Corporation computers is logged and monitored. If you use or attempt to use a Big Whammix computer system, you consent to such monitoring and to adhere to Big Whammix Corporation policies about appropriate use. If you do not agree, then do not attempt use of these systems. Unauthorized use of Big Whammix Corporation computers may be in violation of state or Federal law, and will be prosecuted.
If you have any questions about this message or policy, contact <[email protected]> or call during EST business hours: 1-800-555-3662.
The banner will be displayed if anyone from pirate.net tries to log in over the net. The system will pause 10 seconds for the message to be fully displayed before disconnecting.
In the /security/logit shell file, you could have something similar to the script in Example 22.1 . This script puts an entry into the syslog about the event, and attempts to raise a very visible alert window on the screen of the security administrator's workstation. Furthermore, it does a reverse finger on the calling host, and for good measure does a netstat and ps on the local machine. This process is done in the event that some mischief is already occurring that hasn't triggered an alarm.
Note the -n option to the netstat command in the script. This is because DNS can be slow to resolve all the IP numbers to names. You want the command to complete before the connection is dropped; it is always possible to look the hostnames up later from the log file.
#!/bin/ksh set -o nolog -u -h +a +o bgnice +e -m # Bmon is intended to capture some information about whatever site is # twisting my doorknob. It is probably higher overhead than I need, # but... export PATH=/usr/ucb:/usr/bin:/bin:/usr/etc:/etc mkdir /tmp/root # Create /tmp/root in case it doesn't exist. print "Subject: Notice\nFrom: operator\n\n$@" | /usr/lib/sendmail security typeset daemon="$1" status="$2" client="$3" pid=$4 addr=$5 host=$6 user=$7 # For most things, we simply want a notice. # Unsuccessful attempts are warnings # Unsuccessful attempts on special accounts merit an alert typeset level=notice [[ $status != allow ]] && level=warning [[ $daemon = in.@(rshd|rlogind) && $user = @(root|security) ]] && level=alert /usr/ucb/logger -t tcpd -p auth.$level "$*" & umask 037 function mktemp { typeset temp=/security/log.$$ typeset -Z3 suffix=0 while [[ -a $temp.$suffix ]] do let suffix+=1 done logfile=$temp.$suffix chgrp security $logfile } function Indent { sed -e 's/^//' >> $logfile } exec 3>&1 >>$logfile 2>&1 date print "Remote host: $host Remote user: $user" print "" print "Local processes:" ps axg | Indent print "" print "Local network connections:" netstat -n -a -f inet | Indent print "" print "Finger of $host" safe_finger -s @$host|Indent print "" [[ $user != unknown ]] && safe_finger -h -p -m $user@$host | Indent exec >> /netc/log/$daemon.log 2>&1 print "-----------------------" print "\npid=$pid client=$client addr=$addr user=$user" print Details in $logfile date print "" # Now bring up an alert box on the admin's workstation { print "\ndaemon=$daemon client=$client addr=$addr user=$user" print Details in $logfile date print "" print -n "(press return to close window.)" >> /tmp/root/alert.$$ } > /tmp/root/alert.$$ integer lines=$(wc -l < /tmp/root/alert.$$ | tr -d ' ') xterm -display security:0 -fg white -bg red -fn 9x15 -T "ALERT" -fn 9x15B\ -geom 60x$lines+20+20 -e sh -c "cat /tmp/root/alert.$$;read nothing" /bin/rm /tmp/root/alert.$$
The configuration files we have shown earlier are simple; unfortunately, sometimes things get complicated. The tcpwrapper system comes with a utility called tcpdchk that will scan through your configuration file and report on a wide variety of potential configuration errors.
The tcpwrapper system comes with another utility program called tcpdmatch , which allows you to simulate an incoming connection and determine if the connection would be permitted or blocked with your current configuration files.
Programs like tcpdchk and tcpdmatch are excellent complements to the security program tcpwrapper , because they help you head off security problems before they happen. Wietse Venema is to be complimented for thinking to write and include them in his tcpwrapper release; other programmers should follow his example.