sshdfilterrc(5)

NAME
sshdfilterrc - configuration file for sshd brute force blocker

SYNOPSIS
sshd wrapper script that generates iptables DROP rules when sshd reports any of i) no identify string sent by client ii) attempted login to a non-existant account iii) mupliple password failures for a valid account. DROP rules are added in realtime. There are two install routes, either as an sshd wrapper, in which case sshd messages are read directly by sshdfilter, or as a separate standalone program that parses sshd output via a didicated syslog named pipe.

DESCRIPTION
sshdfilter blocks the frequent brute force attacks on ssh daemons, it does this by directly reading the sshd logging output (or syslog output) and generating iptables rules, the process can be quick enough to block an attack before they get a chance to enter any password at all. The blocking policy is defined by a list of blockrules largely by user name or by the type of user name.

There are two install routes, the old style sshdfilter starts sshd itself, having started sshd with the -e and -D options. The newer style uses a syslog configuration line that writes sshd messages to a dedicated named pipe, normally /var/run/sshd.fifo. Regardless, this means sshdfilter can see events as they happenand act on them as they happen.

OPTIONS
Configuration is divided into several sections, OPTIONS for general options, USERPOLICY for user based block rules, IPPOLICY for IP based block rules and SSHDLOG for sshd log message definitions.

  SECTION OPTIONS

maxblocktime=<seconds>
    How long (seconds) after the last activity from an ip that it can be removed from iptables block list. The default is 3600*24*3 (259200) seconds, which is 3 days.

maxchances=<number of guesses>
    How many password guesses an existing user can make before going on the blocked list. sshdfilter runs with sshd with the -e -D options, with these options, sshd likes to output failure and success messages twice. So this value needs to be twice what you actually want, defaults to 6, ie, 3 failed passwords.

firewalladd=<firewall command run when a drop rule is added> =item firewalldel=<firewall command run when a drop rule is deleted>
    These commands are executed, the following variables are available: $ip - IP address of the offending machine. $chain - Chain to add this IP to. $idx - the next free ipfw index number (if you are using ipfw). Typical examples are: firewalladd='iptables -A $chain -p tcp -s $ip --dport 22 -j DROP' firewalldel='iptables -D $chain -p tcp -s $ip --dport 22 -j DROP' or for ipfw: firewalladd='ipfw add $idx drop tcp from $ip to any dst-port 22' firewalldel='ipfw delete $idx drop tcp from $ip to any dst-port 22'

chain=<name of iptables chain for sshfilter>
    Name of iptables chain where sshdfilter will store its rules. If you want to run multiple isolated instances of sshdfilter then you will need to change this, your iptables setup and use the "SSHFILTERRC" environment variable (see INSTALL). Defaults to "SSHD".

ip6toip4=<boolean value>
    Convert any IPv6 addresses to IPv4, necessary for iptables, as only ip6tables knows about IPv6. Setting this option to 0 also enables calling ip6tables instead of iptables, so you should generally leave it set to 1. Defaults to 1.

ipfwmin=<index number>
ipfwmax=<index number>
    Enable the use of ipfw (for BSD, Solaris, Mac) instead of iptables. This pair specify the range of index numbers used by the rules. Pick a range of numbers that fit into your firewall. Read INSTALL.ipfw

mail=<email command sequence>
    Email any block events using the given command sequence. sshdfilter runs this line with some more details on stdin. Note perl executes this line, so be careful with escaping. Using the debug option might be a good idea, as would logging debug level syslog events (thats /etc/syslog.conf). Defaults to the empty string, but can for example be:
     mail="mail -s \"sshdfilter event for $ip, $event\" greg\@abatis.flint"

logsource=<file name>
    Where the sshd log messages come from, either from STDIN (sshd -e -D | sshdfilter), or via syslog, in which case the messages are read from a named pipe and you need to look at the sshdname and logpid options below.

logpid=<sshd pid>
    Assuming standard sshd behaviour, children of sshd (one sshd per connection) log to syslog directly, so the pid reported by syslog will change every time. The parent of the reported pid will be constant, and that is what this value should be. Or, set to <=0, and all sshdname processes will be interpretted as the same sshd. Can be given on the command line, sshdfilter logpid=`cat /var/run/sshd.pid`. Normally set to 0, as you normally don't need this.

sanitise=<'[^-a-zA-Z0-9_]'>
    Any character matching this expression is removed from the username before matching, to ensure odd characters aren't processed. If satitisation changes a username, the username is called DIRTY and matches the DIRTY pattern below. Normally [^-a-zA-Z0-9_].

sshdname=<sshd log name>
    The name of the sshd process, only needed to identify the sshd process from a none STDIN logsource. See also logpid above, which isn't required if you have only one sshd daemon process. Normally 'sshd'.

sshdpath=<path to sshd executable>
    Where the "sshd" executable can be found, defaults to /usr/sbin/sshd.

debug=<boolean>
    Debugging mode can be enabled by setting debug to 1, this enables a more verbose message parser which should help in locating any problems. Defaults to 0.

  SECTION USERPOLICY
    Action policy says what happens when different users try to log in. The right hand side of the = is a regular expression that matches either usernames or is a special word DEFAULT, INVALID, NOID or DIRTY.

    The format is:

    [number of failures],[block time] = <regular expression>

    [number of failures] is the maximum number of failures (password or invalid usernames) before an iptables block rule is created. Here twice what it should be, 'sshd -e -D', likes to output failures and successes twice. [block time] is how long that block will last. After this time, the iptables rule will be removed. This is specified as <number>d, <number>h, <number>m or <number>s, for days, hours, minutes or seconds respectively.

    This list is read from top to bottom, the first match wins. But, DEFAULT sets the current default values and can be used multiple times to set the ongoing default values for following lines. INVALID works in the same way, setting the defaults for future matches against users that match the given regular expression but are also invalid user names. Notice the effect is to match the last DEFAULT or INVALID line.

    An example policy:
     5,3d = DEFAULT # catch all
     0,10d = DIRTY # username sanitising was necessary? instant long term block
     0,10d = '^(nobody|test|guest|mythtv)$' # common brute force names, instant block for 10 days
     6 = '^greg$' # My username, so give me more chances, block for the default 3 days.
     3 = '^g[reg]{3}$' # allow 3 guesses of greg, grge, ggre, gger, gerg, gegr,
                         # even if they are invalid usernames.
     2,5d = '^root$' # allow two guesses of root, block for 5 days.
     ,1h = '^iant$' # default of 3 guesses, only block for 1 hour.
     3,5d = DEFAULT # change defaults from this point on, 3 guesses, block for 5 days.
     3,7d = INVALID # Sets the dafault for Invalid user names, three chances, and a 7 day block time.
                      # If any of the below are Invalid and missing a value, this value, not the DEFAULT
                      # value is used.
     4 = '^(peter|iant)$' # these two get 4 chances and would be blocked for 7 days.
     , = '^bob$' # If bob exists, gets 3 chances and is blocked for 5 days, all values based on last default.
                       # If bob is Illegal, gets 3 chances and is blocked for 7 days, values based on last INVALID.
     1,7d = INVALID # Catch all for Invalid usernames, if none of the above matched, these numbers will apply.
     0,10d = NOID # Catch all No ssh id events, instant block for 10 days.

    Keep in mind that an sshd bug will duplicate (or worse) log messages. sshdfilter cannot tell these apart, so you need to account for multiple messages here in the number of failures option. The bug only shows up with the sshd "-eD" options, as used when logsource='STDIN', ie, install route 1, as an sshd wrapper. This table summerises what you will problably see:

     (Failed valid users)
     Messages   Event   Comment
        2         1     First login failure
        2         2     Second login failure
        2         3     Third login failure

     (Invalid users)
     Messages   Event   Comment
        4         0     Initial connection, no password offered
        2         1     First login failure
        2         2     Second login failure
        2         3     Third login failure

  SECTION IPPOLICY
    This section lets you specify good networks\(+\) and bad networks\(-\), by regular expression matching IP addresses. This matches the same addresses as reported in sshdfilter logs, ie, the same IP version as used by your iptables command, which will most likely be version 4. No hostname lookup is done, or proper subnet matching. If you want any of that you need to be using iptables. Note that bad does not mean neutral, a connection attempt from a bad network will block that connection, even if the connection is successful.

    An example policy is:

     -'^192\.168\.7\.9$'  # drop a test #
     +'^192\.168\.7\.[0-9]+$'       # always accept, never block LAN connections
     +'^192\.168\.8\.[0-9]+$'       # always accept, never block LAN connections
     +'^192\.168\.0\.[0-9]+$'       # always accept, never block LAN connections
     -'^207\.46\.[0-9]+.[0-9]+$'    # Block known evil domain

  SECTION EMAILPOLICY
    When to send emails about block events. + means send email, - means don't. Read from top to bottom, the first match is the action. Except DEFAULT, which only matches after none of the others have matched. But for DEFAULT, INVALID and NOID, the surrounding '' are required.

     -'^peter$'   # If peter ever fails to login, don't email.
     +DEFAULT     # Email in most circumstances.
     +'^greg$'    # Email if the user is greg, redundant as this is the default.
     +INVALID     # Email all invalid users
     -NOID        # Don't email if there was no ssh id given.

  SECTION SSHDLOGS
    The SSHDLOG section maps sshd messages into one of several types, No Id string, Invalid User, Bad password for valid user, and Good password for valid user. Each version of sshd and many distribution use different message formats, so the exact format needs to be user configurable for your distribution/sshd. These are already supplied for quite a few distributions, see the patterns directory in the installation tree.

    Each of the above types needs two strings, the first is a regular expression that identifies an IP address and (maybe) a user name. Or, just identifies that a connection has been attempted and sshd rejected it (the No Id string message). The second string is a perl command that puts the identified data items into an array in the correct order.

    These two pairs of lines add patterns that detect and parse lines starting with 'Invalid user' or 'Failed user', which denote the remote machine tried to login with a non-existant account. But for typos, this would be a good sign of a brute force attempt. The second line of each pair puts the user name and then the IP address in a result array.
     #msg_invalid='^Illegal user (.*) from ([0-9a-fA-F:\.]+)'
     #map_invalid='push @res,$1; push @res,$2;'

     msg_invalid='^Failed [^ ]+ for illegal user (.*) from ([0-9a-fA-F:\.]+) port [0-9]+ ssh2'
     map_invalid='push @res,$1;  push @res,$2;'

    Identifies valid users that failed to give the right password. Their user name and IP address is placed in the result array.
     msg_failed_valid='^Failed password for (.*) from ([0-9a-fA-F:\.]+) port [0-9]+ ssh2'
     map_failed_valid='push @res,$1; push @res,$2;'

    Identifies valid user that did give a corrent password. Their user name and IP address is placed in the result array.
     msg_accepted_user='^Accepted [^ ]+ for (.*) from ([0-9a-fA-F:\.]+) port [0-9]+ ssh2'
     map_accepted_user='push @res,$1; push @res,$2;'

    Identifies port scans and initial brute force attempts that connect but never say anything. Their IP address is placed in the result array.
     msg_no_id_string='^Did not receive identification string from ([0-9a-fA-F:\.]+)'
     map_no_id_string='push @res,$1;'

    Identifies when the sshd process exited, which lets sshdfilter exit gracefully. The return status is placed in the result array, though sshdfilter currently does nothing with this result.
     msg_quit='^Received signal ([0-9]+); terminating.'
     map_quit='push @res,$1;'

    Note: Multi-line patterns are supported using \n in the pattern.

ENVIRONMENT VARIABLES

SSHDFILTERRC
    By default sshdfilter checks for its configuration file in /etc/sshdfilterrc, setting this variable will instead use the given file. This will typically be used to run multiple instances of sshdfilter, when monitoring multiple ports.

BUGS
None known. More likely there are features you don't like.

SEE ALSO
sshdfilter(1)

AUTHOR
Written by Greg: greg at csc liv ac uk. Would welcome any comments.

LogWatch script written by Tommo: sshdfilter at gmail com.

LICENSE
This software is released under the terms of the GNU GPLv2.

POD ERRORS
Hey! The above document had some coding errors, which are explained below:

Around line 126:
    You can't have =items (as at line 134) unless the first thing after the =over is an =item

Around line 268:
    '=item' outside of any '=over'

Around line 274:
    You forgot a '=back' before '=head1'