|
Chapter 22 Wrappers and Proxies
|
|
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.)
-
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.
-
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]
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:
-
daemon_list
-
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"
).
-
client_host_list
-
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
.
-
shell_command
-
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.
Table 22.1: Special tcpwrapper Hosts
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]
|
Table 22.2: Token Expansion Available for the tcpwrapper Shell Command
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 (
security@machine.com
), 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]
#
# /etc/hosts.deny with more logging!
#
all EXCEPT in.fingerd : pirate.net : (/usr/local/bin/safe_finger -l @%h | \
/bin/mailx -s %d-%h security@machine.com) &
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
Table 22.3: Advanced Options for tcpwrapper When Compiled with -DPROCESS_OPTIONS
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 <security@bwammix.com>
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.
|