PortSentry is an adaptive packet filter. It watches for a threshold number of connects (including stealth connects) to closed ports, then blocks that IP from connecting to any port. This page documents, largely for my own use, how to install and use PortSentry, and provides (or will provide) some evaluation of it. PortSentry is part of the Abacus toolkit from Psionic; Craig Rowland wrote it. It's still under development, my RCS timestamps show mods on 06/26/01 in July of 2001.
PortSentry works as advertised. Following the documentation would be easier if the default advised setup were made clearer. I think using the fast 'portsentry -atcp' is the way to go, since it's fast and doesn't bind to any ports.
However, where would we really apply this? Most ports on a host should start out with IPchains DENY rules, unless there's a legitimate service. And many legit services should be limited to, say, your local subnet(s). For a public server, with HTTP, FTP, ssh, etc., it might well be a good thing to drop a client to all ports when suspicious activity is seen on any port. Nonetheless, most exploits and attempted exploits I've seen are not preceded by any scan -- the magic packet destined for the IIS '.ida' or LPRng format string attack simply shows up.
Defense in depth calls for using this tool, but I also should look
at some of the Snort-based stuff for adaptive firewalling. E.g,
snort2iptables, girr, hogwash, or Guardian at:
http://www.snort.org/snort-files.htm
$ wget http://www.psionic.com/tools/portsentry-1.1.tar.gz $ wget http://www.psionic.com/tools/portsentry-1.1.tar.gz.sig $ # import pgp key 0xBFB08FDA for Craig Rowland $ pgp portsentry-1.1.tar.gz.sig $ make linux $ sudo make install Creating psionic directory /usr/local/psionic Setting directory permissions Creating portsentry directory /usr/local/psionic/portsentry Setting directory permissions chmod 700 /usr/local/psionic/portsentry Copying files cp ./portsentry.conf /usr/local/psionic/portsentry cp ./portsentry.ignore /usr/local/psionic/portsentry cp ./portsentry /usr/local/psionic/portsentry Setting permissions chmod 600 /usr/local/psionic/portsentry/portsentry.ignore chmod 600 /usr/local/psionic/portsentry/portsentry.conf chmod 700 /usr/local/psionic/portsentry/portsentry Edit /usr/local/psionic/portsentry/portsentry.conf and change your settings if you haven't already. (route, etc) WARNING: This version and above now use a new directory structure for storing the program and config files (/usr/local/psionic/portsentry). Please make sure you delete the old files when the testing of this install is complete.
Most configuration is of the /usr/local/psionic/portsentry/portsentry.conf file. I've made the following changes:
To start with, we will NOT block scans: # 0 = Do not block UDP/TCP scans. # 1 = Block UDP/TCP scans. # 2 = Run external command only (KILL_RUN_CMD) BLOCK_UDP="0" BLOCK_TCP="0" And we will not used tcpd for this purpose. #KILL_HOSTS_DENY="ALL: $TARGET$"
Starting : ./portsentry -tcp and syslog shows all the ports that are being blocked. netstat -a and lsof -i show portsentry listening to all ports listed in configuation file. From another host telnet 65.100.135.241 11 provokes portsentry to say: Jul 25 10:26:14 hillburkholder portsentry[6505]: attackalert: Connect from host: win4lin/65.100.135.245 to TCP port: 11 Jul 25 10:26:14 hillburkholder portsentry[6505]: attackalert: Ignoring TCP response per configuration file setting. And I can still SSH to port 22. So, indeed, I'm not blocked. From scanner, I can STEALTH scan and ports look open: nmap -sS -p 11 65.100.136.241 11/tcp open systat Done killall portsentry
./portsentry -stcp ... Jul 25 10:34:08 hillburkholder portsentry[6521]: adminalert: ERROR: Socket 111 is in use and will not be monitored. Attempting to continue # note, in '-tcp' mode the message is Jul 25 10:45:42 hillburkholder portsentry[6554]: adminalert: ERROR: could not bind TCP socket: 111. Attempting to continue ... scan to port 11: Jul 25 10:35:06 hillburkholder portsentry[6521]: attackalert: TCP SYN/Normal scan from host: win4lin/65.100.135.245 to TCP port: 11 Jul 25 10:35:06 hillburkholder portsentry[6521]: attackalert: Ignoring TCP response per configuration file setting. stealth scan to port 1, 11: Jul 25 10:36:32 hillburkholder portsentry[6521]: attackalert: TCP SYN/Normal scan from host: win4lin/65.100.135.245 to TCP port: 11 Jul 25 10:36:32 hillburkholder portsentry[6521]: attackalert: Host: win4lin/65.100.135.245 is already blocked Ignoring Jul 25 10:36:56 hillburkholder portsentry[6521]: attackalert: TCP SYN/Normal scan from host: win4lin/65.100.135.245 to TCP port: 1 Jul 25 10:36:56 hillburkholder portsentry[6521]: attackalert: Host: win4lin/65.100.135.245 is already blocked Ignoring when a port first scanned, the host goes into the file 'portsentry.tcp' or 'portsentry.stcp' like this: 996079139 - 07/25/2001 10:38:59 Host: win4lin/65.100.135.245 Port: 27665 TCP Blocked on the first connect, then portsentry simply refers to that table for subsequent connects. ---- setting the 'BANNER' doesn't seem to do anything in -stcp, but does in -tcp (as documented). --- now, setting this to actually block: BLOCK_TCP="1" And when we do kill_route, we'll use ipchains. # ipchain support for Linux KILL_ROUTE="/sbin/ipchains -I input -s $TARGET$ -j DENY -l" # ipchains -L Chain input (policy ACCEPT): Chain forward (policy ACCEPT): Chain output (policy ACCEPT): Nmap stealth scan show as open all ports to which portsentry is bound. Nmap tcp-connect scan shows as closed (221, 243, 382, 643, 775, 795, 894, 1248, 1471, 31337) and all others as filtered. Then, a Stealth scan shows that the target host is down completely.... Syslog: Jul 25 10:48:50 hillburkholder portsentry[6554]: attackalert: Connect from host: win4lin/65.100.135.245 to TCP port: 27665 ... Jul 25 10:49:04 hillburkholder kernel: Packet log: input DENY eth0 PROTO=6 65.100.135.245:1686 65.100.135.241:296 L=60 S=0x00 I=3589 F=0x4000 T=64 SYN (#1) Jul 25 10:53:55 hillburkholder kernel: Packet log: input DENY eth0 PROTO=6 65.100.135.245:53558 65.100.135.241:80 L=40 S=0x00 I=5197 F=0x0000 T=49 (#1) [and so on]
------- advanced stealth -- ./portsentry -atcp Startup: Jul 25 10:58:41 hillburkholder portsentry[6607]: adminalert: Psionic PortSentry 1.1 is starting. Jul 25 10:58:41 hillburkholder portsentry[6608]: adminalert: Advanced mode will monitor first 1024 ports Jul 25 10:58:41 hillburkholder portsentry[6608]: adminalert: Advanced mode will manually exclude port: 113 Jul 25 10:58:41 hillburkholder portsentry[6608]: adminalert: Advanced mode will manually exclude port: 139 Jul 25 10:58:41 hillburkholder portsentry[6608]: adminalert: Advanced Stealth scan detection mode activated. Ignored TCP port: 22 ... and so on for ignoring already bound ports .... 'lsof -i' doesn't show portsentry even exits. I can connect OK to port 80, then a stealth scan blocks me immediately. If I delete the blocking from ipchains: ipchains -D input 1 Then I can scan I get lots of syslog messages in /var/log/messages since portsentry sees the host in portsentry.blocked.atcp and doesn't act on it other than reporting it. This is part of the the portsentry design so it doesn't keep acting on the same IP, but let's the action defined earlier do the job.
How fast is portsentry? An nmap scan that start at port 21 (monitored), then steps through 22, 80, 11, 139, 443, 515 (open ports), then into the monitored ports (516, 517, 518, ...) get to
ADVANCED_PORTS_TCP="1024" ADVANCED_PORTS_UDP="1024" ADVANCED_EXCLUDE_TCP="113,139" ADVANCED_EXCLUDE_UDP="520,138,137,67" IGNORE_FILE="/usr/local/psionic/portsentry/portsentry.ignore" HISTORY_FILE="/usr/local/psionic/portsentry/portsentry.history" BLOCKED_FILE="/usr/local/psionic/portsentry/portsentry.blocked" RESOLVE_HOST = "1" BLOCK_UDP="0" BLOCK_TCP="1" KILL_ROUTE="/sbin/ipchains -I input -s $TARGET$ -j DENY -l" SCAN_TRIGGER="0"
Also, I added my local network to the ignore list.
Return to Peter's Systems Administration Page.
Please feel free to contact me at pburkholder@pobox.com.