mirror of https://github.com/fail2ban/fail2ban
Merge branch 'master' into nginx-botsearch
commit
eb0d086ed0
12
ChangeLog
12
ChangeLog
|
@ -29,10 +29,18 @@ ver. 0.9.2 (2014/XX/XXX) - wanna-be-released
|
||||||
* recidive uses iptables-allports banaction by default now.
|
* recidive uses iptables-allports banaction by default now.
|
||||||
Avoids problems with iptables versions not understanding 'all' for
|
Avoids problems with iptables versions not understanding 'all' for
|
||||||
protocols and ports
|
protocols and ports
|
||||||
|
* filter.d/dovecot.conf
|
||||||
|
- match pam_authenticate line from EL7
|
||||||
|
- match unknown user line from EL7
|
||||||
|
* Use use_poll=True for Python 2.7 to overcome "Bad file descriptor" msgs
|
||||||
|
issue (gh-161)
|
||||||
|
* filter.d/postfix-sasl.conf - tweak failregex and add ignoreregex to ignore
|
||||||
|
system authentication issues
|
||||||
|
|
||||||
- New Features:
|
- New Features:
|
||||||
- New filter:
|
- New filter:
|
||||||
- postfix-rbl Thanks Lee Clemens
|
- postfix-rbl Thanks Lee Clemens
|
||||||
|
- apache-fakegooglebot.conf Thanks Lee Clemens
|
||||||
- New recursive embedded substitution feature added:
|
- New recursive embedded substitution feature added:
|
||||||
- `<<PREF>HOST>` becomes `<IPV4HOST>` for PREF=`IPV4`;
|
- `<<PREF>HOST>` becomes `<IPV4HOST>` for PREF=`IPV4`;
|
||||||
- `<<PREF>HOST>` becomes `1.2.3.4` for PREF=`IPV4` and IPV4HOST=`1.2.3.4`;
|
- `<<PREF>HOST>` becomes `1.2.3.4` for PREF=`IPV4` and IPV4HOST=`1.2.3.4`;
|
||||||
|
@ -54,6 +62,10 @@ ver. 0.9.2 (2014/XX/XXX) - wanna-be-released
|
||||||
* Enable multiport for firewallcmd-new action. Closes gh-834
|
* Enable multiport for firewallcmd-new action. Closes gh-834
|
||||||
* files/debian-initd migrated from the debian branch and should be
|
* files/debian-initd migrated from the debian branch and should be
|
||||||
suitable for manual installations now (thanks Juan Karlo de Guzman)
|
suitable for manual installations now (thanks Juan Karlo de Guzman)
|
||||||
|
* Define empty ignoreregex in filters which didn't have it to avoid
|
||||||
|
warnings (gh-934)
|
||||||
|
* action.d/{sendmail-*,xarf-login-attack}.conf - report local
|
||||||
|
timezone not UTC time/zone. Closes gh-911
|
||||||
|
|
||||||
|
|
||||||
ver. 0.9.1 (2014/10/29) - better, faster, stronger
|
ver. 0.9.1 (2014/10/29) - better, faster, stronger
|
||||||
|
|
2
MANIFEST
2
MANIFEST
|
@ -266,6 +266,8 @@ config/filter.d/groupoffice.conf
|
||||||
config/filter.d/gssftpd.conf
|
config/filter.d/gssftpd.conf
|
||||||
config/filter.d/guacamole.conf
|
config/filter.d/guacamole.conf
|
||||||
config/filter.d/horde.conf
|
config/filter.d/horde.conf
|
||||||
|
config/filter.d/ignorecommands
|
||||||
|
config/filter.d/ignorecommands/apache-fakegooglebot
|
||||||
config/filter.d/kerio.conf
|
config/filter.d/kerio.conf
|
||||||
config/filter.d/lighttpd-auth.conf
|
config/filter.d/lighttpd-auth.conf
|
||||||
config/filter.d/monit.conf
|
config/filter.d/monit.conf
|
||||||
|
|
|
@ -2,3 +2,4 @@ include ChangeLog COPYING DEVELOP FILTERS README.* THANKS TODO CONTRIBUTING* Vag
|
||||||
graft doc
|
graft doc
|
||||||
graft files
|
graft files
|
||||||
recursive-include config *.conf *.py
|
recursive-include config *.conf *.py
|
||||||
|
recursive-include config/filter.d/ignorecommands *
|
||||||
|
|
1
THANKS
1
THANKS
|
@ -83,6 +83,7 @@ Michael Hanselmann
|
||||||
Mika (mkl)
|
Mika (mkl)
|
||||||
Nick Munger
|
Nick Munger
|
||||||
onorua
|
onorua
|
||||||
|
Orion Poplawski
|
||||||
Paul Marrapese
|
Paul Marrapese
|
||||||
Paul Traina
|
Paul Traina
|
||||||
Noel Butler
|
Noel Butler
|
||||||
|
|
|
@ -15,7 +15,7 @@ after = sendmail-common.local
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionstart = printf %%b "Subject: [Fail2Ban] <name>: started on `uname -n`
|
actionstart = printf %%b "Subject: [Fail2Ban] <name>: started on `uname -n`
|
||||||
Date: `LC_TIME=C date -u +"%%a, %%d %%h %%Y %%T +0000"`
|
Date: `LC_TIME=C date +"%%a, %%d %%h %%Y %%T %%z"`
|
||||||
From: <sendername> <<sender>>
|
From: <sendername> <<sender>>
|
||||||
To: <dest>\n
|
To: <dest>\n
|
||||||
Hi,\n
|
Hi,\n
|
||||||
|
@ -28,7 +28,7 @@ actionstart = printf %%b "Subject: [Fail2Ban] <name>: started on `uname -n`
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionstop = printf %%b "Subject: [Fail2Ban] <name>: stopped on `uname -n`
|
actionstop = printf %%b "Subject: [Fail2Ban] <name>: stopped on `uname -n`
|
||||||
Date: `LC_TIME=C date -u +"%%a, %%d %%h %%Y %%T +0000"`
|
Date: `LC_TIME=C date +"%%a, %%d %%h %%Y %%T %%z"`
|
||||||
From: <sendername> <<sender>>
|
From: <sendername> <<sender>>
|
||||||
To: <dest>\n
|
To: <dest>\n
|
||||||
Hi,\n
|
Hi,\n
|
||||||
|
|
|
@ -17,7 +17,7 @@ before = sendmail-common.conf
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip> from `uname -n`
|
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip> from `uname -n`
|
||||||
Date: `LC_TIME=C date -u +"%%a, %%d %%h %%Y %%T +0000"`
|
Date: `LC_TIME=C date +"%%a, %%d %%h %%Y %%T %%z"`
|
||||||
From: <sendername> <<sender>>
|
From: <sendername> <<sender>>
|
||||||
To: <dest>\n
|
To: <dest>\n
|
||||||
Hi,\n
|
Hi,\n
|
||||||
|
|
|
@ -17,7 +17,7 @@ before = sendmail-common.conf
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip> from `uname -n`
|
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip> from `uname -n`
|
||||||
Date: `LC_TIME=C date -u +"%%a, %%d %%h %%Y %%T +0000"`
|
Date: `LC_TIME=C date +"%%a, %%d %%h %%Y %%T %%z"`
|
||||||
From: <sendername> <<sender>>
|
From: <sendername> <<sender>>
|
||||||
To: <dest>\n
|
To: <dest>\n
|
||||||
Hi,\n
|
Hi,\n
|
||||||
|
|
|
@ -17,7 +17,7 @@ before = sendmail-common.conf
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip> from `uname -n`
|
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip> from `uname -n`
|
||||||
Date: `LC_TIME=C date -u +"%%a, %%d %%h %%Y %%T +0000"`
|
Date: `LC_TIME=C date +"%%a, %%d %%h %%Y %%T %%z"`
|
||||||
From: <sendername> <<sender>>
|
From: <sendername> <<sender>>
|
||||||
To: <dest>\n
|
To: <dest>\n
|
||||||
Hi,\n
|
Hi,\n
|
||||||
|
|
|
@ -17,7 +17,7 @@ before = sendmail-common.conf
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip> from `uname -n`
|
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip> from `uname -n`
|
||||||
Date: `LC_TIME=C date -u +"%%a, %%d %%h %%Y %%T +0000"`
|
Date: `LC_TIME=C date +"%%a, %%d %%h %%Y %%T %%z"`
|
||||||
From: <sendername> <<sender>>
|
From: <sendername> <<sender>>
|
||||||
To: <dest>\n
|
To: <dest>\n
|
||||||
Hi,\n
|
Hi,\n
|
||||||
|
|
|
@ -17,7 +17,7 @@ before = sendmail-common.conf
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip> from `uname -n`
|
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip> from `uname -n`
|
||||||
Date: `LC_TIME=C date -u +"%%a, %%d %%h %%Y %%T +0000"`
|
Date: `LC_TIME=C date +"%%a, %%d %%h %%Y %%T %%z"`
|
||||||
From: <sendername> <<sender>>
|
From: <sendername> <<sender>>
|
||||||
To: <dest>\n
|
To: <dest>\n
|
||||||
Hi,\n
|
Hi,\n
|
||||||
|
|
|
@ -17,7 +17,7 @@ before = sendmail-common.conf
|
||||||
# Values: CMD
|
# Values: CMD
|
||||||
#
|
#
|
||||||
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip> from `uname -n`
|
actionban = printf %%b "Subject: [Fail2Ban] <name>: banned <ip> from `uname -n`
|
||||||
Date: `LC_TIME=C date -u +"%%a, %%d %%h %%Y %%T +0000"`
|
Date: `LC_TIME=C date +"%%a, %%d %%h %%Y %%T %%z"`
|
||||||
From: <sendername> <<sender>>
|
From: <sendername> <<sender>>
|
||||||
To: <dest>\n
|
To: <dest>\n
|
||||||
Hi,\n
|
Hi,\n
|
||||||
|
|
|
@ -46,7 +46,7 @@ actionban = oifs=${IFS}; IFS=.;SEP_IP=( <ip> ); set -- ${SEP_IP}; ADDRESSES=$(di
|
||||||
REPORTID=<time>@`uname -n`
|
REPORTID=<time>@`uname -n`
|
||||||
TLP=<tlp>
|
TLP=<tlp>
|
||||||
PORT=<port>
|
PORT=<port>
|
||||||
DATE=`LC_TIME=C date -u --date=@<time> +"%%a, %%d %%h %%Y %%T +0000"`
|
DATE=`LC_TIME=C date --date=@<time> +"%%a, %%d %%h %%Y %%T %%z"`
|
||||||
if [ ! -z "$ADDRESSES" ]; then
|
if [ ! -z "$ADDRESSES" ]; then
|
||||||
(printf -- %%b "<header>\n<message>\n<report>\n";
|
(printf -- %%b "<header>\n<message>\n<report>\n";
|
||||||
date '+Note: Local timezone is %%z (%%Z)';
|
date '+Note: Local timezone is %%z (%%Z)';
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
# Fail2Ban filter for fake Googlebot User Agents
|
||||||
|
|
||||||
|
[Definition]
|
||||||
|
|
||||||
|
failregex = ^<HOST> .*Googlebot.*$
|
||||||
|
|
||||||
|
ignoreregex =
|
||||||
|
|
||||||
|
|
||||||
|
# DEV Notes:
|
||||||
|
#
|
||||||
|
# Author: Lee Clemens
|
||||||
|
# Thanks: Johannes B. Ullrich, Ph.D.
|
||||||
|
# Reference: https://isc.sans.edu/forums/diary/When+Google+isnt+Google/15968/
|
|
@ -53,4 +53,8 @@ __bsd_syslog_verbose = (<[^.]+\.[^.]+>)
|
||||||
# This can be optional (for instance if we match named native log files)
|
# This can be optional (for instance if we match named native log files)
|
||||||
__prefix_line = \s*%(__bsd_syslog_verbose)s?\s*(?:%(__hostname)s )?(?:%(__kernel_prefix)s )?(?:@vserver_\S+ )?%(__daemon_combs_re)s?\s%(__daemon_extra_re)s?\s*
|
__prefix_line = \s*%(__bsd_syslog_verbose)s?\s*(?:%(__hostname)s )?(?:%(__kernel_prefix)s )?(?:@vserver_\S+ )?%(__daemon_combs_re)s?\s%(__daemon_extra_re)s?\s*
|
||||||
|
|
||||||
|
# PAM authentication mechanism check for failures, e.g.: pam_unix, pam_sss,
|
||||||
|
# pam_ldap
|
||||||
|
__pam_auth = pam_unix
|
||||||
|
|
||||||
# Author: Yaroslav Halchenko
|
# Author: Yaroslav Halchenko
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
failregex = ^: Bad Rcon: "rcon \d+ "\S+" sv_contact ".*?"" from "<HOST>:\d+"$
|
failregex = ^: Bad Rcon: "rcon \d+ "\S+" sv_contact ".*?"" from "<HOST>:\d+"$
|
||||||
|
|
||||||
|
ignoreregex =
|
||||||
|
|
||||||
[Init]
|
[Init]
|
||||||
|
|
||||||
|
|
|
@ -9,9 +9,10 @@ before = common.conf
|
||||||
|
|
||||||
_daemon = (auth|dovecot(-auth)?|auth-worker)
|
_daemon = (auth|dovecot(-auth)?|auth-worker)
|
||||||
|
|
||||||
failregex = ^%(__prefix_line)s(pam_unix(\(dovecot:auth\))?:)?\s+authentication failure; logname=\S* uid=\S* euid=\S* tty=dovecot ruser=\S* rhost=<HOST>(\s+user=\S*)?\s*$
|
failregex = ^%(__prefix_line)s(%(__pam_auth)s(\(dovecot:auth\))?:)?\s+authentication failure; logname=\S* uid=\S* euid=\S* tty=dovecot ruser=\S* rhost=<HOST>(\s+user=\S*)?\s*$
|
||||||
^%(__prefix_line)s(pop3|imap)-login: (Info: )?(Aborted login|Disconnected)(: Inactivity)? \(((auth failed, \d+ attempts)( in \d+ secs)?|tried to use (disabled|disallowed) \S+ auth)\):( user=<\S*>,)?( method=\S+,)? rip=<HOST>(, lip=(\d{1,3}\.){3}\d{1,3})?(, TLS( handshaking(: SSL_accept\(\) failed: error:[\dA-F]+:SSL routines:[TLS\d]+_GET_CLIENT_HELLO:unknown protocol)?)?(: Disconnected)?)?(, session=<\S+>)?\s*$
|
^%(__prefix_line)s(pop3|imap)-login: (Info: )?(Aborted login|Disconnected)(: Inactivity)? \(((auth failed, \d+ attempts)( in \d+ secs)?|tried to use (disabled|disallowed) \S+ auth)\):( user=<\S*>,)?( method=\S+,)? rip=<HOST>(, lip=(\d{1,3}\.){3}\d{1,3})?(, TLS( handshaking(: SSL_accept\(\) failed: error:[\dA-F]+:SSL routines:[TLS\d]+_GET_CLIENT_HELLO:unknown protocol)?)?(: Disconnected)?)?(, session=<\S+>)?\s*$
|
||||||
^%(__prefix_line)s(Info|dovecot: auth\(default\)): pam\(\S+,<HOST>\): pam_authenticate\(\) failed: (User not known to the underlying authentication module: \d+ Time\(s\)|Authentication failure \(password mismatch\?\))\s*$
|
^%(__prefix_line)s(Info|dovecot: auth\(default\)|auth-worker\(\d+\)): pam\(\S+,<HOST>\): pam_authenticate\(\) failed: (User not known to the underlying authentication module: \d+ Time\(s\)|Authentication failure \(password mismatch\?\))\s*$
|
||||||
|
^%(__prefix_line)sauth-worker\(\d+\): pam\(\S+,<HOST>\): unknown user\s*$
|
||||||
|
|
||||||
ignoreregex =
|
ignoreregex =
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
failregex = ^\[\]LOGIN FAILED for user: "\S+" from IP: <HOST>$
|
failregex = ^\[\]LOGIN FAILED for user: "\S+" from IP: <HOST>$
|
||||||
|
|
||||||
|
ignoreregex =
|
||||||
|
|
||||||
# Author: Daniel Black
|
# Author: Daniel Black
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# Inspired by https://isc.sans.edu/forums/diary/When+Google+isnt+Google/15968/
|
||||||
|
#
|
||||||
|
# Written in Python to reuse built-in Python batteries and not depend on
|
||||||
|
# presence of host and cut commands
|
||||||
|
#
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def process_args(argv):
|
||||||
|
if len(argv) != 2:
|
||||||
|
sys.stderr.write("Please provide a single IP as an argument. Got: %s\n"
|
||||||
|
% (argv[1:]))
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
ip = argv[1]
|
||||||
|
|
||||||
|
from fail2ban.server.filter import DNSUtils
|
||||||
|
if not DNSUtils.isValidIP(ip):
|
||||||
|
sys.stderr.write("Argument must be a single valid IP. Got: %s\n"
|
||||||
|
% ip)
|
||||||
|
sys.exit(3)
|
||||||
|
return ip
|
||||||
|
|
||||||
|
def is_googlebot(ip):
|
||||||
|
import re
|
||||||
|
from fail2ban.server.filter import DNSUtils
|
||||||
|
|
||||||
|
host = DNSUtils.ipToName(ip)
|
||||||
|
sys.exit(0 if (host and re.match('crawl-.*\.googlebot\.com', host)) else 1)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
is_googlebot(process_args(sys.argv))
|
|
@ -6,6 +6,9 @@ failregex = ^ SMTP Spam attack detected from <HOST>,
|
||||||
^ IP address <HOST> found in DNS blacklist \S+, mail from \S+ to \S+$
|
^ IP address <HOST> found in DNS blacklist \S+, mail from \S+ to \S+$
|
||||||
^ Relay attempt from IP address <HOST>
|
^ Relay attempt from IP address <HOST>
|
||||||
^ Attempt to deliver to unknown recipient \S+, from \S+, IP address <HOST>$
|
^ Attempt to deliver to unknown recipient \S+, from \S+, IP address <HOST>$
|
||||||
|
|
||||||
|
ignoreregex =
|
||||||
|
|
||||||
[Init]
|
[Init]
|
||||||
|
|
||||||
datepattern = ^\[%%d/%%b/%%Y %%H:%%M:%%S\]
|
datepattern = ^\[%%d/%%b/%%Y %%H:%%M:%%S\]
|
||||||
|
|
|
@ -7,3 +7,4 @@
|
||||||
failregex = ^\[[A-Z]+\s+\]\s*error\s*:\s*Warning:\s+Client '<HOST>' supplied unknown user '\w+' accessing monit httpd$
|
failregex = ^\[[A-Z]+\s+\]\s*error\s*:\s*Warning:\s+Client '<HOST>' supplied unknown user '\w+' accessing monit httpd$
|
||||||
^\[[A-Z]+\s+\]\s*error\s*:\s*Warning:\s+Client '<HOST>' supplied wrong password for user '\w+' accessing monit httpd$
|
^\[[A-Z]+\s+\]\s*error\s*:\s*Warning:\s+Client '<HOST>' supplied wrong password for user '\w+' accessing monit httpd$
|
||||||
|
|
||||||
|
ignoreregex =
|
||||||
|
|
|
@ -24,3 +24,5 @@ _daemon = nsd
|
||||||
|
|
||||||
failregex = ^\[\]%(__prefix_line)sinfo: ratelimit block .* query <HOST> TYPE255$
|
failregex = ^\[\]%(__prefix_line)sinfo: ratelimit block .* query <HOST> TYPE255$
|
||||||
^\[\]%(__prefix_line)sinfo: .* <HOST> refused, no acl matches\.$
|
^\[\]%(__prefix_line)sinfo: .* <HOST> refused, no acl matches\.$
|
||||||
|
|
||||||
|
ignoreregex =
|
||||||
|
|
|
@ -13,7 +13,7 @@ before = common.conf
|
||||||
# Default: catch all failed logins
|
# Default: catch all failed logins
|
||||||
_ttys_re=\S*
|
_ttys_re=\S*
|
||||||
|
|
||||||
__pam_re=\(?pam_unix(?:\(\S+\))?\)?:?
|
__pam_re=\(?%(__pam_auth)s(?:\(\S+\))?\)?:?
|
||||||
_daemon = \S+
|
_daemon = \S+
|
||||||
|
|
||||||
failregex = ^%(__prefix_line)s%(__pam_re)s\s+authentication failure; logname=\S* uid=\S* euid=\S* tty=%(_ttys_re)s ruser=\S* rhost=<HOST>(?:\s+user=.*)?\s*$
|
failregex = ^%(__prefix_line)s%(__pam_re)s\s+authentication failure; logname=\S* uid=\S* euid=\S* tty=%(_ttys_re)s ruser=\S* rhost=<HOST>(?:\s+user=.*)?\s*$
|
||||||
|
|
|
@ -6,5 +6,7 @@
|
||||||
|
|
||||||
failregex = \/<HOST> Port\: [0-9]+ (TCP|UDP) Blocked$
|
failregex = \/<HOST> Port\: [0-9]+ (TCP|UDP) Blocked$
|
||||||
|
|
||||||
|
ignoreregex =
|
||||||
|
|
||||||
# Author: Pacop <pacoparu@gmail.com>
|
# Author: Pacop <pacoparu@gmail.com>
|
||||||
|
|
||||||
|
|
|
@ -9,9 +9,9 @@ before = common.conf
|
||||||
|
|
||||||
_daemon = postfix/(submission/)?smtp(d|s)
|
_daemon = postfix/(submission/)?smtp(d|s)
|
||||||
|
|
||||||
failregex = ^%(__prefix_line)swarning: [-._\w]+\[<HOST>\]: SASL ((?i)LOGIN|PLAIN|(?:CRAM|DIGEST)-MD5) authentication failed(: [ A-Za-z0-9+/]*={0,2})?\s*$
|
failregex = ^%(__prefix_line)swarning: [-._\w]+\[<HOST>\]: SASL ((?i)LOGIN|PLAIN|(?:CRAM|DIGEST)-MD5) authentication failed(: [ A-Za-z0-9+/:]*={0,2})?\s*$
|
||||||
|
|
||||||
ignoreregex =
|
ignoreregex = authentication failed: Connection lost to authentication server$
|
||||||
|
|
||||||
[Init]
|
[Init]
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
failregex = ^\s+\d\s<HOST>\s+[A-Z_]+_DENIED/403 .*$
|
failregex = ^\s+\d\s<HOST>\s+[A-Z_]+_DENIED/403 .*$
|
||||||
^\s+\d\s<HOST>\s+NONE/405 .*$
|
^\s+\d\s<HOST>\s+NONE/405 .*$
|
||||||
|
|
||||||
|
ignoreregex =
|
||||||
|
|
||||||
# Author: Daniel Black
|
# Author: Daniel Black
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
failregex = ^ \[LOGIN_ERROR\].*from <HOST>: Unknown user or password incorrect\.$
|
failregex = ^ \[LOGIN_ERROR\].*from <HOST>: Unknown user or password incorrect\.$
|
||||||
|
|
||||||
|
ignoreregex =
|
||||||
|
|
||||||
[Init]
|
[Init]
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
failregex = ^ LOG\d\[\d+:\d+\]:\ SSL_accept from <HOST>:\d+ : (?P<CODE>[\dA-F]+): error:(?P=CODE):SSL routines:SSL3_GET_CLIENT_CERTIFICATE:peer did not return a certificate$
|
failregex = ^ LOG\d\[\d+:\d+\]:\ SSL_accept from <HOST>:\d+ : (?P<CODE>[\dA-F]+): error:(?P=CODE):SSL routines:SSL3_GET_CLIENT_CERTIFICATE:peer did not return a certificate$
|
||||||
|
|
||||||
|
ignoreregex =
|
||||||
|
|
||||||
# DEV NOTES:
|
# DEV NOTES:
|
||||||
#
|
#
|
||||||
# Author: Daniel Black
|
# Author: Daniel Black
|
||||||
|
|
|
@ -10,7 +10,7 @@ before = common.conf
|
||||||
|
|
||||||
[Definition]
|
[Definition]
|
||||||
|
|
||||||
__pam_re=\(?pam_unix(?:\(\S+\))?\)?:?
|
__pam_re=\(?%(__pam_auth)s(?:\(\S+\))?\)?:?
|
||||||
_daemon = vsftpd
|
_daemon = vsftpd
|
||||||
|
|
||||||
failregex = ^%(__prefix_line)s%(__pam_re)s\s+authentication failure; logname=\S* uid=\S* euid=\S* tty=(ftp)? ruser=\S* rhost=<HOST>(?:\s+user=.*)?\s*$
|
failregex = ^%(__prefix_line)s%(__pam_re)s\s+authentication failure; logname=\S* uid=\S* euid=\S* tty=(ftp)? ruser=\S* rhost=<HOST>(?:\s+user=.*)?\s*$
|
||||||
|
|
|
@ -11,7 +11,7 @@ before = common.conf
|
||||||
[Definition]
|
[Definition]
|
||||||
|
|
||||||
_daemon = wu-ftpd
|
_daemon = wu-ftpd
|
||||||
__pam_re=\(?pam_unix(?:\(wu-ftpd:auth\))?\)?:?
|
__pam_re=\(?%(__pam_auth)s(?:\(wu-ftpd:auth\))?\)?:?
|
||||||
|
|
||||||
failregex = ^%(__prefix_line)sfailed login from \S+ \[<HOST>\]\s*$
|
failregex = ^%(__prefix_line)sfailed login from \S+ \[<HOST>\]\s*$
|
||||||
^%(__prefix_line)s%(__pam_re)s\s+authentication failure; logname=\S* uid=\S* euid=\S* tty=(ftp)? ruser=\S* rhost=<HOST>(?:\s+user=.*)?\s*$
|
^%(__prefix_line)s%(__pam_re)s\s+authentication failure; logname=\S* uid=\S* euid=\S* tty=(ftp)? ruser=\S* rhost=<HOST>(?:\s+user=.*)?\s*$
|
||||||
|
|
|
@ -277,6 +277,14 @@ logpath = %(apache_error_log)s
|
||||||
maxretry = 2
|
maxretry = 2
|
||||||
|
|
||||||
|
|
||||||
|
[apache-fakegooglebot]
|
||||||
|
|
||||||
|
port = http,https
|
||||||
|
logpath = %(apache_access_log)s
|
||||||
|
maxretry = 1
|
||||||
|
ignorecommand = %(ignorecommands_dir)s/apache-fakegooglebot <ip>
|
||||||
|
|
||||||
|
|
||||||
[apache-modsecurity]
|
[apache-modsecurity]
|
||||||
|
|
||||||
port = http,https
|
port = http,https
|
||||||
|
|
|
@ -61,3 +61,6 @@ dovecot_log = %(syslog_mail_warn)s
|
||||||
solidpop3d_log = %(syslog_local0)s
|
solidpop3d_log = %(syslog_local0)s
|
||||||
|
|
||||||
mysql_log = %(syslog_daemon)s
|
mysql_log = %(syslog_daemon)s
|
||||||
|
|
||||||
|
# Directory with ignorecommand scripts
|
||||||
|
ignorecommands_dir = /etc/fail2ban/filter.d/ignorecommands
|
||||||
|
|
|
@ -50,17 +50,17 @@ class FilterReader(DefinitionInitConfigReader):
|
||||||
def getCombined(self):
|
def getCombined(self):
|
||||||
combinedopts = dict(list(self._opts.items()) + list(self._initOpts.items()))
|
combinedopts = dict(list(self._opts.items()) + list(self._initOpts.items()))
|
||||||
if not len(combinedopts):
|
if not len(combinedopts):
|
||||||
return {};
|
return {}
|
||||||
opts = CommandAction.substituteRecursiveTags(combinedopts)
|
opts = CommandAction.substituteRecursiveTags(combinedopts)
|
||||||
if not opts:
|
if not opts:
|
||||||
raise ValueError('recursive tag definitions unable to be resolved')
|
raise ValueError('recursive tag definitions unable to be resolved')
|
||||||
return opts;
|
return opts
|
||||||
|
|
||||||
def convert(self):
|
def convert(self):
|
||||||
stream = list()
|
stream = list()
|
||||||
opts = self.getCombined()
|
opts = self.getCombined()
|
||||||
if not len(opts):
|
if not len(opts):
|
||||||
return stream;
|
return stream
|
||||||
for opt, value in opts.iteritems():
|
for opt, value in opts.iteritems():
|
||||||
if opt == "failregex":
|
if opt == "failregex":
|
||||||
for regex in value.split('\n'):
|
for regex in value.split('\n'):
|
||||||
|
|
|
@ -149,7 +149,10 @@ class AsyncServer(asyncore.dispatcher):
|
||||||
self.__init = True
|
self.__init = True
|
||||||
# TODO Add try..catch
|
# TODO Add try..catch
|
||||||
# There's a bug report for Python 2.6/3.0 that use_poll=True yields some 2.5 incompatibilities:
|
# There's a bug report for Python 2.6/3.0 that use_poll=True yields some 2.5 incompatibilities:
|
||||||
logSys.debug("Detected Python 2.6 or greater. asyncore.loop() not using poll")
|
if sys.version_info >= (2, 7) and sys.version_info < (2, 8): # if python 2.7 ...
|
||||||
|
logSys.debug("Detected Python 2.7. asyncore.loop() using poll")
|
||||||
|
asyncore.loop(use_poll=True) # workaround for the "Bad file descriptor" issue on Python 2.7, gh-161
|
||||||
|
else:
|
||||||
asyncore.loop(use_poll=False) # fixes the "Unexpected communication problem" issue on Python 2.6 and 3.0
|
asyncore.loop(use_poll=False) # fixes the "Unexpected communication problem" issue on Python 2.6 and 3.0
|
||||||
|
|
||||||
##
|
##
|
||||||
|
|
|
@ -338,6 +338,10 @@ class Filter(JailThread):
|
||||||
logSys.debug("Remove " + ip + " from ignore list")
|
logSys.debug("Remove " + ip + " from ignore list")
|
||||||
self.__ignoreIpList.remove(ip)
|
self.__ignoreIpList.remove(ip)
|
||||||
|
|
||||||
|
def logIgnoreIp(self, ip, log_ignore, ignore_source="unknown source"):
|
||||||
|
if log_ignore:
|
||||||
|
logSys.info("[%s] Ignore %s by %s" % (self.jail.name, ip, ignore_source))
|
||||||
|
|
||||||
def getIgnoreIP(self):
|
def getIgnoreIP(self):
|
||||||
return self.__ignoreIpList
|
return self.__ignoreIpList
|
||||||
|
|
||||||
|
@ -349,7 +353,7 @@ class Filter(JailThread):
|
||||||
# @param ip IP address
|
# @param ip IP address
|
||||||
# @return True if IP address is in ignore list
|
# @return True if IP address is in ignore list
|
||||||
|
|
||||||
def inIgnoreIPList(self, ip):
|
def inIgnoreIPList(self, ip, log_ignore=False):
|
||||||
for i in self.__ignoreIpList:
|
for i in self.__ignoreIpList:
|
||||||
# An empty string is always false
|
# An empty string is always false
|
||||||
if i == "":
|
if i == "":
|
||||||
|
@ -369,16 +373,20 @@ class Filter(JailThread):
|
||||||
# Check if IP in DNS
|
# Check if IP in DNS
|
||||||
ips = DNSUtils.dnsToIp(i)
|
ips = DNSUtils.dnsToIp(i)
|
||||||
if ip in ips:
|
if ip in ips:
|
||||||
|
self.logIgnoreIp(ip, log_ignore, ignore_source="dns")
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
if a == b:
|
if a == b:
|
||||||
|
self.logIgnoreIp(ip, log_ignore, ignore_source="ip")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if self.__ignoreCommand:
|
if self.__ignoreCommand:
|
||||||
command = CommandAction.replaceTag(self.__ignoreCommand, { 'ip': ip } )
|
command = CommandAction.replaceTag(self.__ignoreCommand, { 'ip': ip } )
|
||||||
logSys.debug('ignore command: ' + command)
|
logSys.debug('ignore command: ' + command)
|
||||||
return CommandAction.executeCmd(command)
|
ret_ignore = CommandAction.executeCmd(command)
|
||||||
|
self.logIgnoreIp(ip, log_ignore and ret_ignore, ignore_source="command")
|
||||||
|
return ret_ignore
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -418,8 +426,7 @@ class Filter(JailThread):
|
||||||
logSys.debug("Ignore line since time %s < %s - %s"
|
logSys.debug("Ignore line since time %s < %s - %s"
|
||||||
% (unixTime, MyTime.time(), self.getFindTime()))
|
% (unixTime, MyTime.time(), self.getFindTime()))
|
||||||
break
|
break
|
||||||
if self.inIgnoreIPList(ip):
|
if self.inIgnoreIPList(ip, log_ignore=True):
|
||||||
logSys.info("[%s] Ignore %s" % (self.jail.name, ip))
|
|
||||||
continue
|
continue
|
||||||
logSys.info("[%s] Found %s" % (self.jail.name, ip))
|
logSys.info("[%s] Found %s" % (self.jail.name, ip))
|
||||||
## print "D: Adding a ticket for %s" % ((ip, unixTime, [line]),)
|
## print "D: Adding a ticket for %s" % ((ip, unixTime, [line]),)
|
||||||
|
@ -852,6 +859,14 @@ class DNSUtils:
|
||||||
% (dns, e))
|
% (dns, e))
|
||||||
return list()
|
return list()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def ipToName(ip):
|
||||||
|
try:
|
||||||
|
return socket.gethostbyaddr(ip)[0]
|
||||||
|
except socket.error, e:
|
||||||
|
logSys.debug("Unable to find a name for the IP %s: %s" % (ip, e))
|
||||||
|
return None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def searchIP(text):
|
def searchIP(text):
|
||||||
""" Search if an IP address if directly available and return
|
""" Search if an IP address if directly available and return
|
||||||
|
|
|
@ -213,7 +213,7 @@ class Jail:
|
||||||
if self.database is not None:
|
if self.database is not None:
|
||||||
for ticket in self.database.getBansMerged(
|
for ticket in self.database.getBansMerged(
|
||||||
jail=self, bantime=self.actions.getBanTime()):
|
jail=self, bantime=self.actions.getBanTime()):
|
||||||
if not self.filter.inIgnoreIPList(ticket.getIP()):
|
if not self.filter.inIgnoreIPList(ticket.getIP(), log_ignore=True):
|
||||||
self.__queue.put(ticket)
|
self.__queue.put(ticket)
|
||||||
logSys.info("Jail '%s' started" % self.name)
|
logSys.info("Jail '%s' started" % self.name)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Apache 2.2
|
||||||
|
# failJSON: { "time": "2015-01-31T14:29:44", "match": true, "host": "66.249.66.1" }
|
||||||
|
66.249.66.1 - - - [31/Jan/2015:14:29:44 ] example.com "GET / HTTP/1.1" 200 814 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" + 293 1149 546
|
||||||
|
# failJSON: { "time": "2015-01-31T14:29:44", "match": false, "host": "93.184.216.34" }
|
||||||
|
93.184.216.34 - - - [31/Jan/2015:14:29:44 ] example.com "GET / HTTP/1.1" 200 814 "-" "NOT A __GOOGLE_BOT__" + 293 1149 546
|
|
@ -31,6 +31,12 @@ Jul 02 13:49:32 hostname dovecot[442]: dovecot: auth(default): pam(account@MYSER
|
||||||
# failJSON: { "time": "2013-08-11T03:56:40", "match": true , "host": "1.2.3.4" }
|
# failJSON: { "time": "2013-08-11T03:56:40", "match": true , "host": "1.2.3.4" }
|
||||||
2013-08-11 03:56:40 auth-worker(default): Info: pam(username,1.2.3.4): pam_authenticate() failed: Authentication failure (password mismatch?)
|
2013-08-11 03:56:40 auth-worker(default): Info: pam(username,1.2.3.4): pam_authenticate() failed: Authentication failure (password mismatch?)
|
||||||
|
|
||||||
|
# failJSON: { "time": "2005-01-29T05:32:50", "match": true , "host": "1.2.3.4" }
|
||||||
|
Jan 29 05:32:50 mail dovecot: auth-worker(304): pam(username,1.2.3.4): pam_authenticate() failed: Authentication failure (password mismatch?)
|
||||||
|
|
||||||
|
# failJSON: { "time": "2005-01-29T05:13:40", "match": true , "host": "1.2.3.4" }
|
||||||
|
Jan 29 05:13:40 mail dovecot: auth-worker(31326): pam(username,1.2.3.4): unknown user
|
||||||
|
|
||||||
# failJSON: { "time": "2005-04-19T05:22:20", "match": true , "host": "80.255.3.104" }
|
# failJSON: { "time": "2005-04-19T05:22:20", "match": true , "host": "80.255.3.104" }
|
||||||
Apr 19 05:22:20 vm5 auth: pam_unix(dovecot:auth): authentication failure; logname= uid=0 euid=0 tty=dovecot ruser=informix rhost=80.255.3.104
|
Apr 19 05:22:20 vm5 auth: pam_unix(dovecot:auth): authentication failure; logname= uid=0 euid=0 tty=dovecot ruser=informix rhost=80.255.3.104
|
||||||
|
|
||||||
|
|
|
@ -12,3 +12,12 @@ Sep 6 00:44:56 trianon postfix/submission/smtpd[11538]: warning: unknown[82.221
|
||||||
#4 Example from postfix post-debian changes to rename to add "submission" to syslog name + downcase
|
#4 Example from postfix post-debian changes to rename to add "submission" to syslog name + downcase
|
||||||
# failJSON: { "time": "2004-09-06T00:44:57", "match": true , "host": "82.221.106.233" }
|
# failJSON: { "time": "2004-09-06T00:44:57", "match": true , "host": "82.221.106.233" }
|
||||||
Sep 6 00:44:57 trianon postfix/submission/smtpd[11538]: warning: unknown[82.221.106.233]: SASL login authentication failed: UGFzc3dvcmQ6
|
Sep 6 00:44:57 trianon postfix/submission/smtpd[11538]: warning: unknown[82.221.106.233]: SASL login authentication failed: UGFzc3dvcmQ6
|
||||||
|
|
||||||
|
#5 Example to add :
|
||||||
|
# failJSON: { "time": "2005-01-29T08:11:45", "match": true , "host": "1.1.1.1" }
|
||||||
|
Jan 29 08:11:45 mail postfix/smtpd[10752]: warning: unknown[1.1.1.1]: SASL LOGIN authentication failed: Password:
|
||||||
|
|
||||||
|
#6 Example to ignore because due to a failed attempt to connect to authentication service - no malicious activities whatsoever
|
||||||
|
# failJSON: { "time": "2005-02-03T08:29:28", "match": false , "host": "1.1.1.1" }
|
||||||
|
Feb 3 08:29:28 mail postfix/smtpd[21022]: warning: unknown[1.1.1.1]: SASL LOGIN authentication failed: Connection lost to authentication server
|
||||||
|
|
||||||
|
|
|
@ -266,6 +266,15 @@ class IgnoreIP(LogCaptureTestCase):
|
||||||
self.assertTrue(self.filter.inIgnoreIPList("10.0.0.1"))
|
self.assertTrue(self.filter.inIgnoreIPList("10.0.0.1"))
|
||||||
self.assertFalse(self.filter.inIgnoreIPList("10.0.0.0"))
|
self.assertFalse(self.filter.inIgnoreIPList("10.0.0.0"))
|
||||||
|
|
||||||
|
def testIgnoreCauseOK(self):
|
||||||
|
ip = "93.184.216.34"
|
||||||
|
for ignore_source in ["dns", "ip", "command"]:
|
||||||
|
self.filter.logIgnoreIp(ip, True, ignore_source=ignore_source)
|
||||||
|
self.assertTrue(self._is_logged("[%s] Ignore %s by %s" % (self.jail.name, ip, ignore_source)))
|
||||||
|
|
||||||
|
def testIgnoreCauseNOK(self):
|
||||||
|
self.filter.logIgnoreIp("example.com", False, ignore_source="NOT_LOGGED")
|
||||||
|
self.assertFalse(self._is_logged("[%s] Ignore %s by %s" % (self.jail.name, "example.com", "NOT_LOGGED")))
|
||||||
|
|
||||||
class IgnoreIPDNS(IgnoreIP):
|
class IgnoreIPDNS(IgnoreIP):
|
||||||
|
|
||||||
|
@ -1011,6 +1020,12 @@ class DNSUtilsTests(unittest.TestCase):
|
||||||
else:
|
else:
|
||||||
self.assertEqual(res, [])
|
self.assertEqual(res, [])
|
||||||
|
|
||||||
|
def testIpToName(self):
|
||||||
|
res = DNSUtils.ipToName('66.249.66.1')
|
||||||
|
self.assertEqual(res, 'crawl-66-249-66-1.googlebot.com')
|
||||||
|
res = DNSUtils.ipToName('10.0.0.0')
|
||||||
|
self.assertEqual(res, None)
|
||||||
|
|
||||||
class JailTests(unittest.TestCase):
|
class JailTests(unittest.TestCase):
|
||||||
|
|
||||||
def testSetBackend_gh83(self):
|
def testSetBackend_gh83(self):
|
||||||
|
|
|
@ -113,7 +113,7 @@ class SetupTest(unittest.TestCase):
|
||||||
# clean up
|
# clean up
|
||||||
shutil.rmtree(tmp)
|
shutil.rmtree(tmp)
|
||||||
# remove build directory
|
# remove build directory
|
||||||
os.system("%s %s clean --all >/dev/null"
|
os.system("%s %s clean --all >/dev/null 2>&1"
|
||||||
% (sys.executable, self.setup))
|
% (sys.executable, self.setup))
|
||||||
|
|
||||||
class TestsUtilsTest(unittest.TestCase):
|
class TestsUtilsTest(unittest.TestCase):
|
||||||
|
|
|
@ -141,7 +141,8 @@ def testSampleRegexsFactory(name):
|
||||||
|
|
||||||
return testFilter
|
return testFilter
|
||||||
|
|
||||||
for filter_ in filter(lambda x: not x.endswith('common.conf'), os.listdir(os.path.join(CONFIG_DIR, "filter.d"))):
|
for filter_ in filter(lambda x: not x.endswith('common.conf') and x.endswith('.conf'),
|
||||||
|
os.listdir(os.path.join(CONFIG_DIR, "filter.d"))):
|
||||||
filterName = filter_.rpartition(".")[0]
|
filterName = filter_.rpartition(".")[0]
|
||||||
if not filterName.startswith('.'):
|
if not filterName.startswith('.'):
|
||||||
setattr(
|
setattr(
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
# Provides: fail2ban
|
# Provides: fail2ban
|
||||||
# Required-Start: $local_fs $remote_fs
|
# Required-Start: $local_fs $remote_fs
|
||||||
# Required-Stop: $local_fs $remote_fs
|
# Required-Stop: $local_fs $remote_fs
|
||||||
# Should-Start: $time $network $syslog iptables firehol shorewall ipmasq arno-iptables-firewall iptables-persistent ferm
|
# Should-Start: $time $network $syslog $named iptables firehol shorewall ipmasq arno-iptables-firewall iptables-persistent ferm ufw
|
||||||
# Should-Stop: $network $syslog iptables firehol shorewall ipmasq arno-iptables-firewall iptables-persistent ferm
|
# Should-Stop: $network $syslog $named iptables firehol shorewall ipmasq arno-iptables-firewall iptables-persistent ferm ufw
|
||||||
# Default-Start: 2 3 4 5
|
# Default-Start: 2 3 4 5
|
||||||
# Default-Stop: 0 1 6
|
# Default-Stop: 0 1 6
|
||||||
# Short-Description: Start/stop fail2ban
|
# Short-Description: Start/stop fail2ban
|
||||||
|
|
3
setup.py
3
setup.py
|
@ -124,6 +124,9 @@ setup(
|
||||||
('/etc/fail2ban/filter.d',
|
('/etc/fail2ban/filter.d',
|
||||||
glob("config/filter.d/*.conf")
|
glob("config/filter.d/*.conf")
|
||||||
),
|
),
|
||||||
|
('/etc/fail2ban/filter.d/ignorecommands',
|
||||||
|
glob("config/filter.d/ignorecommands/*")
|
||||||
|
),
|
||||||
('/etc/fail2ban/action.d',
|
('/etc/fail2ban/action.d',
|
||||||
glob("config/action.d/*.conf") +
|
glob("config/action.d/*.conf") +
|
||||||
glob("config/action.d/*.py")
|
glob("config/action.d/*.py")
|
||||||
|
|
Loading…
Reference in New Issue