HOWTO Setup fail2ban: Difference between revisions

From Research
Jump to navigation Jump to search
No edit summary
 
(54 intermediate revisions by the same user not shown)
Line 1: Line 1:
==What fail2ban does==
==What fail2ban does==
Fail2ban parses logfiles, and finds repeated-failures for various services.  Once a specified number of failures within a given time is reached, the fail2ban makes an iptables-entry for you, banning (blocking) that IP-address.  After a configurable length of time, the IP-address is unblocked.
'''''fail2ban''''' parses logfiles, and finds repeated-access-failures for various services.  Once a specified number of failures (5) within a given time (10min) is reached, fail2ban makes an iptables-entry automatically, banning (blocking) that IP-address.  After a configurable length of time (2 weeks), the IP-address is automatically unblocked.  The status (number of hosts banned; number un-banned) is extracted from /var/log/fail2ban.log by logwatch, and summarized in our daily logwatch-email.


==Why we want fail2ban==
==Why we want fail2ban==
One alternative is denyhosts, which requires tcpwrappers, and makes entries in your /etc/hosts.deny file.  The problem is that regular-expressions are not supplied to filter more than SSH, and denyhosts can only scan a single log-file.  One advantage of denyhosts is that it doesn't require iptables.<br>
Our Gentoo systems use syslog-ng, with separate (from /var/log/messages) SSH auth.log file.  Often, we supply vsftpd connectivity for users, which uses another separate log-file.  We may also add other services.<br>
So, the flexibility and integration with iptables is a major benefit.


==Pre-Requisites==
Our Gentoo systems use syslog-ng, sometimes with separate SSH auth.log file (many times, though SSH logging is integrated into /var/log/messages).  Occasionally we also supply vsftpd connectivity for users, which uses yet another separate log-file.  We may also add other services (apache2, postfix, and others).  Fail2ban is capable of working with multiple log-files, and multiple services.  The flexibility and integration with iptables/netfilter is a major benefit of fail2ban, and filtering is performed at the kernel-level.  For most '''servers''', this is the way to go.<br>
*Iptables
 
<br>
 
<hr>
Yet another alternative to '''''fail2ban''''' is a set of iptables rules, in which you specify a time-window and number-of-failures you will tolerate within that time-window.  If you exercise some patience and wait a bit, the block goes away; most-effective against simplest automated attacks:
 
# define our own "extra" chain for processing SSH connections
$IPTABLES -N SSHSCAN
.
.
.
$IPTABLES -A INPUT -p tcp --dport 22 -m state --state NEW -j SSHSCAN
#IPTABLES -A INPUT -p tcp -m multiport --dports 22,2222 -m state --state NEW -j SSHSCAN
$IPTABLES -A SSHSCAN -m recent --set --name SSH --rsource
$IPTABLES -A SSHSCAN -m recent --update --seconds 10 --hitcount 4 --name SSH --rsource -j DROP  #only 4 fails in 10s
$IPTABLES -A SSHSCAN -m recent --update --seconds 1800 --hitcount 10 --name SSH --rsource -j DROP  #only 10 fails in 30min
$IPTABLES -A SSHSCAN -j ACCEPT #check status:  cat /proc/self/net/xt_recent/SSH
 
<br>
<br>
 
==Pre-Requisites for fail2ban==
*Python
*[[HOWTO Setup iptables|iptables]]
**Note:  if you want to use iptables-multiport (http, https for example) then verify that your kernel has Netfilter "multiport" included!)
*[[HOWTO Setup Logrotate|logrotate]]  (watch out!  Some stuff doesn't rotate; follow the link to fix it!)
*gamin (if you're following my suggestion, below)


==Installing fail2ban==
==Installing fail2ban==
  emerge -v fail2ban
  <font color=red>hostname</font> <font color=blue>~ #</font> '''emerge -v gamin fail2ban'''
emacs -nw /etc/fail2ban/jail.conf


==Configuring fail2ban==
==Configuring fail2ban==
Scroll to section "[ssh-iptables]" and enable it:
previously, we edited '''/etc/fail2ban/jail.conf'''. But no more! Leave this jail.conf alone, so updates can adjust this, and our own local-config will persist.
  ###enabled = false
enabled  = true


Change the the SSH logfile we want to scan:
Create a local-configuration file named jail.local:
###logpath = /var/log/sshd.log
logpath = /var/log/auth.log


Change how we monitor failures, preferring a file-alteration monitor over polling:
<font color=red>hostname</font> <font color=blue>~ #</font> '''emacs -nw /etc/fail2ban/jail.local'''
  ###backend = auto
[DEFAULT]
  backend = gamin
ignoreip = sfu.ca shaw.ca telus.ca telus.com teksavvy.com rogers.com rogers.ca bell.ca
bantime  = 1209600
findtime  = 1800
maxretry = 3
action_ = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
  logpath  = /var/log/auth.log
  logencoding=utf-8


Comment out the "mail-whois" actions.
[sshd]
enabled  = true
[webmin-auth]
enabled = true
 
Another example:
<font color=red>hostname</font> <font color=blue>~ #</font> '''emacs -nw /etc/fail2ban/jail.local'''
[DEFAULT]
ignoreip = sfu.ca shaw.ca telus.ca telus.com teksavvy.com rogers.com rogers.ca bell.ca
bantime  = 1209600
findtime  = 1800
maxretry = 3
action_ = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
# For hardened syslog-ng:
#logpath  = /var/log/auth.log
# For non-hardened syslog-ng:
logpath  = /var/log/messages
syslog_authpriv = /var/log/messages
[sshd]
enabled  = true
banaction = iptables-multiport
port   = 22,222


==Running fail2ban==
==Running fail2ban==
  root@hostname ~
  <font color=red>hostname</font> <font color=blue>~ #</font> '''/etc/init.d/fail2ban start'''
# /etc/init.d/fail2ban start
  <font color=lime>*</font> Starting fail2ban ...                                        <font color=blue>[</font> <font color=lime>ok</font> <font color=blue>]</font>
  * Starting fail2ban


  root@hostname ~
  <font color=red>hostname</font> <font color=blue>~ #</font> '''rc-update add fail2ban default'''
# rc-update add fail2ban default
  <font color=lime>*</font> fail2ban added to runlevel default
  * fail2ban added to runlevel default


==Monitoring and Verifying fail2ban==
==Monitoring and Verifying fail2ban==
Check the log file:
Check the log file:
  # tail /var/log/fail2ban.log
  <font color=red>hostname</font> <font color=blue>~ #</font> '''tail /var/log/fail2ban.log'''
and, for scrolling/real-time monitoring of additions to the log-file:
and, for scrolling/real-time monitoring of additions to the log-file:
  # tail -f /var/log/fail2ban.log
  <font color=red>hostname</font> <font color=blue>~ #</font> '''tail -f /var/log/fail2ban.log'''


Check Iptables:
Check Iptables:
  # iptables -L
  <font color=red>hostname</font> <font color=blue>~ #</font> '''iptables -L'''
Example output, for a web-server (port 80 open), with SSH and FTP services too.  Note the banned SSH user, resulting from too many failed-login-attempts:
Example output, for a web-server (port 80 open), with SSH and FTP services too.  Note the banned SSH user, resulting from too many failed-login-attempts:


Line 76: Line 123:
  target    prot opt source              destination         
  target    prot opt source              destination         
  RETURN    all  --  anywhere            anywhere
  RETURN    all  --  anywhere            anywhere
==Troubleshooting fail2ban==
===Log-file===
By far, the most-common mistake is not specifying the proper log-file!  Triple-check this, and use the next regex-tool to see that something sensible is happening.
===Regular Expression Testing===
One of the best ways of troubleshooting is to use the '''fail2ban-regex tool'''.  Feed this with the log-file you want to watch, and point it to the filter you want applied:
<font color=red>hostname</font> <font color=blue>~ #</font> '''/usr/bin/fail2ban-regex /var/log/messages /etc/fail2ban/filter.d/sshd.conf'''
Example output:
Unable to find a corresponding IP address for eges.esstel.ru
Unable to find a corresponding IP address for adsl-75-22-172-193.dsl.sndg02.sbcglobal.net
Unable to find a corresponding IP address for adsl-75-22-172-193.dsl.sndg02.sbcglobal.net
Running tests
=============
Use regex file : /etc/fail2ban/filter.d/sshd.conf
Use log file  : /var/log/messages
Results
=======
Failregex:
[1] Authentication failure for .* from <HOST>$
[2] Failed [-/\w]+ for .* from <HOST>$
[3] ROOT LOGIN REFUSED .* FROM <HOST>$
[4] [iI](?:llegal|nvalid) user .* from <HOST>$
Number of matches:
[1] 3161 match(es)
[2] 0 match(es)
[3] 0 match(es)
[4] 932 match(es)
Addresses found:
[1]
    203.98.175.182 (Wed Nov 19 06:04:16 2008)
    59.125.226.213 (Wed Nov 19 06:07:05 2008)
    80.153.123.179 (Wed Nov 19 06:10:13 2008)
    76.255.174.78 (Wed Nov 19 06:13:03 2008)
    66.158.139.11 (Wed Nov 19 06:15:54 2008)
    66.158.139.11 (Wed Nov 19 06:18:54 2008)
<truncated the rest of the output, for brevity's sake>
This verifies that the logfile you are parsing does indeed contain appropriate information for fail2ban, and it shows the filter-rules and numbers of matches for each rule.  Some attacks try to sneak under a fail2ban threshold, so this kind of regex-test may show only a single, or perhaps 2 failures from a given IP-address... often (depending on configuration), this isn't enough to trigger a ban (the default config may require 5 attempts, or a tweaked version may reduce this threshold to 3 failures before banning).
<br>
<br>
===Fail2ban Jail Status===
Another useful tool is '''fail2ban-client''' to view the current status of a jail:
<font color=red>hostname</font> <font color=blue>~ #</font> '''/usr/bin/fail2ban-client status ssh-iptables'''
Example output:
Status for the jail: ssh-iptables
|- filter
|  |- Currently failed: 11
|  `- Total failed: 207
`- action
    |- Currently banned: 3
    |  `- IP list: 211.139.168.226 140.120.108.187 83.208.170.100
    `- Total banned: 3
<br>
===Other Things to Look For===
If you see this kind of 0 references, and you're using iptables-multiport, check that you have enabled Netfilter "multiport" in your kernel:
...
Chain fail2ban-ssh (0 references)
target    prot opt source              destination       
RETURN    all  --  anywhere            anywhere
'''0 references''' means that your actions are '''not''' in-effect :-O :-(  You '''should not''' see a top-portion of your iptables that looks like this (without any fail2ban references):
<font color=red>hostname</font> <font color=blue>~ #</font> '''iptables -L'''
Chain INPUT (policy DROP)
target    prot opt source              destination       
ACCEPT    all  --  anywhere            anywhere           
DROP      tcp  --  anywhere            anywhere            tcp flags:FIN,SYN,RST,PSH,ACK,URG/NONE
DROP      tcp  --  anywhere            anywhere            tcp flags:FIN,SYN/FIN,SYN
DROP      tcp  --  anywhere            anywhere            tcp flags:SYN,RST/SYN,RST
DROP      tcp  --  anywhere            anywhere            tcp flags:FIN,RST/FIN,RST
DROP      tcp  --  anywhere            anywhere            tcp flags:FIN,ACK/FIN
DROP      tcp  --  anywhere            anywhere            tcp flags:PSH,ACK/PSH
DROP      tcp  --  anywhere            anywhere            tcp flags:ACK,URG/URG
...
Instead, you should see an iptables top, and lower references which match up and look like this healthy example:
<font color=red>hostname</font> <font color=blue>~ #</font> '''iptables -L'''
Chain INPUT (policy DROP)
target    prot opt source              destination       
fail2ban-web  tcp  --  anywhere            anywhere            multiport dports http,https
fail2ban-web  tcp  --  anywhere            anywhere            multiport dports http,https
fail2ban-web  tcp  --  anywhere            anywhere            multiport dports http,https
...
Chain fail2ban-web (3 references)
target    prot opt source              destination       
RETURN    all  --  anywhere            anywhere           
RETURN    all  --  anywhere            anywhere           
RETURN    all  --  anywhere            anywhere
==Extra Fun!==
You can use this one-liner to parse through your '''/var/log/messages''' file and totalize the number of times a specific IP-address has been attempting to access your machine:
awk '($(NF-7) = /invalid user/){print $(NF-3)}' /var/log/messages | sort | uniq -c | sort
Once you have this listing, you can manually add IP-blocks of the form:
iptables -I INPUT -p tcp -s 83.103.96.33 --dport ssh -j REJECT --reject-with tcp-reset

Latest revision as of 23:37, 27 February 2017

What fail2ban does

fail2ban parses logfiles, and finds repeated-access-failures for various services. Once a specified number of failures (5) within a given time (10min) is reached, fail2ban makes an iptables-entry automatically, banning (blocking) that IP-address. After a configurable length of time (2 weeks), the IP-address is automatically unblocked. The status (number of hosts banned; number un-banned) is extracted from /var/log/fail2ban.log by logwatch, and summarized in our daily logwatch-email.

Why we want fail2ban

Our Gentoo systems use syslog-ng, sometimes with separate SSH auth.log file (many times, though SSH logging is integrated into /var/log/messages). Occasionally we also supply vsftpd connectivity for users, which uses yet another separate log-file. We may also add other services (apache2, postfix, and others). Fail2ban is capable of working with multiple log-files, and multiple services. The flexibility and integration with iptables/netfilter is a major benefit of fail2ban, and filtering is performed at the kernel-level. For most servers, this is the way to go.



Yet another alternative to fail2ban is a set of iptables rules, in which you specify a time-window and number-of-failures you will tolerate within that time-window. If you exercise some patience and wait a bit, the block goes away; most-effective against simplest automated attacks:

# define our own "extra" chain for processing SSH connections
$IPTABLES -N SSHSCAN
.
.
.
$IPTABLES -A INPUT -p tcp --dport 22 -m state --state NEW -j SSHSCAN
#IPTABLES -A INPUT -p tcp -m multiport --dports 22,2222 -m state --state NEW -j SSHSCAN
$IPTABLES -A SSHSCAN -m recent --set --name SSH --rsource
$IPTABLES -A SSHSCAN -m recent --update --seconds 10 --hitcount 4 --name SSH --rsource -j DROP  #only 4 fails in 10s
$IPTABLES -A SSHSCAN -m recent --update --seconds 1800 --hitcount 10 --name SSH --rsource -j DROP  #only 10 fails in 30min
$IPTABLES -A SSHSCAN -j ACCEPT #check status:  cat /proc/self/net/xt_recent/SSH



Pre-Requisites for fail2ban

  • Python
  • iptables
    • Note: if you want to use iptables-multiport (http, https for example) then verify that your kernel has Netfilter "multiport" included!)
  • logrotate (watch out! Some stuff doesn't rotate; follow the link to fix it!)
  • gamin (if you're following my suggestion, below)

Installing fail2ban

hostname ~ # emerge -v gamin fail2ban

Configuring fail2ban

previously, we edited /etc/fail2ban/jail.conf. But no more! Leave this jail.conf alone, so updates can adjust this, and our own local-config will persist.

Create a local-configuration file named jail.local:

hostname ~ # emacs -nw /etc/fail2ban/jail.local
[DEFAULT]
ignoreip = sfu.ca shaw.ca telus.ca telus.com teksavvy.com rogers.com rogers.ca bell.ca
bantime  = 1209600
findtime  = 1800
maxretry = 3
action_ = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
logpath  = /var/log/auth.log
logencoding=utf-8
[sshd]
enabled  = true

[webmin-auth]
enabled = true

Another example:

hostname ~ # emacs -nw /etc/fail2ban/jail.local
[DEFAULT]
ignoreip = sfu.ca shaw.ca telus.ca telus.com teksavvy.com rogers.com rogers.ca bell.ca
bantime  = 1209600
findtime  = 1800
maxretry = 3
action_ = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]

# For hardened syslog-ng:
#logpath  = /var/log/auth.log

# For non-hardened syslog-ng:
logpath  = /var/log/messages
syslog_authpriv = /var/log/messages

[sshd]
enabled  = true
banaction = iptables-multiport
port	   = 22,222

Running fail2ban

hostname ~ # /etc/init.d/fail2ban start
* Starting fail2ban ...                                         [ ok ]
hostname ~ # rc-update add fail2ban default
* fail2ban added to runlevel default

Monitoring and Verifying fail2ban

Check the log file:

hostname ~ # tail /var/log/fail2ban.log

and, for scrolling/real-time monitoring of additions to the log-file:

hostname ~ # tail -f /var/log/fail2ban.log

Check Iptables:

hostname ~ # iptables -L

Example output, for a web-server (port 80 open), with SSH and FTP services too. Note the banned SSH user, resulting from too many failed-login-attempts:

Chain INPUT (policy DROP)
target     prot opt source               destination         
fail2ban-VSFTPD  tcp  --  anywhere             anywhere            tcp dpt:ftp 
fail2ban-SSH  tcp  --  anywhere             anywhere            tcp dpt:ssh 
ACCEPT     all  --  anywhere             anywhere            
DROP       all  --  anywhere             anywhere            state INVALID 
ACCEPT     all  --  anywhere             anywhere            state RELATED,ESTABLISHED 
ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:ftp-data 
ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:ftp 
ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:ssh 
ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:http

Chain FORWARD (policy DROP)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere            state RELATED,ESTABLISHED 

Chain fail2ban-SSH (1 references)
target     prot opt source               destination         
DROP       all  --  sr-01504.iat.sfu.ca  anywhere            
RETURN     all  --  anywhere             anywhere            

Chain fail2ban-VSFTPD (1 references)
target     prot opt source               destination         
RETURN     all  --  anywhere             anywhere

Troubleshooting fail2ban

Log-file

By far, the most-common mistake is not specifying the proper log-file! Triple-check this, and use the next regex-tool to see that something sensible is happening.

Regular Expression Testing

One of the best ways of troubleshooting is to use the fail2ban-regex tool. Feed this with the log-file you want to watch, and point it to the filter you want applied:

hostname ~ # /usr/bin/fail2ban-regex /var/log/messages /etc/fail2ban/filter.d/sshd.conf

Example output:

Unable to find a corresponding IP address for eges.esstel.ru
Unable to find a corresponding IP address for adsl-75-22-172-193.dsl.sndg02.sbcglobal.net
Unable to find a corresponding IP address for adsl-75-22-172-193.dsl.sndg02.sbcglobal.net

Running tests
=============

Use regex file : /etc/fail2ban/filter.d/sshd.conf
Use log file   : /var/log/messages


Results
=======

Failregex:
[1] Authentication failure for .* from <HOST>$
[2] Failed [-/\w]+ for .* from <HOST>$
[3] ROOT LOGIN REFUSED .* FROM <HOST>$
[4] [iI](?:llegal|nvalid) user .* from <HOST>$

Number of matches:
[1] 3161 match(es)
[2] 0 match(es)
[3] 0 match(es)
[4] 932 match(es)

Addresses found:
[1]
    203.98.175.182 (Wed Nov 19 06:04:16 2008)
    59.125.226.213 (Wed Nov 19 06:07:05 2008)
    80.153.123.179 (Wed Nov 19 06:10:13 2008)
    76.255.174.78 (Wed Nov 19 06:13:03 2008)
    66.158.139.11 (Wed Nov 19 06:15:54 2008)
    66.158.139.11 (Wed Nov 19 06:18:54 2008)

<truncated the rest of the output, for brevity's sake>

This verifies that the logfile you are parsing does indeed contain appropriate information for fail2ban, and it shows the filter-rules and numbers of matches for each rule. Some attacks try to sneak under a fail2ban threshold, so this kind of regex-test may show only a single, or perhaps 2 failures from a given IP-address... often (depending on configuration), this isn't enough to trigger a ban (the default config may require 5 attempts, or a tweaked version may reduce this threshold to 3 failures before banning).

Fail2ban Jail Status

Another useful tool is fail2ban-client to view the current status of a jail:

hostname ~ # /usr/bin/fail2ban-client status ssh-iptables

Example output:

Status for the jail: ssh-iptables
|- filter
|  |- Currently failed:	11
|  `- Total failed:	207
`- action
   |- Currently banned:	3
   |  `- IP list:	211.139.168.226 140.120.108.187 83.208.170.100 
   `- Total banned:	3


Other Things to Look For

If you see this kind of 0 references, and you're using iptables-multiport, check that you have enabled Netfilter "multiport" in your kernel:

...
Chain fail2ban-ssh (0 references)
target     prot opt source               destination         
RETURN     all  --  anywhere             anywhere

0 references means that your actions are not in-effect :-O :-( You should not see a top-portion of your iptables that looks like this (without any fail2ban references):

hostname ~ # iptables -L
Chain INPUT (policy DROP)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere            
DROP       tcp  --  anywhere             anywhere            tcp flags:FIN,SYN,RST,PSH,ACK,URG/NONE 
DROP       tcp  --  anywhere             anywhere            tcp flags:FIN,SYN/FIN,SYN 
DROP       tcp  --  anywhere             anywhere            tcp flags:SYN,RST/SYN,RST 
DROP       tcp  --  anywhere             anywhere            tcp flags:FIN,RST/FIN,RST 
DROP       tcp  --  anywhere             anywhere            tcp flags:FIN,ACK/FIN 
DROP       tcp  --  anywhere             anywhere            tcp flags:PSH,ACK/PSH 
DROP       tcp  --  anywhere             anywhere            tcp flags:ACK,URG/URG 
...

Instead, you should see an iptables top, and lower references which match up and look like this healthy example:

hostname ~ # iptables -L
Chain INPUT (policy DROP)
target     prot opt source               destination         
fail2ban-web  tcp  --  anywhere             anywhere            multiport dports http,https 
fail2ban-web  tcp  --  anywhere             anywhere            multiport dports http,https 
fail2ban-web  tcp  --  anywhere             anywhere            multiport dports http,https 
...
Chain fail2ban-web (3 references)
target     prot opt source               destination         
RETURN     all  --  anywhere             anywhere            
RETURN     all  --  anywhere             anywhere            
RETURN     all  --  anywhere             anywhere

Extra Fun!

You can use this one-liner to parse through your /var/log/messages file and totalize the number of times a specific IP-address has been attempting to access your machine:

awk '($(NF-7) = /invalid user/){print $(NF-3)}' /var/log/messages | sort | uniq -c | sort

Once you have this listing, you can manually add IP-blocks of the form:

iptables -I INPUT -p tcp -s 83.103.96.33 --dport ssh -j REJECT --reject-with tcp-reset