Psionic PortSentry - Port scan detection and active defense.
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

$Id: README.install,v 1.30 2002/04/08 17:24:14 crowland Exp crowland $

E-Mail : sentrysupport@psionic.com
Date   : 04-08-2002
Version: 2.0b1

Introduction
=-=-=-=-=-=-

This is the "long" install version. You should read this file if you want
to understand everything going on and the method to the madness in the
program logic. Skip to Install down below if you don't care about this.

PortSentry is part of Psionic's TriSentry Suite of security products. If you like
this tool you will really like our other products. Check our website at:

http://www.psionic.com

PortSentry has a number of options to detect port scans, when it finds one it
can react in the following ways:

	- A log indicating the incident is made via syslog()
	- The target host is automatically dropped into /etc/hosts.deny
	  for TCP Wrappers
	- The local host is automatically re-configured to route all
	  traffic to the target to a dead host to make the target system
	  disappear.
	- The local host is automatically re-configured to drop all
	  packets from the target via a local packet filter.


The purpose of this is to give an admin a heads up that their host is
being probed. There are similar programs that do this already (klaxon,
etc.) We have added a little twist to the whole idea (auto-blocking), plus
extensive support for stealth scan detection.

PortSentry 2.x has been re-written to use libpcap. The old "classic" modes
that used bound ports to detect attacks has been removed. If you liked the
"classic" modes, please use the 1.1 version of PortSentry.

Install
=-=-=-=

Step ONE:

Pull the portsentry_config.h file into your editor and make sure the
following are to your liking:

CONFIG_FILE - The path to the PortSentry configuration file.
WRAPPER_HOSTS_DENY - The path and name of TCP wrapper hosts.deny file.
SYSLOG_FACILITY - The syslog facility for PortSentry to use.
SYSLOG_LEVEL - The syslog level to send messages.

We suggest not changing any of these options unless you know what you
are doing.

NOTE: For advanced users, you may wish to change the SYSLOG_FACILITY from
LOG_DAEMON to LOG_LOCAL0 (or one of the other LOCAL reporting facilities).
This will allow you to edit the syslog.conf file and drop PortSentry
messages direcly to its own file on the system for separate monitoring.

SECOND NOTE: DO NOT DELETE THE "#" SIGNS FROM THIS FILE. They are NOT comments,
they are required by the C compiler to pre-process the headers. If you delete
the "#" signs you will get compile errors.

THIRD NOTE: Read the SECOND NOTE again. We get a lot of questions from people who
delete the "#" signs and then can't compile the program. Note that the
portsentry_config.h will probably go away as the 2.x version exits beta.


Step TWO:

Next, pull in portsentry.conf into your editor and check/change the
following options:

INTERFACE - The interface name you want to monitor. Most people can leave
this as "auto" and PortSentry will figure out the primary interface to monitor.
Others though may have multiple interfaces and want to watch only one (i.e.
a firewall external interface). In this case you can set the interface name
manually. Don't include "/dev/eth0" to watch eth0, just put in the interface
name "eth0", etc. in here. PortSentry can only watch one interface at a time
so don't put in multiple names.

INTERFACE_ADDRESS - PortSentry needs to know the IP Address of the Interface
you are watching. This version does not figure this out automatically, but
should in the near future. If you don't put in the address then PortSentry will
not work properly. This is not a great solution for DHCP or dynamic IP users, but
will be fixed as the beta matures. For now you'll have to do this manually for
static IPs, or write a quick script to do it automatically for you on system
startup.

TCP_PORTS - A comma delimited string of TCP ports you want PortSentry to
listen to. This string can NOT have any spaces in it. You can put in as
many sockets as you want but the Berkely Packet Filter (BPF) length may get
too big and cause problems. If this happens you'll see an error message in the
log file and should shorten the sting length.

UDP_PORTS - The same as above, except for UDP ports.

IGNORE_FILE - The path to the file that contains IP addresses of hosts you
want to always be ignored. This will be explained later.

BLOCKED_FILE - The path to the file that contains the IP addresses of
blocked hosts.

RESOLVE_HOST - This option turns off DNS resolution for hosts. If you have a
slow DNS server it may be more effective to turn off resolution. Also if you have
this turned on an attacker could see the DNS requests coming back to them and know
you are monitoring connections. Default is to leave this off.

BLOCK_UDP - This option disables all automatic responses to UDP probes.
Because UDP can be easily forged, it may allow an attacker to start a
denial of service attack against the protected host, causing it to block
all manner of hosts that should normally be left alone. Setting this option
to "0" will disable all responses, although the connects are still logged.
This option is mainly useful for Internet exposed hosts. For internal hosts
you should leave this enabled. If someone internally is firing spoofed
packets at you, then you have a much bigger problem than a denial of service.

BLOCK_TCP - Same as above, but for TCP. For stealth scan detection modes the
UDP warning applies as well:

	An attacker can cause you to block hosts you don't want to
	through packet forgery.

Every few months we get someone who writes and tells us this obvious point.
Yes, we know about packet forgery, denial of service, etc. We just don't
consider it as big of a risk compared to a system compromise so we leave
this option enabled for most hosts (except certain hosts prone to being
beat up on [firewall]). Read README.stealth for a more in-depth answer
to what you should do.

KILL_ROUTE - This is the command to run to drop the offending route if
an attack is detected. This is the *full path* to the route command
along with the necessary parameters to make the command work. The macro
$TARGET$ will be substituted with the attacking host IP and is
REQUIRED in this option. Your gateway should be a *dead host* on the
local subnet. On some systems though you can just put in the localhost
address (127.0.0.1) and this will probably work. All packets from the
target host will get routed to this address so don't mess this up.
More modern route commands will include a "-blackhole" or "-reject" flag.
Check your man(1) pages and if your route command supports this feature
you should use it (although we recommend using packet filtering
instead, see below).

Also be aware that can create what is known as an "asynchronous
route" which basically means packets enter your host via one route
and are sent out on another (dead) route. This works OK for full
TCP connect requests, but for UDP and stealth scan modes it
still allows packets to activate PortSentry and you may get a
series of "already blocked" alarms by PortSentry. For UDP scans
this method prevents ICMP messages from returning to the attacker
so all ports appear open. However, if the attacker is performing
an actual exploit with UDP the drop route method will not work.
The asynchronous route allows the packet to hit the system and the
attacker could perform a "blind" attack with UDP if they know what
the responses are going to be.

By far the best method is to use the local packet filter (such as Linux
ipchains/iptables, BSD ipfw, etc). This is a much cleaner solution and is
detailed in the config file. The macro $PORT$ will substitute the port
that was connected to by the attacker, but this is NOT required for this
option. The macro $MODE$ reports what mode the blocking occurred in
(tcp, udp) but is also NOT required.

KILL_HOSTS_DENY - This is the format of the string to drop into the
hosts.deny file that TCP wrappers uses. Again the $TARGET$ macro is
expanded out to be the IP of the attacker and is required. You can
also drop in any TCP wrapper escape codes here as well (%h, twist,
etc). The macro $PORT$ will substitute the port that was connected to
by the attacker, but this is NOT required for this option. The macro
$MODE$ reports what mode the blocking occurred in (tcp, udp) but is also
NOT required.

KILL_RUN_CMD - This is a command you want run *before* the route
is dropped to the attacker. You can put in any program/script you want
executed when an attack is detected. WE NEVER RECOMMEND PUTTING IN
RETALIATORY ACTION AGAINST AN ATTACKING HOST. Virtually every time you're
are port scanned the host doing the scanning has been compromised itself.
Therefore, if you retaliate you are probably attacking an innocent(?)
party. Also the goal of security is to make the person GO AWAY. You don't
want to irritate them into making a personal vendetta against you.
Remember, even a 13 year old can run a [insert favorite D.O.S. program
here] attack against you from their Windows box to make your life
miserable. As above, the $TARGET$, $PORT$, and $MODE$ macros are
available to you but they are not required with this option as above.

KILL_RUN_CMD_FIRST - Setting this to "0" makes the command above run
before the route is dropped. Setting it to "1" makes the command run
after the blocking has occurred.

SCAN_TRIGGER - PortSentry has a state engine that will remember hosts
that connected to it. Setting this value will tell PortSentry to allow X
number of grace port hits before it reacts. This will detect both
sequential and random port sweeps. The default is 0 which will react
immediately. A setting of 1 or 2 will reduce false alarms, anything
higher is probably too much as anything more than 3 hits to different
ports is pretty suspicious behavior. Usually you can leave this at 0
without any consequence.

Step THREE:

Pull the portsentry.ignore file into your editor and add in any host you
want to have ignored if it connects to a tripwired port. This should always
contain at least the localhost (127.0.0.1) and the IP's of the local
interfaces. We would *not* recommend putting in every machine IP on your
network, but you can use a netmask to do this. Format for this is:

<IP Address>/<Netmask Bits>

192.168.2.0/24
192.168.0.0/16
etc.

We don't recommend ignoring too much. It may be important for you to see
who is connecting to you, even if it is a "friendly" machine. This can
help you detect internal host compromises faster.

To answer your paranoia, yes this does happen and we've heard of *several*
cases of admins ignoring too much and getting hacked by their *own compromised
machines*


Step FOUR:

Compile. Type make and pick your system type and allow it to build and install.
The default directory is /usr/local/psionic/portsentry2. If you don't like
this directory just edit the Makefile and make sure your portsentry.conf and
portsentry_config.h files reflect the new path.

Type make install after the build to have it copy files to your install
directory.

Step FIVE:

Start up PortSentry. Two ways to do this after install:

1) cd to the install directory (/usr/local/psionic/portsentry2, etc.) and 
type:

./portsentry

2) Run the command directly:

/usr/local/psionic/portsentry2/portsentry


Stealth TCP scan detection mode [BETA]

PortSentry will use monitor all incoming packets. If an incoming
packet is destined for a monitored port listed in TCP_PORTS it will react
to block the host. This method will detect connect() scans, SYN/half-open
scans, XMAS scan, FIN scans, NULL scans, etc. UDP/Stealth scan warnings apply
(read: README.stealth).

"Stealth" UDP scan detection mode [BETA]

This operates the same as the TCP stealth mode above. UDP ports need to be
listed and they are then monitored. This does not bind any sockets, and
while not really "stealth" scan detection (doesn't usually apply to UDP),
it operates in a similar manner (reacts to *any* UDP packet). UDP/Stealth
scan warnings apply (read: README.stealth).

** Advanced Logic Mode ** - PortSentry is intelligent about how it monitors
ports. For some protocols such as FTP the client actually opens up ports
in the ephemeral range (1024-65535) and the server then connects *back* to
you. This would normally cause the port scanner to activate. PortSentry though
will look at the incoming connection and determine if it is destined for
one of these "temporary" bindings. If it is, then the connection is
ignored for that one time. As soon as the connection is torn down the
window closes and full protection is back again. This is in fact a
rudimentary stateful inspection engine. UDP/Stealth scan warnings apply
(read: README.stealth).


Test the install:

Tail the local log and you should see several PortSentry initialization
messages.

A successful startup looks like this:

Mar  5 21:16:00 nemesis portsentry[2286]: adminalert: Monitoring interface
eth0 and address: 10.1.1.1
Mar  5 21:16:00 nemesis portsentry[2286]: adminalert: Monitoring TCP ports:
1,11,110,143,635,1080
. . .
Mar  5 21:16:00 nemesis portsentry[2286]: adminalert: PortSentry is initialized
and monitoring.

************************************************************************
** The last line indicates the PortSentry is properly initialized, if **
** you don't see it then something failed. 			      **
************************************************************************

Now you can go to another host and telnet to a booby-trapped port.

DO NOT DO THIS FROM YOUR ONLY ACCESS POINT TO THE PROTECTED HOST
BECAUSE YOU WILL BLOCK YOURSELF OFF COMPLETELY IF IT WORKS.

Read the above again. We get a fair number of people who write something
like this to us (a dramatization, but you get the idea):

"hi, i installed port sentry on my web server installed on an isolated oil
platform in the north atlantic that's only accessible by helicopter for one
week out of the year. i then went to the only admin system on the entire
planet that can connect to it and tested port sentry by telneting to a protected
port. now it looks like port sentry worked because i can't get to my box but
now i need to get to my box. can you help me?"

Anyway...

You should immediately see something like:

Mar  5 21:17:39 packetmonkey portsentry[2286]: attackalert: Host 192.168.2.15
has been blocked via wrappers with string: "ALL: 192.168.2.15"
Mar  5 21:17:39 packetmonkey portsentry[2286]: attackalert: TCP SYN scan from
host 192.168.2.15/192.168.2.15 to TCP port: 143 from TCP port: 31337

If you disconnect and try to telnet back again you should find that the
target system is now unreachable. Congratulations you are now operational.

If you are running Logcheck this will show up in the next pass and
it should be screaming at you.

If you do a netstat -rn you will see the suspect host pointed at the dead
route you supplied (unless using a packet filter, which is what we
recommend).

Drop the PortSentry commands in a startup file and get back to work as
you are done.

How will it help?

Here are some ideas:

	- Run as a UDP service on port 69 to catch TFTP probes.
	- Run as a UDP service on port 161,162 to catch SNMP probes.
	- Run as a UDP service in the port range 32000-33000 to catch RPC
	  probes.
	- Run as a TCP service on port 143 to catch IMAP probes.
	- Run as a TCP service on ports 11,15 to catch netstat/systat
	  probes.
	- etc.

The fact is that PortSentry reacts quickly enough that a port scan of your
host by an attacker will be stopped within one second after hitting any
tripwired port.

For any type of UDP scan it will prove highly irritating for the person
trying to scan you as all the ports will likely appear "open." For TCP scans
the attacker will simply get no response whatsoever.

Safety
=-=-=-

If we missed anything in the program's safety considerations we would very
much like to hear about it before you post it to BugTraq :).

Messages
=-=-=-=-

To the best we could, all states/errors/successes and unknowns are written
to the syslog. The following tags identify each one:

adminalert: - Some message indicating the status of the PortSentry.
securityalert: - A message indicating a security relevant event occurred.
attackalert: - A host has tripped a sensor and an action was performed.


Files
=-=-=

As it stands now, all hosts are dropped into the portsentry.blocked file
when they are blocked as well as a portsentry.history file. The blocked file
is erased each time PortSentry is restarted. The history file is simply
appended to and can be used as a record of all hosts that have been blocked
to date.

After a period of time elapses you may wish to delete the local dead route
to the offender and keep them in the hosts.deny file. This is solely your
choice. If you wish to re-enable blocking should the offender return, just
re-start PortSentry or delete the individual entry from the blocked file.

If you need to restore the route to the blocked host on most systems you can
simply delete the route like so:

Linux:

route del <ip_address> reject

Others:

route delete <ip_address> <dead_route>

Or you can simply flush your packet filters.

That's about it. We highly recommend you use Logcheck to keep an eye
on things in the log files as well so you can detect other problems, and
see what the PortSentry is saying to you. You can find this program at:

http://www.psionic.com

Thanks for reading this and write if you have any questions or comments.


Thanks,


-- Craig

Psionic Technologies, Inc.
sentrysupport@psionic.com

