From 4a1fd888f030a6a329e2a3fdf51130b8ee76d570 Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Sun, 11 Dec 2016 00:49:09 -0500 Subject: [PATCH 01/33] Carry on development --- ChangeLog | 17 ++++++++++++++++- README.md | 2 +- RELEASE | 2 +- fail2ban/version.py | 2 +- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0852a360..b9fadce5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,13 +6,28 @@ Fail2Ban: Changelog =================== -ver. 0.9.6 (2016/12/10) - stretch-is-coming + +ver. 0.9.x (2016/??/??) - wanna-be-released ----------- 0.9.x line is no longer heavily developed. If you are interested in new features (e.g. IPv6 support), please consider 0.10 branch and its releases. +### Fixes + +### New Features +* New Actions: + +* New Filters: + + +### Enhancements + + +ver. 0.9.6 (2016/12/10) - stretch-is-coming +----------- + ### Fixes * Misleading add resp. enable of (already available) jail in database, that induced a subsequent error: last position of log file will be never retrieved (gh-795) diff --git a/README.md b/README.md index 998e43e2..3f0e3253 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ / _|__ _(_) |_ ) |__ __ _ _ _ | _/ _` | | |/ /| '_ \/ _` | ' \ |_| \__,_|_|_/___|_.__/\__,_|_||_| - v0.9.6 2016/12/10 + v0.9.6.dev0 2016/??/?? ## Fail2Ban: ban hosts that cause multiple authentication errors diff --git a/RELEASE b/RELEASE index b879fa20..c4f62d7a 100644 --- a/RELEASE +++ b/RELEASE @@ -190,7 +190,7 @@ Post Release Add the following to the top of the ChangeLog:: - ver. 0.9.7 (2016/XX/XXX) - wanna-be-released + ver. 0.9.8 (2016/XX/XXX) - wanna-be-released ----------- ### Fixes diff --git a/fail2ban/version.py b/fail2ban/version.py index 194918d7..c2a8dc59 100644 --- a/fail2ban/version.py +++ b/fail2ban/version.py @@ -24,4 +24,4 @@ __author__ = "Cyril Jaquier, Yaroslav Halchenko, Steven Hiscocks, Daniel Black" __copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2005-2016 Yaroslav Halchenko, 2013-2014 Steven Hiscocks, Daniel Black" __license__ = "GPL-v2+" -version = "0.9.6" +version = "0.9.6.dev0" From 31a1560eaae663cb3b740829e3262198a909d1c4 Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Sun, 11 Dec 2016 15:13:11 -0500 Subject: [PATCH 02/33] minor typos (thanks Vincent Lefevre, Debian #847785) --- config/action.d/firewallcmd-rich-logging.conf | 2 +- config/action.d/firewallcmd-rich-rules.conf | 2 +- config/filter.d/assp.conf | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/action.d/firewallcmd-rich-logging.conf b/config/action.d/firewallcmd-rich-logging.conf index 1b88c2d9..c4a8b6f7 100644 --- a/config/action.d/firewallcmd-rich-logging.conf +++ b/config/action.d/firewallcmd-rich-logging.conf @@ -29,7 +29,7 @@ actioncheck = # firewall-cmd --zone= --add-rich-rule="rule family='ipv4' source address='' port port='' protocol='' log prefix='f2b-' level='' limit value='/m' " # service name example: # firewall-cmd --zone= --add-rich-rule="rule family='ipv4' source address='' service name='' log prefix='f2b-' level='' limit value='/m' " -# Because rich rules can only handle single or a range of ports we must split ports and execute the command for each port. Ports can be single and ranges seperated by a comma or space for an example: http, https, 22-60, 18 smtp +# Because rich rules can only handle single or a range of ports we must split ports and execute the command for each port. Ports can be single and ranges separated by a comma or space for an example: http, https, 22-60, 18 smtp actionban = ports=""; for p in $(echo $ports | tr ", " " "); do firewall-cmd --add-rich-rule="rule family='ipv4' source address='' port port='$p' protocol='' log prefix='f2b-' level='' limit value='/m' "; done diff --git a/config/action.d/firewallcmd-rich-rules.conf b/config/action.d/firewallcmd-rich-rules.conf index 4e39df54..5bf10b03 100644 --- a/config/action.d/firewallcmd-rich-rules.conf +++ b/config/action.d/firewallcmd-rich-rules.conf @@ -27,7 +27,7 @@ actioncheck = # firewall-cmd --zone= --add-rich-rule="rule family='ipv4' source address='' port port='' protocol='' " # service name example: # firewall-cmd --zone= --add-rich-rule="rule family='ipv4' source address='' service name='' " -# Because rich rules can only handle single or a range of ports we must split ports and execute the command for each port. Ports can be single and ranges seperated by a comma or space for an example: http, https, 22-60, 18 smtp +# Because rich rules can only handle single or a range of ports we must split ports and execute the command for each port. Ports can be single and ranges separated by a comma or space for an example: http, https, 22-60, 18 smtp actionban = ports=""; for p in $(echo $ports | tr ", " " "); do firewall-cmd --add-rich-rule="rule family='ipv4' source address='' port port='$p' protocol='' "; done diff --git a/config/filter.d/assp.conf b/config/filter.d/assp.conf index 278e25cb..ddf18f33 100644 --- a/config/filter.d/assp.conf +++ b/config/filter.d/assp.conf @@ -8,7 +8,7 @@ # [Definition] -# Note: First three failregex matches below are for ASSP V1 with the remaining being designed for V2. Deleting the V1 regex is recommended but I left it in for compatibilty reasons. +# Note: First three failregex matches below are for ASSP V1 with the remaining being designed for V2. Deleting the V1 regex is recommended but I left it in for compatibility reasons. __assp_actions = (?:dropping|refusing) From 2009f1c4346597dcc4fd27151d220ea4a7806fdd Mon Sep 17 00:00:00 2001 From: sebres Date: Tue, 10 Jan 2017 10:59:53 +0100 Subject: [PATCH 03/33] fail2ban-regex: fix for systemd-journal (see gh-1657) --- fail2ban/client/fail2banregex.py | 31 ++++++++++++++----------------- fail2ban/server/filtersystemd.py | 8 ++++++++ 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/fail2ban/client/fail2banregex.py b/fail2ban/client/fail2banregex.py index 71f50955..13fa35d9 100755 --- a/fail2ban/client/fail2banregex.py +++ b/fail2ban/client/fail2banregex.py @@ -43,12 +43,12 @@ from optparse import OptionParser, Option from ConfigParser import NoOptionError, NoSectionError, MissingSectionHeaderError try: - from systemd import journal from ..server.filtersystemd import FilterSystemd except ImportError: - journal = None + FilterSystemd = None from ..version import version +from .jailreader import JailReader from .filterreader import FilterReader from ..server.filter import Filter, FileContainer from ..server.failregex import RegexException @@ -82,7 +82,7 @@ def pprint_list(l, header=None): s = '' output( s + "| " + "\n| ".join(l) + '\n`-' ) -def journal_lines_gen(myjournal): +def journal_lines_gen(flt, myjournal): # pragma: no cover while True: try: entry = myjournal.get_next() @@ -90,7 +90,7 @@ def journal_lines_gen(myjournal): continue if not entry: break - yield FilterSystemd.formatJournalEntry(entry) + yield flt.formatJournalEntry(entry) def get_opt_parser(): # use module docstring for help output @@ -513,25 +513,22 @@ class Fail2banRegex(object): except IOError as e: output( e ) return False - elif cmd_log == "systemd-journal": # pragma: no cover - if not journal: + elif cmd_log.startswith("systemd-journal"): # pragma: no cover + if not FilterSystemd: output( "Error: systemd library not found. Exiting..." ) return False - myjournal = journal.Reader(converters={'__CURSOR': lambda x: x}) + output( "Use systemd journal" ) + output( "Use encoding : %s" % self.encoding ) + backend, beArgs = JailReader.extractOptions(cmd_log) + flt = FilterSystemd(None, **beArgs) + flt.setLogEncoding(self.encoding) + myjournal = flt.getJournalReader() journalmatch = self._journalmatch self.setDatePattern(None) if journalmatch: - try: - for element in journalmatch: - if element == "+": - myjournal.add_disjunction() - else: - myjournal.add_match(element) - except ValueError: - output( "Error: Invalid journalmatch: %s" % shortstr(" ".join(journalmatch)) ) - return False + flt.addJournalMatch(journalmatch) output( "Use journal match : %s" % " ".join(journalmatch) ) - test_lines = journal_lines_gen(myjournal) + test_lines = journal_lines_gen(flt, myjournal) else: output( "Use single line : %s" % shortstr(cmd_log) ) test_lines = [ cmd_log ] diff --git a/fail2ban/server/filtersystemd.py b/fail2ban/server/filtersystemd.py index 3023155c..908112a7 100644 --- a/fail2ban/server/filtersystemd.py +++ b/fail2ban/server/filtersystemd.py @@ -174,6 +174,14 @@ class FilterSystemd(JournalFilter): # pragma: systemd no cover v = Filter.uni_decode(x, self.getLogEncoding()) return v + ## + # Get journal reader + # + # @return journal reader + + def getJournalReader(self): + return self.__journal + ## # Format journal log entry into syslog style # From f8d35a7c9c8b783b6cc40ef13c0462a5ad8dcaf0 Mon Sep 17 00:00:00 2001 From: sebres Date: Tue, 10 Jan 2017 11:16:17 +0100 Subject: [PATCH 04/33] changelog entry --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index b9fadce5..0fd91b70 100644 --- a/ChangeLog +++ b/ChangeLog @@ -15,6 +15,7 @@ new features (e.g. IPv6 support), please consider 0.10 branch and its releases. ### Fixes +* Fixed a systemd-journal handling in fail2ban-regex (gh-1657) ### New Features * New Actions: From a9523aefbb9b179e6a18ae163d44dc9f9b4b7695 Mon Sep 17 00:00:00 2001 From: sebres Date: Tue, 10 Jan 2017 12:51:11 +0100 Subject: [PATCH 05/33] sshd.conf: fixed non-anchored part of regex (misleading match of colon inside IPv6 address instead of `: ` in the reason-part by missing space). --- ChangeLog | 4 ++++ config/filter.d/sshd.conf | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 0fd91b70..126bd2e0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -16,6 +16,10 @@ releases. ### Fixes * Fixed a systemd-journal handling in fail2ban-regex (gh-1657) +* filter.d/sshd.conf + - Fixed non-anchored part of failregex (misleading match of colon inside + IPv6 address instead of `: ` in the reason-part by missing space, gh-1658) + (0.10th resp. IPv6 relevant only, amend for gh-1479) ### New Features * New Actions: diff --git a/config/filter.d/sshd.conf b/config/filter.d/sshd.conf index 35cd8754..d5a66cc8 100644 --- a/config/filter.d/sshd.conf +++ b/config/filter.d/sshd.conf @@ -20,7 +20,7 @@ _daemon = sshd failregex = ^%(__prefix_line)s(?:error: PAM: )?[aA]uthentication (?:failure|error|failed) for .* from ( via \S+)?\s*$ ^%(__prefix_line)s(?:error: PAM: )?User not known to the underlying authentication module for .* from \s*$ - ^%(__prefix_line)sFailed \S+ for (?Pinvalid user )?(?P(?P\S+)|(?(cond_inv)(?:(?! from ).)*?|[^:]+)) from (?: port \d+)?(?: ssh\d*)?(?(cond_user):|(?:(?:(?! from ).)*)$) + ^%(__prefix_line)sFailed \S+ for (?Pinvalid user )?(?P(?P\S+)|(?(cond_inv)(?:(?! from ).)*?|[^:]+)) from (?: port \d+)?(?: ssh\d*)?(?(cond_user): |(?:(?:(?! from ).)*)$) ^%(__prefix_line)sROOT LOGIN REFUSED.* FROM \s*$ ^%(__prefix_line)s[iI](?:llegal|nvalid) user .*? from (?: port \d+)?\s*$ ^%(__prefix_line)sUser .+ from not allowed because not listed in AllowUsers\s*$ From 6187431629f2ee3a0cee8d1e60c286d434567b83 Mon Sep 17 00:00:00 2001 From: Christoph Theis Date: Tue, 17 Jan 2017 11:48:25 +0100 Subject: [PATCH 06/33] #1667: Wrong paths for apache and nginx under FreeBSD --- config/paths-freebsd.conf | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/config/paths-freebsd.conf b/config/paths-freebsd.conf index fd788ab4..91b23636 100644 --- a/config/paths-freebsd.conf +++ b/config/paths-freebsd.conf @@ -34,13 +34,13 @@ auditd_log = /dev/null # http://svnweb.freebsd.org/ports/head/www/apache24/files/patch-config.layout # http://svnweb.freebsd.org/ports/head/www/apache22/files/patch-config.layout -apache_error_log = /usr/local/www/logs/*error[_.]log +apache_error_log = /var/log/httpd-error.log -apache_access_log = /usr/local/www/logs/*access[_.]log +apache_access_log = /var/log/httpd-access.log # http://svnweb.freebsd.org/ports/head/www/nginx/Makefile?view=markup -nginx_error_log = /var/log/nginx-error.log +nginx_error_log = /var/log/nginx/error.log -nginx_access_log = /var/log/nginx-access.log +nginx_access_log = /var/log/nginx/access.log From fe76cd9b7db541270117c4af1f88f209852e6a1e Mon Sep 17 00:00:00 2001 From: Christoph Theis Date: Tue, 17 Jan 2017 14:05:20 +0100 Subject: [PATCH 07/33] #1667: changelog entry --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index 126bd2e0..b37d7a08 100644 --- a/ChangeLog +++ b/ChangeLog @@ -20,6 +20,8 @@ releases. - Fixed non-anchored part of failregex (misleading match of colon inside IPv6 address instead of `: ` in the reason-part by missing space, gh-1658) (0.10th resp. IPv6 relevant only, amend for gh-1479) +* config/pathes-freebsd.conf + - Fixed filenames for apache and nginx log files (gh-1667) ### New Features * New Actions: From 1fe554dd2508db99c59763753de4df369b0c54b5 Mon Sep 17 00:00:00 2001 From: Juliano Jeziorny Date: Thu, 19 Jan 2017 14:30:25 +0100 Subject: [PATCH 08/33] Introduced Citrix Netscaler action --- ChangeLog | 8 ++++++++ config/action.d/netscaler.conf | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 config/action.d/netscaler.conf diff --git a/ChangeLog b/ChangeLog index 0fd91b70..843cb0a0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -26,6 +26,14 @@ releases. ### Enhancements +ver. 0.9.7 (2016/19/01) +----------- + +### New Features +* New Actions: + - action.d/netscaler: Block IPs on a Citrix Netscaler ADC (gh-1663) + + ver. 0.9.6 (2016/12/10) - stretch-is-coming ----------- diff --git a/config/action.d/netscaler.conf b/config/action.d/netscaler.conf new file mode 100644 index 00000000..87f7e7bf --- /dev/null +++ b/config/action.d/netscaler.conf @@ -0,0 +1,33 @@ +# Fail2ban Citrix Netscaler Action +# by Juliano Jeziorny +# juliano@jeziorny.eu +# +# The script will add offender IPs to a dataset on netscaler, the dataset can then be used to block the IPs at a cs/vserver or global level +# This dataset is then used to block IPs using responder policies on the netscaler. +# +# The script assumes using HTTPS with unsecure certificate to access the netscaler, +# if you have a valid certificate installed remove the -k from the curl lines, or if you want http change it accordingly (and remove the -k) +# +# This action depends on curl +# +# You need to populate the 3 options inside Init +# +# ns_host: IP or hostname of netslcaer appliance +# ns_auth: username:password, suggest base64 encoded for a little added security (echo -n "username:password" | base64) +# ns_dataset: Name of the netscaler dataset holding the IPs to be blocked. +# +# For further details on how to use it please check http://blog.ckzone.eu/2017/01/fail2ban-action-for-citrix-netscaler.html + +[Init] +ns_host = +ns_auth = +ns_dataset = + +[Definition] +actionstart = curl -kH 'Authorization: Basic ' https:///nitro/v1/config + +actioncheck = + +actionban = curl -k -H 'Authorization: Basic ' -X PUT -d '{"policydataset_value_binding":{"name":"","value":""}}' https:///nitro/v1/config/ + +actionunban = curl -H 'Authorization: Basic ' -X DELETE -k "https:///nitro/v1/config/policydataset_value_binding/?args=value:" From 75b252e47f19976aeb5a112b9b8e1786b2340500 Mon Sep 17 00:00:00 2001 From: "Serg G. Brester" Date: Thu, 19 Jan 2017 15:00:08 +0100 Subject: [PATCH 09/33] Update ChangeLog --- ChangeLog | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index 843cb0a0..7acd7635 100644 --- a/ChangeLog +++ b/ChangeLog @@ -19,6 +19,7 @@ releases. ### New Features * New Actions: + - action.d/netscaler: Block IPs on a Citrix Netscaler ADC (gh-1663) * New Filters: @@ -26,14 +27,6 @@ releases. ### Enhancements -ver. 0.9.7 (2016/19/01) ------------ - -### New Features -* New Actions: - - action.d/netscaler: Block IPs on a Citrix Netscaler ADC (gh-1663) - - ver. 0.9.6 (2016/12/10) - stretch-is-coming ----------- From a4d84264010ea0cb6c4bb044682e70a6c1db412a Mon Sep 17 00:00:00 2001 From: Christian Brandlehner Date: Fri, 20 Jan 2017 08:44:20 +0100 Subject: [PATCH 10/33] Support for IBM Domino SMTP task (#1603) filter.d/domino-smtp.conf --- config/filter.d/domino-smtp.conf | 47 +++++++++++++++++++++++++++ config/jail.conf | 5 +++ fail2ban/tests/files/logs/domino-smtp | 8 +++++ 3 files changed, 60 insertions(+) create mode 100644 config/filter.d/domino-smtp.conf create mode 100644 fail2ban/tests/files/logs/domino-smtp diff --git a/config/filter.d/domino-smtp.conf b/config/filter.d/domino-smtp.conf new file mode 100644 index 00000000..cdc17736 --- /dev/null +++ b/config/filter.d/domino-smtp.conf @@ -0,0 +1,47 @@ +# Fail2Ban configuration file for IBM Domino SMTP Server TASK to detect failed login attempts +# +# Author: Christian Brandlehner +# +# $Revision: 003 $ +# +# Configuration: +# Set the following Domino Server parameters in notes.ini: +# console_log_enabled=1 +# log_sessions=2 +# You also have to use a date and time format supported by fail2ban. Recommended notes.ini configuration is: +# DateOrder=DMY +# DateSeparator=- +# ClockType=24_Hour +# TimeSeparator=: +# +# Depending on your locale you might have to tweak the date and time format so fail2ban can read the log + +#[INCLUDES] +# Read common prefixes. If any customizations available -- read them from +# common.local +#before = common.conf + +[Definition] +# Option: failregex +# Notes.: regex to match the password failure messages in the logfile. The +# host must be matched by a group named "host". The tag "" can +# be used for standard IP/hostname matching and is only an alias for +# (?:::f{4,6}:)?(?P\S+) +# Values: TEXT +# +# Sample log entries (used different time formats and an extra sample with process info in front of date) +# 01-23-2009 19:54:51 SMTP Server: Authentication failed for user postmaster ; connecting host 1.2.3.4 +# [28325:00010-3735542592] 22-06-2014 09:56:12 smtp: postmaster [1.2.3.4] authentication failure using internet password +# 08-09-2014 06:14:27 smtp: postmaster [1.2.3.4] authentication failure using internet password +# 08-09-2014 06:14:27 SMTP Server: Authentication failed for user postmaster ; connecting host 1.2.3.4 + +__prefix = (?:\[[^\]]+\])?\s+ +failregex = ^%(__prefix)sSMTP Server: Authentication failed for user .*? \; connecting host $ + ^%(__prefix)ssmtp: (?:[^\[]+ )*\[\] authentication failure using internet password\s*$ +# Option: ignoreregex +# Notes.: regex to ignore. If this regex matches, the line is ignored. +# Values: TEXT +# + +ignoreregex = + diff --git a/config/jail.conf b/config/jail.conf index d80e3d0a..2d8567d6 100644 --- a/config/jail.conf +++ b/config/jail.conf @@ -853,3 +853,8 @@ logpath = /var/log/haproxy.log port = ldap,ldaps filter = slapd logpath = /var/log/slapd.log + +[domino-smtp] +port = smtp,ssmtp +filter = domino-smtp +logpath = /home/domino01/data/IBM_TECHNICAL_SUPPORT/console.log diff --git a/fail2ban/tests/files/logs/domino-smtp b/fail2ban/tests/files/logs/domino-smtp new file mode 100644 index 00000000..4987e7ea --- /dev/null +++ b/fail2ban/tests/files/logs/domino-smtp @@ -0,0 +1,8 @@ +# failJSON: { "time": "2005-07-03T23:07:20", "match": true , "host": "1.2.3.4" } +03-07-2005 23:07:20 SMTP Server: Authentication failed for user postmaster ; connecting host 1.2.3.4 +# failJSON: { "time": "2014-06-22T09:56:12", "match": true , "host": "1.2.3.4" } +[28325:00010-3735542592] 22-06-2014 09:56:12 smtp: postmaster [1.2.3.4] authentication failure using internet password +# failJSON: { "time": "2014-09-08T06:14:27", "match": true , "host": "1.2.3.4" } +08-09-2014 06:14:27 smtp: postmaster [1.2.3.4] authentication failure using internet password +# failJSON: { "time": "2016-11-07T22:21:20", "match": true , "host": "1.2.3.4" } +2016-11-07 22:21:20 smtp: postmaster [1.2.3.4] authentication failure using internet password From 5e08298b6b714977bddc9e62e45f138c2dffd00e Mon Sep 17 00:00:00 2001 From: "Serg G. Brester" Date: Fri, 20 Jan 2017 08:47:30 +0100 Subject: [PATCH 11/33] Update ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 14d2d898..50f5ee3f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -28,7 +28,7 @@ releases. - action.d/netscaler: Block IPs on a Citrix Netscaler ADC (gh-1663) * New Filters: - + - filter.d/domino-smtp: IBM Domino SMTP task (gh-1603) ### Enhancements From dd373dba9fdcb2318fcacff1dc91ed213b83937c Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 5 Oct 2015 21:18:16 +0200 Subject: [PATCH 12/33] test all config-regexp, that contains greedy catch-all before , that is hard-anchored at end or precise sub expression after ; new ssh rule(s) added: - Connection reset by peer (multi-line rule during authorization process); - No supported authentication methods available; Single line and multi-line expression optimized, added optional prefixes and suffix (logged from several ssh versions); closes gh-864 --- ChangeLog | 9 ++++++ config/filter.d/sendmail-reject.conf | 2 +- config/filter.d/sshd.conf | 46 ++++++++++++++++++---------- config/filter.d/suhosin.conf | 2 +- fail2ban/tests/files/logs/sshd | 24 +++++++++++++++ fail2ban/tests/samplestestcase.py | 26 ++++++++++++++++ 6 files changed, 90 insertions(+), 19 deletions(-) diff --git a/ChangeLog b/ChangeLog index 50f5ee3f..6f9d8069 100644 --- a/ChangeLog +++ b/ChangeLog @@ -71,6 +71,15 @@ ver. 0.9.6 (2016/12/10) - stretch-is-coming - optimized failregex to match all of "Failed any-method for ... from " (gh-1479) - eliminated possible complex injections (on user-name resp. auth-info, see gh-1479) - optional port part after host (see gh-1533, gh-1581) + - new aggressive rules (gh-864): + - Connection reset by peer (multi-line rule during authorization process) + - No supported authentication methods available + - single line and multi-line expression optimized, added optional prefixes + and suffix (logged from several ssh versions), according to gh-1206; +* filter.d/suhosin.conf + - greedy catch-all before `` fixed (potential vulnerability) +* Filter tests extended with check of all config-regexp, that contains greedy catch-all + before ``, that is hard-anchored at end or precise sub expression after `` ### New Features * New Actions: diff --git a/config/filter.d/sendmail-reject.conf b/config/filter.d/sendmail-reject.conf index 20d3648e..2f8fd882 100644 --- a/config/filter.d/sendmail-reject.conf +++ b/config/filter.d/sendmail-reject.conf @@ -25,7 +25,7 @@ failregex = ^%(__prefix_line)s\w{14}: ruleset=check_rcpt, arg1=(?P<\S+@\S ^%(__prefix_line)sruleset=check_relay, arg1=(?P\S+), arg2=, relay=((?P=dom) )?\[(\d+\.){3}\d+\]( \(may be forged\))?, reject=421 4\.3\.2 (Connection rate limit exceeded\.|Too many open connections\.)$ ^%(__prefix_line)s\w{14}: rejecting commands from (\S* )?\[\] due to pre-greeting traffic after \d+ seconds$ ^%(__prefix_line)s\w{14}: (\S+ )?\[\]: ((?i)expn|vrfy) \S+ \[rejected\]$ - ^(?P<__prefix>%(__prefix_line)s\w+: )<[^@]+@[^>]+>\.\.\. No such user here(?P=__prefix)from=<[^@]+@[^>]+>, size=\d+, class=\d+, nrcpts=\d+, bodytype=\w+, proto=E?SMTP, daemon=MTA, relay=\S+ \[\]$ + ^(?P<__prefix>%(__prefix_line)s\w+: )<[^@]+@[^>]+>\.\.\. No such user here$^(?P=__prefix)from=<[^@]+@[^>]+>, size=\d+, class=\d+, nrcpts=\d+, bodytype=\w+, proto=E?SMTP, daemon=MTA, relay=\S+ \[\]$ ignoreregex = diff --git a/config/filter.d/sshd.conf b/config/filter.d/sshd.conf index d5a66cc8..c04c0875 100644 --- a/config/filter.d/sshd.conf +++ b/config/filter.d/sshd.conf @@ -18,23 +18,35 @@ before = common.conf _daemon = sshd -failregex = ^%(__prefix_line)s(?:error: PAM: )?[aA]uthentication (?:failure|error|failed) for .* from ( via \S+)?\s*$ - ^%(__prefix_line)s(?:error: PAM: )?User not known to the underlying authentication module for .* from \s*$ - ^%(__prefix_line)sFailed \S+ for (?Pinvalid user )?(?P(?P\S+)|(?(cond_inv)(?:(?! from ).)*?|[^:]+)) from (?: port \d+)?(?: ssh\d*)?(?(cond_user): |(?:(?:(?! from ).)*)$) - ^%(__prefix_line)sROOT LOGIN REFUSED.* FROM \s*$ - ^%(__prefix_line)s[iI](?:llegal|nvalid) user .*? from (?: port \d+)?\s*$ - ^%(__prefix_line)sUser .+ from not allowed because not listed in AllowUsers\s*$ - ^%(__prefix_line)sUser .+ from not allowed because listed in DenyUsers\s*$ - ^%(__prefix_line)sUser .+ from not allowed because not in any group\s*$ - ^%(__prefix_line)srefused connect from \S+ \(\)\s*$ - ^%(__prefix_line)s(?:error: )?Received disconnect from : 3: .*: Auth fail(?: \[preauth\])?$ - ^%(__prefix_line)sUser .+ from not allowed because a group is listed in DenyGroups\s*$ - ^%(__prefix_line)sUser .+ from not allowed because none of user's groups are listed in AllowGroups\s*$ - ^(?P<__prefix>%(__prefix_line)s)User .+ not allowed because account is locked(?P=__prefix)(?:error: )?Received disconnect from : 11: .+ \[preauth\]$ - ^(?P<__prefix>%(__prefix_line)s)Disconnecting: Too many authentication failures for .+? \[preauth\](?P=__prefix)(?:error: )?Connection closed by \[preauth\]$ - ^(?P<__prefix>%(__prefix_line)s)Connection from port \d+(?: on \S+ port \d+)?(?P=__prefix)Disconnecting: Too many authentication failures for .+? \[preauth\]$ - ^%(__prefix_line)s(error: )?maximum authentication attempts exceeded for .* from (?: port \d*)?(?: ssh\d*)? \[preauth\]$ - ^%(__prefix_line)spam_unix\(sshd:auth\):\s+authentication failure;\s*logname=\S*\s*uid=\d*\s*euid=\d*\s*tty=\S*\s*ruser=\S*\s*rhost=\s.*$ +# optional prefix (logged from several ssh versions) like "error: ", "error: PAM: " or "fatal: " +__pref = (?:(?:error|fatal): (?:PAM: )?)? +# optional suffix (logged from several ssh versions) like " [preauth]" +__suff = (?: \[preauth\])? + +# single line prefix: +__prefix_line_sl = %(__prefix_line)s%(__pref)s +# multi line prefixes (for first and second lines): +__prefix_line_ml1 = (?P<__prefix>%(__prefix_line)s)%(__pref)s +__prefix_line_ml2 = %(__suff)s$^(?P=__prefix)%(__pref)s + +failregex = ^%(__prefix_line_sl)s[aA]uthentication (?:failure|error|failed) for .* from ( via \S+)?\s*%(__suff)s$ + ^%(__prefix_line_sl)sUser not known to the underlying authentication module for .* from \s*%(__suff)s$ + ^%(__prefix_line_sl)sFailed \S+ for (?Pinvalid user )?(?P(?P\S+)|(?(cond_inv)(?:(?! from ).)*?|[^:]+)) from (?: port \d+)?(?: ssh\d*)?(?(cond_user): |(?:(?:(?! from ).)*)$) + ^%(__prefix_line_sl)sROOT LOGIN REFUSED.* FROM \s*%(__suff)s$ + ^%(__prefix_line_sl)s[iI](?:llegal|nvalid) user .*? from (?: port \d+)?\s*$ + ^%(__prefix_line_sl)sUser .+ from not allowed because not listed in AllowUsers\s*%(__suff)s$ + ^%(__prefix_line_sl)sUser .+ from not allowed because listed in DenyUsers\s*%(__suff)s$ + ^%(__prefix_line_sl)sUser .+ from not allowed because not in any group\s*%(__suff)s$ + ^%(__prefix_line_sl)srefused connect from \S+ \(\)\s*%(__suff)s$ + ^%(__prefix_line_sl)sReceived disconnect from : (?:3: .*: Auth fail|14: No supported authentication methods available)%(__suff)s$ + ^%(__prefix_line_sl)sUser .+ from not allowed because a group is listed in DenyGroups\s*%(__suff)s$ + ^%(__prefix_line_sl)sUser .+ from not allowed because none of user's groups are listed in AllowGroups\s*%(__suff)s$ + ^%(__prefix_line_sl)spam_unix\(sshd:auth\):\s+authentication failure;\s*logname=\S*\s*uid=\d*\s*euid=\d*\s*tty=\S*\s*ruser=\S*\s*rhost=\s.*%(__suff)s$ + ^%(__prefix_line_sl)s(error: )?maximum authentication attempts exceeded for .* from (?: port \d*)?(?: ssh\d*)? \[preauth\]$ + ^%(__prefix_line_ml1)sUser .+ not allowed because account is locked%(__prefix_line_ml2)sReceived disconnect from : 11: .+%(__suff)s$ + ^%(__prefix_line_ml1)sDisconnecting: Too many authentication failures for .+?%(__prefix_line_ml2)sConnection closed by %(__suff)s$ + ^%(__prefix_line_ml1)sConnection from port \d+(?: on \S+ port \d+)?%(__prefix_line_ml2)sDisconnecting: Too many authentication failures for .+%(__suff)s$ + ^%(__prefix_line_ml1)sSSH: Server;Ltype: (?:Authname|Version|Kex);Remote: -\d+;[A-Z]\w+:.*%(__prefix_line_ml2)sRead from socket failed: Connection reset by peer%(__suff)s$ ignoreregex = diff --git a/config/filter.d/suhosin.conf b/config/filter.d/suhosin.conf index f125eadc..07eb212d 100644 --- a/config/filter.d/suhosin.conf +++ b/config/filter.d/suhosin.conf @@ -17,7 +17,7 @@ _daemon = (?:lighttpd|suhosin) _lighttpd_prefix = (?:\(mod_fastcgi\.c\.\d+\) FastCGI-stderr:\s) -failregex = ^%(__prefix_line)s%(_lighttpd_prefix)s?ALERT - .* \(attacker '', file '.*'(?:, line \d+)?\)$ +failregex = ^%(__prefix_line)s%(_lighttpd_prefix)s?ALERT - .*? \(attacker '', file '.*'(?:, line \d+)?\)$ ignoreregex = diff --git a/fail2ban/tests/files/logs/sshd b/fail2ban/tests/files/logs/sshd index 0800f86b..64b27084 100644 --- a/fail2ban/tests/files/logs/sshd +++ b/fail2ban/tests/files/logs/sshd @@ -169,3 +169,27 @@ Apr 27 13:02:04 host sshd[29116]: Received disconnect from 1.2.3.4: 11: Normal S # Match sshd auth errors on OpenSUSE systems # failJSON: { "time": "2015-04-16T20:02:50", "match": true , "host": "222.186.21.217", "desc": "Authentication for user failed" } 2015-04-16T18:02:50.321974+00:00 host sshd[2716]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=222.186.21.217 user=root + +# gh-864(1): +# failJSON: { "match": false } +Nov 24 23:46:39 host sshd[32686]: SSH: Server;Ltype: Version;Remote: 127.0.0.1-1780;Protocol: 2.0;Client: libssh2_1.4.3 +# failJSON: { "time": "2004-11-24T23:46:43", "match": true , "host": "127.0.0.1", "desc": "Multiline for connection reset by peer (1)" } +Nov 24 23:46:43 host sshd[32686]: fatal: Read from socket failed: Connection reset by peer [preauth] + +# gh-864(2): +# failJSON: { "match": false } +Nov 24 23:46:40 host sshd[32686]: SSH: Server;Ltype: Kex;Remote: 127.0.0.1-1780;Enc: aes128-ctr;MAC: hmac-sha1;Comp: none [preauth] +# failJSON: { "time": "2004-11-24T23:46:43", "match": true , "host": "127.0.0.1", "desc": "Multiline for connection reset by peer (2)" } +Nov 24 23:46:43 host sshd[32686]: fatal: Read from socket failed: Connection reset by peer [preauth] + +# gh-864(3): +# failJSON: { "match": false } +Nov 24 23:46:41 host sshd[32686]: SSH: Server;Ltype: Authname;Remote: 127.0.0.1-1780;Name: root [preauth] +# failJSON: { "time": "2004-11-24T23:46:43", "match": true , "host": "127.0.0.1", "desc": "Multiline for connection reset by peer (3)" } +Nov 24 23:46:43 host sshd[32686]: fatal: Read from socket failed: Connection reset by peer [preauth] + +# several other cases from gh-864: +# failJSON: { "time": "2004-11-25T01:34:12", "match": true , "host": "127.0.0.1", "desc": "No supported authentication methods" } +Nov 25 01:34:12 srv sshd[123]: Received disconnect from 127.0.0.1: 14: No supported authentication methods available [preauth] +# failJSON: { "time": "2004-11-25T01:35:13", "match": true , "host": "127.0.0.1", "desc": "No supported authentication methods" } +Nov 25 01:35:13 srv sshd[123]: error: Received disconnect from 127.0.0.1: 14: No supported authentication methods available [preauth] diff --git a/fail2ban/tests/samplestestcase.py b/fail2ban/tests/samplestestcase.py index 327410bc..9fb70425 100644 --- a/fail2ban/tests/samplestestcase.py +++ b/fail2ban/tests/samplestestcase.py @@ -31,6 +31,7 @@ import re import sys import time import unittest +from ..server.failregex import Regex from ..server.filter import Filter from ..client.filterreader import FilterReader from .utils import setUpMyTime, tearDownMyTime, CONFIG_DIR @@ -38,6 +39,10 @@ from .utils import setUpMyTime, tearDownMyTime, CONFIG_DIR TEST_CONFIG_DIR = os.path.join(os.path.dirname(__file__), "config") TEST_FILES_DIR = os.path.join(os.path.dirname(__file__), "files") +# regexp to test greedy catch-all should be not-greedy: +RE_HOST = Regex('').getRegex() +RE_WRONG_GREED = re.compile(r'\.[+\*](?!\?).*' + re.escape(RE_HOST) + r'.*(?:\.[+\*].*|[^\$])$') + class FilterSamplesRegex(unittest.TestCase): @@ -60,6 +65,19 @@ class FilterSamplesRegex(unittest.TestCase): >= 10, "Expected more FilterSampleRegexs tests") + def testReWrongGreedyCatchAll(self): + """Tests regexp RE_WRONG_GREED is intact (positive/negative)""" + self.assertTrue( + RE_WRONG_GREED.search('greedy .* test' + RE_HOST + ' test not hard-anchored')) + self.assertTrue( + RE_WRONG_GREED.search('greedy .+ test' + RE_HOST + ' test vary .* anchored$')) + self.assertFalse( + RE_WRONG_GREED.search('greedy .* test' + RE_HOST + ' test no catch-all, hard-anchored$')) + self.assertFalse( + RE_WRONG_GREED.search('non-greedy .*? test' + RE_HOST + ' test not hard-anchored')) + self.assertFalse( + RE_WRONG_GREED.search('non-greedy .+? test' + RE_HOST + ' test vary catch-all .* anchored$')) + def testSampleRegexsFactory(name, basedir): def testFilter(self): @@ -88,6 +106,14 @@ def testSampleRegexsFactory(name, basedir): logFile = fileinput.FileInput( os.path.join(TEST_FILES_DIR, "logs", name)) + # test regexp contains greedy catch-all before , that is + # not hard-anchored at end or has not precise sub expression after : + for fr in self.filter.getFailRegex(): + if RE_WRONG_GREED.search(fr): #pragma: no cover + raise AssertionError("Following regexp of \"%s\" contains greedy catch-all before , " + "that is not hard-anchored at end or has not precise sub expression after :\n%s" % + (name, str(fr).replace(RE_HOST, ''))) + regexsUsed = set() for line in logFile: jsonREMatch = re.match("^# ?failJSON:(.+)$", line) From 628789f9a98a4d7362beb5a969bfa0a9716a2a01 Mon Sep 17 00:00:00 2001 From: sebres Date: Fri, 11 Nov 2016 13:23:20 +0100 Subject: [PATCH 13/33] sshd: conditional parameter "mode" for sshd jail (normal, ddos, aggressive) filter sshd-ddos and new filter sshd-aggressive are both derivation of sshd-filter --- config/filter.d/sshd-aggressive.conf | 11 ++ config/filter.d/sshd-ddos.conf | 16 +-- config/filter.d/sshd.conf | 52 ++++++---- config/jail.conf | 2 + fail2ban/tests/clientreadertestcase.py | 2 +- fail2ban/tests/files/logs/sshd | 24 ----- fail2ban/tests/files/logs/sshd-aggressive | 3 + fail2ban/tests/files/logs/sshd-ddos | 24 +++++ fail2ban/tests/samplestestcase.py | 117 ++++++++++++---------- 9 files changed, 137 insertions(+), 114 deletions(-) create mode 100644 config/filter.d/sshd-aggressive.conf create mode 100644 fail2ban/tests/files/logs/sshd-aggressive diff --git a/config/filter.d/sshd-aggressive.conf b/config/filter.d/sshd-aggressive.conf new file mode 100644 index 00000000..98175cbe --- /dev/null +++ b/config/filter.d/sshd-aggressive.conf @@ -0,0 +1,11 @@ +# Fail2Ban aggressive ssh filter for at attempted exploit +# +# Includes failregex of both sshd and sshd-ddos filters +# +[INCLUDES] + +before = sshd.conf + +[Definition] + +mode = %(aggressive)s diff --git a/config/filter.d/sshd-ddos.conf b/config/filter.d/sshd-ddos.conf index 4f71c7f3..69b42069 100644 --- a/config/filter.d/sshd-ddos.conf +++ b/config/filter.d/sshd-ddos.conf @@ -10,20 +10,8 @@ [INCLUDES] -# Read common prefixes. If any customizations available -- read them from -# common.local -before = common.conf +before = sshd.conf [Definition] -_daemon = sshd - -failregex = ^%(__prefix_line)sDid not receive identification string from \s*$ - -ignoreregex = - -[Init] - -journalmatch = _SYSTEMD_UNIT=sshd.service + _COMM=sshd - -# Author: Yaroslav Halchenko +mode = %(ddos)s diff --git a/config/filter.d/sshd.conf b/config/filter.d/sshd.conf index c04c0875..394f6631 100644 --- a/config/filter.d/sshd.conf +++ b/config/filter.d/sshd.conf @@ -14,14 +14,14 @@ # common.local before = common.conf -[Definition] +[DEFAULT] _daemon = sshd # optional prefix (logged from several ssh versions) like "error: ", "error: PAM: " or "fatal: " __pref = (?:(?:error|fatal): (?:PAM: )?)? # optional suffix (logged from several ssh versions) like " [preauth]" -__suff = (?: \[preauth\])? +__suff = (?: \[preauth\])?\s* # single line prefix: __prefix_line_sl = %(__prefix_line)s%(__pref)s @@ -29,24 +29,36 @@ __prefix_line_sl = %(__prefix_line)s%(__pref)s __prefix_line_ml1 = (?P<__prefix>%(__prefix_line)s)%(__pref)s __prefix_line_ml2 = %(__suff)s$^(?P=__prefix)%(__pref)s -failregex = ^%(__prefix_line_sl)s[aA]uthentication (?:failure|error|failed) for .* from ( via \S+)?\s*%(__suff)s$ - ^%(__prefix_line_sl)sUser not known to the underlying authentication module for .* from \s*%(__suff)s$ - ^%(__prefix_line_sl)sFailed \S+ for (?Pinvalid user )?(?P(?P\S+)|(?(cond_inv)(?:(?! from ).)*?|[^:]+)) from (?: port \d+)?(?: ssh\d*)?(?(cond_user): |(?:(?:(?! from ).)*)$) - ^%(__prefix_line_sl)sROOT LOGIN REFUSED.* FROM \s*%(__suff)s$ - ^%(__prefix_line_sl)s[iI](?:llegal|nvalid) user .*? from (?: port \d+)?\s*$ - ^%(__prefix_line_sl)sUser .+ from not allowed because not listed in AllowUsers\s*%(__suff)s$ - ^%(__prefix_line_sl)sUser .+ from not allowed because listed in DenyUsers\s*%(__suff)s$ - ^%(__prefix_line_sl)sUser .+ from not allowed because not in any group\s*%(__suff)s$ - ^%(__prefix_line_sl)srefused connect from \S+ \(\)\s*%(__suff)s$ - ^%(__prefix_line_sl)sReceived disconnect from : (?:3: .*: Auth fail|14: No supported authentication methods available)%(__suff)s$ - ^%(__prefix_line_sl)sUser .+ from not allowed because a group is listed in DenyGroups\s*%(__suff)s$ - ^%(__prefix_line_sl)sUser .+ from not allowed because none of user's groups are listed in AllowGroups\s*%(__suff)s$ - ^%(__prefix_line_sl)spam_unix\(sshd:auth\):\s+authentication failure;\s*logname=\S*\s*uid=\d*\s*euid=\d*\s*tty=\S*\s*ruser=\S*\s*rhost=\s.*%(__suff)s$ - ^%(__prefix_line_sl)s(error: )?maximum authentication attempts exceeded for .* from (?: port \d*)?(?: ssh\d*)? \[preauth\]$ - ^%(__prefix_line_ml1)sUser .+ not allowed because account is locked%(__prefix_line_ml2)sReceived disconnect from : 11: .+%(__suff)s$ - ^%(__prefix_line_ml1)sDisconnecting: Too many authentication failures for .+?%(__prefix_line_ml2)sConnection closed by %(__suff)s$ - ^%(__prefix_line_ml1)sConnection from port \d+(?: on \S+ port \d+)?%(__prefix_line_ml2)sDisconnecting: Too many authentication failures for .+%(__suff)s$ - ^%(__prefix_line_ml1)sSSH: Server;Ltype: (?:Authname|Version|Kex);Remote: -\d+;[A-Z]\w+:.*%(__prefix_line_ml2)sRead from socket failed: Connection reset by peer%(__suff)s$ +mode = %(normal)s + +normal = ^%(__prefix_line_sl)s[aA]uthentication (?:failure|error|failed) for .* from ( via \S+)?\s*%(__suff)s$ + ^%(__prefix_line_sl)sUser not known to the underlying authentication module for .* from \s*%(__suff)s$ + ^%(__prefix_line_sl)sFailed \S+ for (?Pinvalid user )?(?P(?P\S+)|(?(cond_inv)(?:(?! from ).)*?|[^:]+)) from (?: port \d+)?(?: ssh\d*)?(?(cond_user): |(?:(?:(?! from ).)*)$) + ^%(__prefix_line_sl)sROOT LOGIN REFUSED.* FROM \s*%(__suff)s$ + ^%(__prefix_line_sl)s[iI](?:llegal|nvalid) user .*? from (?: port \d+)?\s*$ + ^%(__prefix_line_sl)sUser .+ from not allowed because not listed in AllowUsers\s*%(__suff)s$ + ^%(__prefix_line_sl)sUser .+ from not allowed because listed in DenyUsers\s*%(__suff)s$ + ^%(__prefix_line_sl)sUser .+ from not allowed because not in any group\s*%(__suff)s$ + ^%(__prefix_line_sl)srefused connect from \S+ \(\)\s*%(__suff)s$ + ^%(__prefix_line_sl)sReceived disconnect from : 3: .*: Auth fail%(__suff)s$ + ^%(__prefix_line_sl)sUser .+ from not allowed because a group is listed in DenyGroups\s*%(__suff)s$ + ^%(__prefix_line_sl)sUser .+ from not allowed because none of user's groups are listed in AllowGroups\s*%(__suff)s$ + ^%(__prefix_line_sl)spam_unix\(sshd:auth\):\s+authentication failure;\s*logname=\S*\s*uid=\d*\s*euid=\d*\s*tty=\S*\s*ruser=\S*\s*rhost=\s.*%(__suff)s$ + ^%(__prefix_line_sl)s(error: )?maximum authentication attempts exceeded for .* from (?: port \d*)?(?: ssh\d*)? \[preauth\]$ + ^%(__prefix_line_ml1)sUser .+ not allowed because account is locked%(__prefix_line_ml2)sReceived disconnect from : 11: .+%(__suff)s$ + ^%(__prefix_line_ml1)sDisconnecting: Too many authentication failures for .+?%(__prefix_line_ml2)sConnection closed by %(__suff)s$ + ^%(__prefix_line_ml1)sConnection from port \d+(?: on \S+ port \d+)?%(__prefix_line_ml2)sDisconnecting: Too many authentication failures for .+%(__suff)s$ + +ddos = ^%(__prefix_line_sl)sDid not receive identification string from %(__suff)s$ + ^%(__prefix_line_sl)sReceived disconnect from : 14: No supported authentication methods available%(__suff)s$ + ^%(__prefix_line_ml1)sSSH: Server;Ltype: (?:Authname|Version|Kex);Remote: -\d+;[A-Z]\w+:.*%(__prefix_line_ml2)sRead from socket failed: Connection reset by peer%(__suff)s$ + +aggressive = %(normal)s + %(ddos)s + +[Definition] + +failregex = %(mode)s ignoreregex = diff --git a/config/jail.conf b/config/jail.conf index 2d8567d6..9296b6af 100644 --- a/config/jail.conf +++ b/config/jail.conf @@ -223,6 +223,8 @@ action = %(action_)s [sshd] +# To use more aggressive sshd filter (inclusive sshd-ddos failregex): +#filter = sshd-aggressive port = ssh logpath = %(sshd_log)s backend = %(sshd_backend)s diff --git a/fail2ban/tests/clientreadertestcase.py b/fail2ban/tests/clientreadertestcase.py index 420d4b29..3f0f8481 100644 --- a/fail2ban/tests/clientreadertestcase.py +++ b/fail2ban/tests/clientreadertestcase.py @@ -597,7 +597,7 @@ class JailsReaderTest(LogCaptureTestCase): # grab all filter names filters = set(os.path.splitext(os.path.split(a)[1])[0] for a in glob.glob(os.path.join('config', 'filter.d', '*.conf')) - if not a.endswith('common.conf')) + if not (a.endswith('common.conf') or a.endswith('-aggressive.conf'))) # get filters of all jails (filter names without options inside filter[...]) filters_jail = set( JailReader.extractOptions(jail.options['filter'])[0] for jail in jails.jails diff --git a/fail2ban/tests/files/logs/sshd b/fail2ban/tests/files/logs/sshd index 64b27084..0800f86b 100644 --- a/fail2ban/tests/files/logs/sshd +++ b/fail2ban/tests/files/logs/sshd @@ -169,27 +169,3 @@ Apr 27 13:02:04 host sshd[29116]: Received disconnect from 1.2.3.4: 11: Normal S # Match sshd auth errors on OpenSUSE systems # failJSON: { "time": "2015-04-16T20:02:50", "match": true , "host": "222.186.21.217", "desc": "Authentication for user failed" } 2015-04-16T18:02:50.321974+00:00 host sshd[2716]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=222.186.21.217 user=root - -# gh-864(1): -# failJSON: { "match": false } -Nov 24 23:46:39 host sshd[32686]: SSH: Server;Ltype: Version;Remote: 127.0.0.1-1780;Protocol: 2.0;Client: libssh2_1.4.3 -# failJSON: { "time": "2004-11-24T23:46:43", "match": true , "host": "127.0.0.1", "desc": "Multiline for connection reset by peer (1)" } -Nov 24 23:46:43 host sshd[32686]: fatal: Read from socket failed: Connection reset by peer [preauth] - -# gh-864(2): -# failJSON: { "match": false } -Nov 24 23:46:40 host sshd[32686]: SSH: Server;Ltype: Kex;Remote: 127.0.0.1-1780;Enc: aes128-ctr;MAC: hmac-sha1;Comp: none [preauth] -# failJSON: { "time": "2004-11-24T23:46:43", "match": true , "host": "127.0.0.1", "desc": "Multiline for connection reset by peer (2)" } -Nov 24 23:46:43 host sshd[32686]: fatal: Read from socket failed: Connection reset by peer [preauth] - -# gh-864(3): -# failJSON: { "match": false } -Nov 24 23:46:41 host sshd[32686]: SSH: Server;Ltype: Authname;Remote: 127.0.0.1-1780;Name: root [preauth] -# failJSON: { "time": "2004-11-24T23:46:43", "match": true , "host": "127.0.0.1", "desc": "Multiline for connection reset by peer (3)" } -Nov 24 23:46:43 host sshd[32686]: fatal: Read from socket failed: Connection reset by peer [preauth] - -# several other cases from gh-864: -# failJSON: { "time": "2004-11-25T01:34:12", "match": true , "host": "127.0.0.1", "desc": "No supported authentication methods" } -Nov 25 01:34:12 srv sshd[123]: Received disconnect from 127.0.0.1: 14: No supported authentication methods available [preauth] -# failJSON: { "time": "2004-11-25T01:35:13", "match": true , "host": "127.0.0.1", "desc": "No supported authentication methods" } -Nov 25 01:35:13 srv sshd[123]: error: Received disconnect from 127.0.0.1: 14: No supported authentication methods available [preauth] diff --git a/fail2ban/tests/files/logs/sshd-aggressive b/fail2ban/tests/files/logs/sshd-aggressive new file mode 100644 index 00000000..5b4d3a12 --- /dev/null +++ b/fail2ban/tests/files/logs/sshd-aggressive @@ -0,0 +1,3 @@ +# sshd-aggressive includes sshd and sshd-ddos failregex's: +# addFILE: "sshd" +# addFILE: "sshd-ddos" \ No newline at end of file diff --git a/fail2ban/tests/files/logs/sshd-ddos b/fail2ban/tests/files/logs/sshd-ddos index 452abbde..3f29b778 100644 --- a/fail2ban/tests/files/logs/sshd-ddos +++ b/fail2ban/tests/files/logs/sshd-ddos @@ -1,3 +1,27 @@ # http://forums.powervps.com/showthread.php?t=1667 # failJSON: { "time": "2005-06-07T01:10:56", "match": true , "host": "69.61.56.114" } Jun 7 01:10:56 host sshd[5937]: Did not receive identification string from 69.61.56.114 + +# gh-864(1): +# failJSON: { "match": false } +Nov 24 23:46:39 host sshd[32686]: SSH: Server;Ltype: Version;Remote: 127.0.0.1-1780;Protocol: 2.0;Client: libssh2_1.4.3 +# failJSON: { "time": "2004-11-24T23:46:43", "match": true , "host": "127.0.0.1", "desc": "Multiline for connection reset by peer (1)" } +Nov 24 23:46:43 host sshd[32686]: fatal: Read from socket failed: Connection reset by peer [preauth] + +# gh-864(2): +# failJSON: { "match": false } +Nov 24 23:46:40 host sshd[32686]: SSH: Server;Ltype: Kex;Remote: 127.0.0.1-1780;Enc: aes128-ctr;MAC: hmac-sha1;Comp: none [preauth] +# failJSON: { "time": "2004-11-24T23:46:43", "match": true , "host": "127.0.0.1", "desc": "Multiline for connection reset by peer (2)" } +Nov 24 23:46:43 host sshd[32686]: fatal: Read from socket failed: Connection reset by peer [preauth] + +# gh-864(3): +# failJSON: { "match": false } +Nov 24 23:46:41 host sshd[32686]: SSH: Server;Ltype: Authname;Remote: 127.0.0.1-1780;Name: root [preauth] +# failJSON: { "time": "2004-11-24T23:46:43", "match": true , "host": "127.0.0.1", "desc": "Multiline for connection reset by peer (3)" } +Nov 24 23:46:43 host sshd[32686]: fatal: Read from socket failed: Connection reset by peer [preauth] + +# several other cases from gh-864: +# failJSON: { "time": "2004-11-25T01:34:12", "match": true , "host": "127.0.0.1", "desc": "No supported authentication methods" } +Nov 25 01:34:12 srv sshd[123]: Received disconnect from 127.0.0.1: 14: No supported authentication methods available [preauth] +# failJSON: { "time": "2004-11-25T01:35:13", "match": true , "host": "127.0.0.1", "desc": "No supported authentication methods" } +Nov 25 01:35:13 srv sshd[123]: error: Received disconnect from 127.0.0.1: 14: No supported authentication methods available [preauth] diff --git a/fail2ban/tests/samplestestcase.py b/fail2ban/tests/samplestestcase.py index 9fb70425..0f368314 100644 --- a/fail2ban/tests/samplestestcase.py +++ b/fail2ban/tests/samplestestcase.py @@ -103,68 +103,75 @@ def testSampleRegexsFactory(name, basedir): os.path.isfile(os.path.join(TEST_FILES_DIR, "logs", name)), "No sample log file available for '%s' filter" % name) - logFile = fileinput.FileInput( - os.path.join(TEST_FILES_DIR, "logs", name)) - - # test regexp contains greedy catch-all before , that is - # not hard-anchored at end or has not precise sub expression after : - for fr in self.filter.getFailRegex(): - if RE_WRONG_GREED.search(fr): #pragma: no cover - raise AssertionError("Following regexp of \"%s\" contains greedy catch-all before , " - "that is not hard-anchored at end or has not precise sub expression after :\n%s" % - (name, str(fr).replace(RE_HOST, ''))) - regexsUsed = set() - for line in logFile: - jsonREMatch = re.match("^# ?failJSON:(.+)$", line) - if jsonREMatch: - try: - faildata = json.loads(jsonREMatch.group(1)) - except ValueError as e: - raise ValueError("%s: %s:%i" % - (e, logFile.filename(), logFile.filelineno())) - line = next(logFile) - elif line.startswith("#") or not line.strip(): - continue - else: - faildata = {} + filenames = [name] + i = 0 + while i < len(filenames): + filename = filenames[i]; i += 1; + logFile = fileinput.FileInput(os.path.join(TEST_FILES_DIR, "logs", + filename)) - ret = self.filter.processLine( - line, returnRawHost=True, checkAllRegex=True)[1] - if not ret: - # Check line is flagged as none match - self.assertFalse(faildata.get('match', True), - "Line not matched when should have: %s:%i %r" % - (logFile.filename(), logFile.filelineno(), line)) - elif ret: - # Check line is flagged to match - self.assertTrue(faildata.get('match', False), - "Line matched when shouldn't have: %s:%i %r" % - (logFile.filename(), logFile.filelineno(), line)) - self.assertEqual(len(ret), 1, "Multiple regexs matched %r - %s:%i" % - (map(lambda x: x[0], ret),logFile.filename(), logFile.filelineno())) + # test regexp contains greedy catch-all before , that is + # not hard-anchored at end or has not precise sub expression after : + for fr in self.filter.getFailRegex(): + if RE_WRONG_GREED.search(fr): #pragma: no cover + raise AssertionError("Following regexp of \"%s\" contains greedy catch-all before , " + "that is not hard-anchored at end or has not precise sub expression after :\n%s" % + (name, str(fr).replace(RE_HOST, ''))) - # Verify timestamp and host as expected - failregex, host, fail2banTime, lines = ret[0] - self.assertEqual(host, faildata.get("host", None)) + for line in logFile: + jsonREMatch = re.match("^# ?(failJSON|addFILE):(.+)$", line) + if jsonREMatch: + try: + faildata = json.loads(jsonREMatch.group(2)) + if jsonREMatch.group(1) == 'addFILE': + filenames.append(faildata) + continue + except ValueError as e: + raise ValueError("%s: %s:%i" % + (e, logFile.filename(), logFile.filelineno())) + line = next(logFile) + elif line.startswith("#") or not line.strip(): + continue + else: + faildata = {} - t = faildata.get("time", None) - try: - jsonTimeLocal = datetime.datetime.strptime(t, "%Y-%m-%dT%H:%M:%S") - except ValueError: - jsonTimeLocal = datetime.datetime.strptime(t, "%Y-%m-%dT%H:%M:%S.%f") + ret = self.filter.processLine( + line, returnRawHost=True, checkAllRegex=True)[1] + if not ret: + # Check line is flagged as none match + self.assertFalse(faildata.get('match', True), + "Line not matched when should have: %s:%i %r" % + (logFile.filename(), logFile.filelineno(), line)) + elif ret: + # Check line is flagged to match + self.assertTrue(faildata.get('match', False), + "Line matched when shouldn't have: %s:%i %r" % + (logFile.filename(), logFile.filelineno(), line)) + self.assertEqual(len(ret), 1, "Multiple regexs matched %r - %s:%i" % + (map(lambda x: x[0], ret),logFile.filename(), logFile.filelineno())) - jsonTime = time.mktime(jsonTimeLocal.timetuple()) - - jsonTime += jsonTimeLocal.microsecond / 1000000 + # Verify timestamp and host as expected + failregex, host, fail2banTime, lines = ret[0] + self.assertEqual(host, faildata.get("host", None)) - self.assertEqual(fail2banTime, jsonTime, - "UTC Time mismatch fail2ban %s (%s) != failJson %s (%s) (diff %.3f seconds) on: %s:%i %r:" % - (fail2banTime, time.strftime("%Y-%m-%dT%H:%M:%S", time.gmtime(fail2banTime)), - jsonTime, time.strftime("%Y-%m-%dT%H:%M:%S", time.gmtime(jsonTime)), - fail2banTime - jsonTime, logFile.filename(), logFile.filelineno(), line ) ) + t = faildata.get("time", None) + try: + jsonTimeLocal = datetime.datetime.strptime(t, "%Y-%m-%dT%H:%M:%S") + except ValueError: + jsonTimeLocal = datetime.datetime.strptime(t, "%Y-%m-%dT%H:%M:%S.%f") - regexsUsed.add(failregex) + jsonTime = time.mktime(jsonTimeLocal.timetuple()) + + jsonTime += jsonTimeLocal.microsecond / 1000000 + + self.assertEqual(fail2banTime, jsonTime, + "UTC Time mismatch fail2ban %s (%s) != failJson %s (%s) (diff %.3f seconds) on: %s:%i %r:" % + (fail2banTime, time.strftime("%Y-%m-%dT%H:%M:%S", time.gmtime(fail2banTime)), + jsonTime, time.strftime("%Y-%m-%dT%H:%M:%S", time.gmtime(jsonTime)), + fail2banTime - jsonTime, logFile.filename(), logFile.filelineno(), line ) ) + + regexsUsed.add(failregex) for failRegexIndex, failRegex in enumerate(self.filter.getFailRegex()): self.assertTrue( From 3276bd6d54ce7d1e76f789eb982b53dcb0bc270b Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 14 Nov 2016 12:59:37 +0100 Subject: [PATCH 14/33] sshd: additionally aggressive filter rules - no matching cipher resp. no matching key exchange method (gh-1545, gh-1117) --- config/filter.d/sshd.conf | 15 +++++++++------ fail2ban/tests/files/logs/sshd-ddos | 12 ++++++++++++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/config/filter.d/sshd.conf b/config/filter.d/sshd.conf index 394f6631..7d2ab421 100644 --- a/config/filter.d/sshd.conf +++ b/config/filter.d/sshd.conf @@ -22,6 +22,7 @@ _daemon = sshd __pref = (?:(?:error|fatal): (?:PAM: )?)? # optional suffix (logged from several ssh versions) like " [preauth]" __suff = (?: \[preauth\])?\s* +__on_port_opt = (?: port \d+)?(?: on \S+(?: port \d+)?)? # single line prefix: __prefix_line_sl = %(__prefix_line)s%(__pref)s @@ -33,24 +34,26 @@ mode = %(normal)s normal = ^%(__prefix_line_sl)s[aA]uthentication (?:failure|error|failed) for .* from ( via \S+)?\s*%(__suff)s$ ^%(__prefix_line_sl)sUser not known to the underlying authentication module for .* from \s*%(__suff)s$ - ^%(__prefix_line_sl)sFailed \S+ for (?Pinvalid user )?(?P(?P\S+)|(?(cond_inv)(?:(?! from ).)*?|[^:]+)) from (?: port \d+)?(?: ssh\d*)?(?(cond_user): |(?:(?:(?! from ).)*)$) + ^%(__prefix_line_sl)sFailed \S+ for (?Pinvalid user )?(?P(?P\S+)|(?(cond_inv)(?:(?! from ).)*?|[^:]+)) from %(__on_port_opt)s(?: ssh\d*)?(?(cond_user): |(?:(?:(?! from ).)*)$) ^%(__prefix_line_sl)sROOT LOGIN REFUSED.* FROM \s*%(__suff)s$ - ^%(__prefix_line_sl)s[iI](?:llegal|nvalid) user .*? from (?: port \d+)?\s*$ + ^%(__prefix_line_sl)s[iI](?:llegal|nvalid) user .*? from %(__on_port_opt)s\s*$ ^%(__prefix_line_sl)sUser .+ from not allowed because not listed in AllowUsers\s*%(__suff)s$ ^%(__prefix_line_sl)sUser .+ from not allowed because listed in DenyUsers\s*%(__suff)s$ ^%(__prefix_line_sl)sUser .+ from not allowed because not in any group\s*%(__suff)s$ ^%(__prefix_line_sl)srefused connect from \S+ \(\)\s*%(__suff)s$ - ^%(__prefix_line_sl)sReceived disconnect from : 3: .*: Auth fail%(__suff)s$ + ^%(__prefix_line_sl)sReceived disconnect from %(__on_port_opt)s: 3: .*: Auth fail%(__suff)s$ ^%(__prefix_line_sl)sUser .+ from not allowed because a group is listed in DenyGroups\s*%(__suff)s$ ^%(__prefix_line_sl)sUser .+ from not allowed because none of user's groups are listed in AllowGroups\s*%(__suff)s$ ^%(__prefix_line_sl)spam_unix\(sshd:auth\):\s+authentication failure;\s*logname=\S*\s*uid=\d*\s*euid=\d*\s*tty=\S*\s*ruser=\S*\s*rhost=\s.*%(__suff)s$ - ^%(__prefix_line_sl)s(error: )?maximum authentication attempts exceeded for .* from (?: port \d*)?(?: ssh\d*)? \[preauth\]$ + ^%(__prefix_line_sl)s(error: )?maximum authentication attempts exceeded for .* from %(__on_port_opt)s(?: ssh\d*)? \[preauth\]$ ^%(__prefix_line_ml1)sUser .+ not allowed because account is locked%(__prefix_line_ml2)sReceived disconnect from : 11: .+%(__suff)s$ ^%(__prefix_line_ml1)sDisconnecting: Too many authentication failures for .+?%(__prefix_line_ml2)sConnection closed by %(__suff)s$ - ^%(__prefix_line_ml1)sConnection from port \d+(?: on \S+ port \d+)?%(__prefix_line_ml2)sDisconnecting: Too many authentication failures for .+%(__suff)s$ + ^%(__prefix_line_ml1)sConnection from %(__on_port_opt)s%(__prefix_line_ml2)sDisconnecting: Too many authentication failures for .+%(__suff)s$ ddos = ^%(__prefix_line_sl)sDid not receive identification string from %(__suff)s$ - ^%(__prefix_line_sl)sReceived disconnect from : 14: No supported authentication methods available%(__suff)s$ + ^%(__prefix_line_sl)sReceived disconnect from %(__on_port_opt)s: 14: No supported authentication methods available%(__suff)s$ + ^%(__prefix_line_sl)sUnable to negotiate with %(__on_port_opt)s: no matching (?:cipher|key exchange method) found. + ^%(__prefix_line_ml1)sConnection from %(__on_port_opt)s%(__prefix_line_ml2)sUnable to negotiate a (?:cipher|key exchange method)%(__suff)s$ ^%(__prefix_line_ml1)sSSH: Server;Ltype: (?:Authname|Version|Kex);Remote: -\d+;[A-Z]\w+:.*%(__prefix_line_ml2)sRead from socket failed: Connection reset by peer%(__suff)s$ aggressive = %(normal)s diff --git a/fail2ban/tests/files/logs/sshd-ddos b/fail2ban/tests/files/logs/sshd-ddos index 3f29b778..1caf5f50 100644 --- a/fail2ban/tests/files/logs/sshd-ddos +++ b/fail2ban/tests/files/logs/sshd-ddos @@ -25,3 +25,15 @@ Nov 24 23:46:43 host sshd[32686]: fatal: Read from socket failed: Connection res Nov 25 01:34:12 srv sshd[123]: Received disconnect from 127.0.0.1: 14: No supported authentication methods available [preauth] # failJSON: { "time": "2004-11-25T01:35:13", "match": true , "host": "127.0.0.1", "desc": "No supported authentication methods" } Nov 25 01:35:13 srv sshd[123]: error: Received disconnect from 127.0.0.1: 14: No supported authentication methods available [preauth] + +# gh-1545: +# failJSON: { "time": "2004-11-26T13:03:29", "match": true , "host": "192.0.2.1", "desc": "No matching cipher" } +Nov 26 13:03:29 srv sshd[45]: Unable to negotiate with 192.0.2.1 port 55419: no matching cipher found. Their offer: aes256-cbc,rijndael-cbc@lysator.liu.se,aes192-cbc,aes128-cbc,arcfour128,arcfour,3des-cbc,none [preauth] + +# gh-1117: +# failJSON: { "time": "2004-11-26T13:03:30", "match": true , "host": "192.0.2.2", "desc": "No matching key exchange method" } +Nov 26 13:03:30 srv sshd[45]: fatal: Unable to negotiate with 192.0.2.2 port 55419: no matching key exchange method found. Their offer: diffie-hellman-group1-sha1 +# failJSON: { "match": false } +Nov 26 15:03:30 host sshd[22440]: Connection from 192.0.2.3 port 39678 on 192.168.1.9 port 22 +# failJSON: { "time": "2004-11-26T15:03:31", "match": true , "host": "192.0.2.3", "desc": "Multiline - no matching key exchange method" } +Nov 26 15:03:31 host sshd[22440]: fatal: Unable to negotiate a key exchange method [preauth] \ No newline at end of file From c8f473110c6ad76508747ac16328c177316c7fe8 Mon Sep 17 00:00:00 2001 From: sebres Date: Sat, 21 Jan 2017 15:59:27 +0100 Subject: [PATCH 15/33] change log update after rebase --- ChangeLog | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6f9d8069..e8a8491e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -22,6 +22,16 @@ releases. (0.10th resp. IPv6 relevant only, amend for gh-1479) * config/pathes-freebsd.conf - Fixed filenames for apache and nginx log files (gh-1667) +* filter.d/sshd.conf + - new aggressive rules (gh-864): + - Connection reset by peer (multi-line rule during authorization process) + - No supported authentication methods available + - single line and multi-line expression optimized, added optional prefixes + and suffix (logged from several ssh versions), according to gh-1206; +* filter.d/suhosin.conf + - greedy catch-all before `` fixed (potential vulnerability) +* Filter tests extended with check of all config-regexp, that contains greedy catch-all + before ``, that is hard-anchored at end or precise sub expression after `` ### New Features * New Actions: @@ -71,15 +81,6 @@ ver. 0.9.6 (2016/12/10) - stretch-is-coming - optimized failregex to match all of "Failed any-method for ... from " (gh-1479) - eliminated possible complex injections (on user-name resp. auth-info, see gh-1479) - optional port part after host (see gh-1533, gh-1581) - - new aggressive rules (gh-864): - - Connection reset by peer (multi-line rule during authorization process) - - No supported authentication methods available - - single line and multi-line expression optimized, added optional prefixes - and suffix (logged from several ssh versions), according to gh-1206; -* filter.d/suhosin.conf - - greedy catch-all before `` fixed (potential vulnerability) -* Filter tests extended with check of all config-regexp, that contains greedy catch-all - before ``, that is hard-anchored at end or precise sub expression after `` ### New Features * New Actions: From 8aa9516d507202ecfb4add52792f656e7dceb263 Mon Sep 17 00:00:00 2001 From: sebres Date: Sat, 21 Jan 2017 16:18:03 +0100 Subject: [PATCH 16/33] sshd.conf: fixed expression "received disconnect ... auth fail" - optional space after port part (gh-1652) --- ChangeLog | 3 +++ config/filter.d/sshd.conf | 2 +- fail2ban/tests/files/logs/sshd | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index e8a8491e..2a7e6638 100644 --- a/ChangeLog +++ b/ChangeLog @@ -28,6 +28,9 @@ releases. - No supported authentication methods available - single line and multi-line expression optimized, added optional prefixes and suffix (logged from several ssh versions), according to gh-1206; + - fixed expression received disconnect auth fail (optional space after port + part, gh-1652) + and suffix (logged from several ssh versions), according to gh-1206; * filter.d/suhosin.conf - greedy catch-all before `` fixed (potential vulnerability) * Filter tests extended with check of all config-regexp, that contains greedy catch-all diff --git a/config/filter.d/sshd.conf b/config/filter.d/sshd.conf index 7d2ab421..74b8925f 100644 --- a/config/filter.d/sshd.conf +++ b/config/filter.d/sshd.conf @@ -41,7 +41,7 @@ normal = ^%(__prefix_line_sl)s[aA]uthentication (?:failure|error|failed) for .* ^%(__prefix_line_sl)sUser .+ from not allowed because listed in DenyUsers\s*%(__suff)s$ ^%(__prefix_line_sl)sUser .+ from not allowed because not in any group\s*%(__suff)s$ ^%(__prefix_line_sl)srefused connect from \S+ \(\)\s*%(__suff)s$ - ^%(__prefix_line_sl)sReceived disconnect from %(__on_port_opt)s: 3: .*: Auth fail%(__suff)s$ + ^%(__prefix_line_sl)sReceived disconnect from %(__on_port_opt)s:\s*3: .*: Auth fail%(__suff)s$ ^%(__prefix_line_sl)sUser .+ from not allowed because a group is listed in DenyGroups\s*%(__suff)s$ ^%(__prefix_line_sl)sUser .+ from not allowed because none of user's groups are listed in AllowGroups\s*%(__suff)s$ ^%(__prefix_line_sl)spam_unix\(sshd:auth\):\s+authentication failure;\s*logname=\S*\s*uid=\d*\s*euid=\d*\s*tty=\S*\s*ruser=\S*\s*rhost=\s.*%(__suff)s$ diff --git a/fail2ban/tests/files/logs/sshd b/fail2ban/tests/files/logs/sshd index 0800f86b..5fbdbe81 100644 --- a/fail2ban/tests/files/logs/sshd +++ b/fail2ban/tests/files/logs/sshd @@ -139,6 +139,8 @@ Nov 23 21:50:37 sshd[7148]: Connection closed by 61.0.0.1 [preauth] # failJSON: { "time": "2005-07-13T18:44:28", "match": true , "host": "89.24.13.192", "desc": "from gh-289" } Jul 13 18:44:28 mdop sshd[4931]: Received disconnect from 89.24.13.192: 3: com.jcraft.jsch.JSchException: Auth fail +# failJSON: { "time": "2005-01-02T01:18:41", "match": true , "host": "10.0.0.1", "desc": "space after port is optional (gh-1652)" } +Jan 2 01:18:41 host sshd[11808]: error: Received disconnect from 10.0.0.1 port 7736:3: com.jcraft.jsch.JSchException: Auth fail [preauth] # failJSON: { "time": "2004-10-01T17:27:44", "match": true , "host": "94.249.236.6", "desc": "newer format per commit 36919d9f" } Oct 1 17:27:44 localhost sshd[24077]: error: Received disconnect from 94.249.236.6: 3: com.jcraft.jsch.JSchException: Auth fail [preauth] From 54a8c681cedbe56f4448001ee6dc371772dca9d6 Mon Sep 17 00:00:00 2001 From: sebres Date: Sat, 21 Jan 2017 16:26:07 +0100 Subject: [PATCH 17/33] suhosin.conf: removed greedy match --- config/filter.d/suhosin.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/filter.d/suhosin.conf b/config/filter.d/suhosin.conf index 07eb212d..46fbe381 100644 --- a/config/filter.d/suhosin.conf +++ b/config/filter.d/suhosin.conf @@ -17,7 +17,7 @@ _daemon = (?:lighttpd|suhosin) _lighttpd_prefix = (?:\(mod_fastcgi\.c\.\d+\) FastCGI-stderr:\s) -failregex = ^%(__prefix_line)s%(_lighttpd_prefix)s?ALERT - .*? \(attacker '', file '.*'(?:, line \d+)?\)$ +failregex = ^%(__prefix_line)s%(_lighttpd_prefix)s?ALERT - .*? \(attacker '', file '[^']*'(?:, line \d+)?\)$ ignoreregex = From 9d06f0ee4067bc6ffec027b0156ede938bca0edc Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 23 Jan 2017 08:56:47 +0100 Subject: [PATCH 18/33] sshd-amend: optional space after port part --- config/filter.d/sshd.conf | 2 +- fail2ban/tests/files/logs/sshd-ddos | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/config/filter.d/sshd.conf b/config/filter.d/sshd.conf index 74b8925f..45566b36 100644 --- a/config/filter.d/sshd.conf +++ b/config/filter.d/sshd.conf @@ -51,7 +51,7 @@ normal = ^%(__prefix_line_sl)s[aA]uthentication (?:failure|error|failed) for .* ^%(__prefix_line_ml1)sConnection from %(__on_port_opt)s%(__prefix_line_ml2)sDisconnecting: Too many authentication failures for .+%(__suff)s$ ddos = ^%(__prefix_line_sl)sDid not receive identification string from %(__suff)s$ - ^%(__prefix_line_sl)sReceived disconnect from %(__on_port_opt)s: 14: No supported authentication methods available%(__suff)s$ + ^%(__prefix_line_sl)sReceived disconnect from %(__on_port_opt)s:\s*14: No supported authentication methods available%(__suff)s$ ^%(__prefix_line_sl)sUnable to negotiate with %(__on_port_opt)s: no matching (?:cipher|key exchange method) found. ^%(__prefix_line_ml1)sConnection from %(__on_port_opt)s%(__prefix_line_ml2)sUnable to negotiate a (?:cipher|key exchange method)%(__suff)s$ ^%(__prefix_line_ml1)sSSH: Server;Ltype: (?:Authname|Version|Kex);Remote: -\d+;[A-Z]\w+:.*%(__prefix_line_ml2)sRead from socket failed: Connection reset by peer%(__suff)s$ diff --git a/fail2ban/tests/files/logs/sshd-ddos b/fail2ban/tests/files/logs/sshd-ddos index 1caf5f50..f0a787a1 100644 --- a/fail2ban/tests/files/logs/sshd-ddos +++ b/fail2ban/tests/files/logs/sshd-ddos @@ -25,6 +25,8 @@ Nov 24 23:46:43 host sshd[32686]: fatal: Read from socket failed: Connection res Nov 25 01:34:12 srv sshd[123]: Received disconnect from 127.0.0.1: 14: No supported authentication methods available [preauth] # failJSON: { "time": "2004-11-25T01:35:13", "match": true , "host": "127.0.0.1", "desc": "No supported authentication methods" } Nov 25 01:35:13 srv sshd[123]: error: Received disconnect from 127.0.0.1: 14: No supported authentication methods available [preauth] +# failJSON: { "time": "2004-11-25T01:35:14", "match": true , "host": "192.168.2.92", "desc": "Optional space after port" } +Nov 25 01:35:14 srv sshd[3625]: error: Received disconnect from 192.168.2.92 port 1684:14: No supported authentication methods available [preauth] # gh-1545: # failJSON: { "time": "2004-11-26T13:03:29", "match": true , "host": "192.0.2.1", "desc": "No matching cipher" } From c4dc698d98c751826e40c0abad6f75a41774fcc7 Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 23 Jan 2017 09:26:05 +0100 Subject: [PATCH 19/33] evil symlink removed: does not supported by some file systems (e. g. development over net share) --- fail2ban/tests/config/filter.d/common.conf | 1 - fail2ban/tests/config/filter.d/zzz-generic-example.conf | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 120000 fail2ban/tests/config/filter.d/common.conf diff --git a/fail2ban/tests/config/filter.d/common.conf b/fail2ban/tests/config/filter.d/common.conf deleted file mode 120000 index 83e92474..00000000 --- a/fail2ban/tests/config/filter.d/common.conf +++ /dev/null @@ -1 +0,0 @@ -../../../../config/filter.d/common.conf \ No newline at end of file diff --git a/fail2ban/tests/config/filter.d/zzz-generic-example.conf b/fail2ban/tests/config/filter.d/zzz-generic-example.conf index e2ae91b0..2234b7b7 100644 --- a/fail2ban/tests/config/filter.d/zzz-generic-example.conf +++ b/fail2ban/tests/config/filter.d/zzz-generic-example.conf @@ -8,7 +8,7 @@ # Read common prefixes. If any customizations available -- read them from # common.local. common.conf is a symlink to the original common.conf and # should be copied (dereferenced) during installation -before = common.conf +before = ../../../../config/filter.d/common.conf [Definition] From 8768776d68d4271bb166af36870d12eab2bbca9c Mon Sep 17 00:00:00 2001 From: sebres Date: Thu, 9 Mar 2017 16:13:45 +0100 Subject: [PATCH 20/33] filter.d/cyrus-imap.conf: fixed `failregex` - accept entries without login-info resp. hostname before IP address --- config/filter.d/cyrus-imap.conf | 2 +- fail2ban/tests/files/logs/cyrus-imap | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/config/filter.d/cyrus-imap.conf b/config/filter.d/cyrus-imap.conf index 73764d9d..31dfda60 100644 --- a/config/filter.d/cyrus-imap.conf +++ b/config/filter.d/cyrus-imap.conf @@ -13,7 +13,7 @@ before = common.conf _daemon = (?:cyrus/)?(?:imap(d|s)?|pop3(d|s)?) -failregex = ^%(__prefix_line)sbadlogin: \S+ ?\[\] \S+ .*?\[?SASL\(-13\): (authentication failure|user not found): .*\]?$ +failregex = ^%(__prefix_line)sbadlogin: [^\[]*\[\] \S+ .*?\[?SASL\(-13\): (authentication failure|user not found): .*\]?$ ignoreregex = diff --git a/fail2ban/tests/files/logs/cyrus-imap b/fail2ban/tests/files/logs/cyrus-imap index f1edff06..c0ec54cb 100644 --- a/fail2ban/tests/files/logs/cyrus-imap +++ b/fail2ban/tests/files/logs/cyrus-imap @@ -16,3 +16,6 @@ Dec 30 16:03:27 somehost imapd[2517]: badlogin: local-somehost[1.2.3.4] OTP [SAS Jul 17 22:55:56 derry cyrus/imaps[7568]: badlogin: serafinat.xxxxxx [1.2.3.4] plain [SASL(-13): user not found: user: pressy@derry property: cmusaslsecretPLAIN not found in sasldb] # failJSON: { "time": "2005-07-18T16:46:42", "match": true , "host": "1.2.3.4" } Jul 18 16:46:42 derry cyrus/imaps[27449]: badlogin: serafinat.xxxxxx [1.2.3.4] PLAIN [SASL(-13): user not found: Password verification failed] + +# failJSON: { "time": "2005-03-08T05:25:21", "match": true , "host": "192.0.2.4", "desc": "entry without loginname/hostname before IP" } +Mar 8 05:25:21 host imap[22130]: badlogin: [192.0.2.4] plain [SASL(-13): authentication failure: Password verification failed] \ No newline at end of file From 0f8cb1749fdfe4e6a81e07a9cead1beefcd0de5b Mon Sep 17 00:00:00 2001 From: sebres Date: Thu, 9 Mar 2017 16:15:45 +0100 Subject: [PATCH 21/33] Update ChangeLog --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index 2a7e6638..e6114caa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -33,6 +33,8 @@ releases. and suffix (logged from several ssh versions), according to gh-1206; * filter.d/suhosin.conf - greedy catch-all before `` fixed (potential vulnerability) +* filter.d/cyrus-imap.conf + - accept entries without login-info resp. hostname before IP address (gh-1707) * Filter tests extended with check of all config-regexp, that contains greedy catch-all before ``, that is hard-anchored at end or precise sub expression after `` From 52c19503715ac5e21aa98e5cc6bfcfd36c9acda3 Mon Sep 17 00:00:00 2001 From: "Serg G. Brester" Date: Fri, 24 Mar 2017 19:03:17 +0100 Subject: [PATCH 22/33] Update mysqld-auth.conf small typo, closes gh-1725 (Thx @seth-reeser) --- config/filter.d/mysqld-auth.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/filter.d/mysqld-auth.conf b/config/filter.d/mysqld-auth.conf index 3ad70cb7..31bd2056 100644 --- a/config/filter.d/mysqld-auth.conf +++ b/config/filter.d/mysqld-auth.conf @@ -1,4 +1,4 @@ -# Fail2Ban filter for unsuccesfull MySQL authentication attempts +# Fail2Ban filter for unsuccesful MySQL authentication attempts # # # To log wrong MySQL access attempts add to /etc/my.cnf in [mysqld]: From e8596cfce755080baee24ceda500b7deb81cb11a Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 27 Mar 2017 11:27:41 +0200 Subject: [PATCH 23/33] amend resp. restore of change from 59c35bc44a175a672e084bc30511dfa3436ff052 (gh-129): - logging of "Log rotation detected" with new MSG level - introduces new log-level MSG (as INFO-2, 18) --- fail2ban/__init__.py | 2 ++ fail2ban/server/filter.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/fail2ban/__init__.py b/fail2ban/__init__.py index cd92dbab..7c752e24 100644 --- a/fail2ban/__init__.py +++ b/fail2ban/__init__.py @@ -34,7 +34,9 @@ Below derived from: https://mail.python.org/pipermail/tutor/2007-August/056243.html """ +logging.MSG = logging.INFO - 2 logging.NOTICE = logging.INFO + 5 +logging.addLevelName(logging.MSG, 'MSG') logging.addLevelName(logging.NOTICE, 'NOTICE') diff --git a/fail2ban/server/filter.py b/fail2ban/server/filter.py index 459a47d0..066ee68f 100644 --- a/fail2ban/server/filter.py +++ b/fail2ban/server/filter.py @@ -820,7 +820,7 @@ class FileContainer: ## sys.stdout.flush() # Compare hash and inode if self.__hash != myHash or self.__ino != stats.st_ino: - logSys.info("Log rotation detected for %s" % self.__filename) + logSys.log(logging.MSG, "Log rotation detected for %s" % self.__filename) self.__hash = myHash self.__ino = stats.st_ino self.__pos = 0 From 7982d1e627913a8cde7bf840bbf3fcb8cb25deda Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 27 Mar 2017 11:31:41 +0200 Subject: [PATCH 24/33] Update ChangeLog --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index e6114caa..213e2c0e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -46,6 +46,7 @@ releases. - filter.d/domino-smtp: IBM Domino SMTP task (gh-1603) ### Enhancements +* Introduced new log-level `MSG` (as INFO-2, equivalent to 18) ver. 0.9.6 (2016/12/10) - stretch-is-coming From a639f0b083c213bde4ff3dcfbbb9fbcab0dd55f8 Mon Sep 17 00:00:00 2001 From: Paul Brook Date: Sun, 16 Apr 2017 12:11:05 -0400 Subject: [PATCH 25/33] BF: specify explicit time offset not a time zone name to avoid needing tzdata during testing --- fail2ban/tests/utils.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fail2ban/tests/utils.py b/fail2ban/tests/utils.py index 9155dc37..54861050 100644 --- a/fail2ban/tests/utils.py +++ b/fail2ban/tests/utils.py @@ -95,7 +95,10 @@ def setUpMyTime(): # Set the time to a fixed, known value # Sun Aug 14 12:00:00 CEST 2005 # yoh: we need to adjust TZ to match the one used by Cyril so all the timestamps match - os.environ['TZ'] = 'Europe/Zurich' + # This offset corresponds to Europe/Zurich timezone. Specifying it + # explicitly allows to avoid requiring tzdata package to be installed during + # testing. See https://bugs.debian.org/855920 for more information + os.environ['TZ'] = 'CET-01CEST-02,M3.5.0,M10.5.0' time.tzset() MyTime.setTime(1124013600) From 3161bcf78b86ee5916d85c9551ba2efedede9d84 Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 24 Apr 2017 19:13:38 +0200 Subject: [PATCH 26/33] filter.d/exim.conf: optional part `(...)` after host-name before `[IP]`, normalized over whole config file. # Conflicts: # config/filter.d/exim.conf --- config/filter.d/exim.conf | 6 +++--- fail2ban/tests/files/logs/exim | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/config/filter.d/exim.conf b/config/filter.d/exim.conf index a1d699c0..27d73426 100644 --- a/config/filter.d/exim.conf +++ b/config/filter.d/exim.conf @@ -14,13 +14,13 @@ before = exim-common.conf [Definition] failregex = ^%(pid)s %(host_info)ssender verify fail for <\S+>: (?:Unknown user|Unrouteable address|all relevant MX records point to non-existent hosts)\s*$ - ^%(pid)s \w+ authenticator failed for (\S+ )?\(\S+\) \[\](?::\d+)?(?: I=\[\S+\](:\d+)?)?: 535 Incorrect authentication data( \(set_id=.*\)|: \d+ Time\(s\))?\s*$ + ^%(pid)s \w+ authenticator failed for (?:[^\[\( ]* )?(?:\(\S*\) )?\[\](?::\d+)?(?: I=\[\S+\](:\d+)?)?: 535 Incorrect authentication data( \(set_id=.*\)|: \d+ Time\(s\))?\s*$ ^%(pid)s %(host_info)sF=(?:<>|[^@]+@\S+) rejected RCPT [^@]+@\S+: (?:relay not permitted|Sender verify failed|Unknown user)\s*$ ^%(pid)s SMTP protocol synchronization error \([^)]*\): rejected (?:connection from|"\S+") %(host_info)s(?:next )?input=".*"\s*$ ^%(pid)s SMTP call from \S+ %(host_info)sdropped: too many nonmail commands \(last was "\S+"\)\s*$ ^%(pid)s SMTP protocol error in "AUTH \S*(?: \S*)?" %(host_info)sAUTH command used when not advertised\s*$ - ^%(pid)s no MAIL in SMTP connection from (?:\S* )?(?:\(\S*\) )?%(host_info)sD=\d+s(?: C=\S*)?\s*$ - ^%(pid)s \S+ SMTP connection from (?:\S* )?(?:\(\S*\) )?%(host_info)sclosed by DROP in ACL\s*$ + ^%(pid)s no MAIL in SMTP connection from (?:[^\[\( ]* )?(?:\(\S*\) )?%(host_info)sD=\d+s(?: C=\S*)?\s*$ + ^%(pid)s ([\w\-]+ )?SMTP connection from (?:[^\[\( ]* )?(?:\(\S*\) )?%(host_info)sclosed by DROP in ACL\s*$ ignoreregex = diff --git a/fail2ban/tests/files/logs/exim b/fail2ban/tests/files/logs/exim index 9053bf8d..44d9e34b 100644 --- a/fail2ban/tests/files/logs/exim +++ b/fail2ban/tests/files/logs/exim @@ -67,3 +67,6 @@ 2016-04-01 11:09:21 [18648] SMTP protocol error in "AUTH LOGIN" H=host.example.com (SERVER) [192.0.2.1]:4692 I=[172.89.0.6]:25 AUTH command used when not advertised # failJSON: { "time": "2016-03-27T16:48:48", "match": true , "host": "192.0.2.1" } 2016-03-27 16:48:48 [21478] 1akDqs-0005aQ-9b SMTP connection from host.example.com (SERVER) [192.0.2.1]:47714 I=[172.89.0.6]:25 closed by DROP in ACL + +# failJSON: { "time": "2017-04-23T22:45:59", "match": true , "host": "192.0.2.2", "desc": "optional part (...)" } +2017-04-23 22:45:59 fixed_login authenticator failed for bad.host.example.com [192.0.2.2]:54412 I=[172.89.0.6]:587: 535 Incorrect authentication data (set_id=user@example.com) From 462442a5174a7f260d4bc2029336548bf0f1e167 Mon Sep 17 00:00:00 2001 From: sebres Date: Tue, 25 Apr 2017 10:04:45 +0200 Subject: [PATCH 27/33] Update ChangeLog #1757 --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index 213e2c0e..7d5929d7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -22,6 +22,8 @@ releases. (0.10th resp. IPv6 relevant only, amend for gh-1479) * config/pathes-freebsd.conf - Fixed filenames for apache and nginx log files (gh-1667) +* filter.d/exim.conf + - optional part `(...)` after host-name before `[IP]` (gh-1751) * filter.d/sshd.conf - new aggressive rules (gh-864): - Connection reset by peer (multi-line rule during authorization process) From c546f852070377455985169d7efaadd65bb85e34 Mon Sep 17 00:00:00 2001 From: sebres Date: Sun, 7 May 2017 13:02:32 +0200 Subject: [PATCH 28/33] filter.d/exim.conf: cherry-picked from 0.10, match complex time like `D=2m42s` (closes gh-1766) --- config/filter.d/exim-common.conf | 4 +++- config/filter.d/exim.conf | 6 +++--- fail2ban/tests/files/logs/exim | 2 ++ 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/config/filter.d/exim-common.conf b/config/filter.d/exim-common.conf index 0e1b74fa..b3b25750 100644 --- a/config/filter.d/exim-common.conf +++ b/config/filter.d/exim-common.conf @@ -9,7 +9,9 @@ after = exim-common.local [Definition] -host_info = (?:H=([\w.-]+ )?(?:\(\S+\) )?)?\[\](?::\d+)? (?:I=\[\S+\](:\d+)? )?(?:U=\S+ )?(?:P=e?smtp )? +host_info_pre = (?:H=([\w.-]+ )?(?:\(\S+\) )?)? +host_info_suf = (?::\d+)?(?: I=\[\S+\](:\d+)?)?(?: U=\S+)?(?: P=e?smtp)?(?: F=(?:<>|[^@]+@\S+))?\s +host_info = %(host_info_pre)s\[\]%(host_info_suf)s pid = (?: \[\d+\])? # DEV Notes: diff --git a/config/filter.d/exim.conf b/config/filter.d/exim.conf index 27d73426..c5352008 100644 --- a/config/filter.d/exim.conf +++ b/config/filter.d/exim.conf @@ -15,12 +15,12 @@ before = exim-common.conf failregex = ^%(pid)s %(host_info)ssender verify fail for <\S+>: (?:Unknown user|Unrouteable address|all relevant MX records point to non-existent hosts)\s*$ ^%(pid)s \w+ authenticator failed for (?:[^\[\( ]* )?(?:\(\S*\) )?\[\](?::\d+)?(?: I=\[\S+\](:\d+)?)?: 535 Incorrect authentication data( \(set_id=.*\)|: \d+ Time\(s\))?\s*$ - ^%(pid)s %(host_info)sF=(?:<>|[^@]+@\S+) rejected RCPT [^@]+@\S+: (?:relay not permitted|Sender verify failed|Unknown user)\s*$ + ^%(pid)s %(host_info)srejected RCPT [^@]+@\S+: (?:relay not permitted|Sender verify failed|Unknown user)\s*$ ^%(pid)s SMTP protocol synchronization error \([^)]*\): rejected (?:connection from|"\S+") %(host_info)s(?:next )?input=".*"\s*$ ^%(pid)s SMTP call from \S+ %(host_info)sdropped: too many nonmail commands \(last was "\S+"\)\s*$ ^%(pid)s SMTP protocol error in "AUTH \S*(?: \S*)?" %(host_info)sAUTH command used when not advertised\s*$ - ^%(pid)s no MAIL in SMTP connection from (?:[^\[\( ]* )?(?:\(\S*\) )?%(host_info)sD=\d+s(?: C=\S*)?\s*$ - ^%(pid)s ([\w\-]+ )?SMTP connection from (?:[^\[\( ]* )?(?:\(\S*\) )?%(host_info)sclosed by DROP in ACL\s*$ + ^%(pid)s no MAIL in SMTP connection from (?:[^\[\( ]* )?(?:\(\S*\) )?%(host_info)sD=\d\S+s(?: C=\S*)?\s*$ + ^%(pid)s (?:[\w\-]+ )?SMTP connection from (?:[^\[\( ]* )?(?:\(\S*\) )?%(host_info)sclosed by DROP in ACL\s*$ ignoreregex = diff --git a/fail2ban/tests/files/logs/exim b/fail2ban/tests/files/logs/exim index 44d9e34b..144335d7 100644 --- a/fail2ban/tests/files/logs/exim +++ b/fail2ban/tests/files/logs/exim @@ -63,6 +63,8 @@ # failJSON: { "time": "2016-04-01T11:08:39", "match": true , "host": "192.0.2.1" } 2016-04-01 11:08:39 [18643] no MAIL in SMTP connection from host.example.com (SERVER) [192.0.2.1]:1418 I=[172.89.0.6]:25 D=34s C=EHLO,AUTH +# failJSON: { "time": "2016-04-01T11:08:40", "match": true , "host": "192.0.2.2" } +2016-04-01 11:08:40 [18643] no MAIL in SMTP connection from host.example.com (SERVER) [192.0.2.2]:1418 I=[172.89.0.6]:25 D=2m42s C=QUIT # failJSON: { "time": "2016-04-01T11:09:21", "match": true , "host": "192.0.2.1" } 2016-04-01 11:09:21 [18648] SMTP protocol error in "AUTH LOGIN" H=host.example.com (SERVER) [192.0.2.1]:4692 I=[172.89.0.6]:25 AUTH command used when not advertised # failJSON: { "time": "2016-03-27T16:48:48", "match": true , "host": "192.0.2.1" } From 3d64d705f30c31bfb3a45468b5ee18e7c3dbc18f Mon Sep 17 00:00:00 2001 From: sebres Date: Sun, 7 May 2017 13:17:43 +0200 Subject: [PATCH 29/33] try to fix travis integration of pypy3: setuptools recently dropped support for Python 3.0 - 3.2, but old pypy3 based on Python 3.2.5 --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9ef607da..40376075 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,9 @@ python: # - 3.2 - 3.3 - 3.4 - - pypy3 + # disabled since setuptools dropped support for Python 3.0 - 3.2 + # - pypy3 + - pypy3.3-5.2-alpha1 before_install: - if [[ $TRAVIS_PYTHON_VERSION == 2* || $TRAVIS_PYTHON_VERSION == 'pypy' ]]; then export F2B_PY_2=true && echo "Set F2B_PY_2"; fi - if [[ $TRAVIS_PYTHON_VERSION == 3* || $TRAVIS_PYTHON_VERSION == 'pypy3' ]]; then export F2B_PY_3=true && echo "Set F2B_PY_3"; fi From 0600d51511c348a0a3e2fc20fa823fbe235df6c9 Mon Sep 17 00:00:00 2001 From: sebres Date: Sun, 7 May 2017 13:53:06 +0200 Subject: [PATCH 30/33] filter.d/exim.conf: added new reason for "rejected RCPT" regex: Unrouteable address --- config/filter.d/exim.conf | 2 +- fail2ban/tests/files/logs/exim | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/config/filter.d/exim.conf b/config/filter.d/exim.conf index c5352008..7848fe00 100644 --- a/config/filter.d/exim.conf +++ b/config/filter.d/exim.conf @@ -15,7 +15,7 @@ before = exim-common.conf failregex = ^%(pid)s %(host_info)ssender verify fail for <\S+>: (?:Unknown user|Unrouteable address|all relevant MX records point to non-existent hosts)\s*$ ^%(pid)s \w+ authenticator failed for (?:[^\[\( ]* )?(?:\(\S*\) )?\[\](?::\d+)?(?: I=\[\S+\](:\d+)?)?: 535 Incorrect authentication data( \(set_id=.*\)|: \d+ Time\(s\))?\s*$ - ^%(pid)s %(host_info)srejected RCPT [^@]+@\S+: (?:relay not permitted|Sender verify failed|Unknown user)\s*$ + ^%(pid)s %(host_info)srejected RCPT [^@]+@\S+: (?:relay not permitted|Sender verify failed|Unknown user|Unrouteable address)\s*$ ^%(pid)s SMTP protocol synchronization error \([^)]*\): rejected (?:connection from|"\S+") %(host_info)s(?:next )?input=".*"\s*$ ^%(pid)s SMTP call from \S+ %(host_info)sdropped: too many nonmail commands \(last was "\S+"\)\s*$ ^%(pid)s SMTP protocol error in "AUTH \S*(?: \S*)?" %(host_info)sAUTH command used when not advertised\s*$ diff --git a/fail2ban/tests/files/logs/exim b/fail2ban/tests/files/logs/exim index 144335d7..326cdf28 100644 --- a/fail2ban/tests/files/logs/exim +++ b/fail2ban/tests/files/logs/exim @@ -72,3 +72,5 @@ # failJSON: { "time": "2017-04-23T22:45:59", "match": true , "host": "192.0.2.2", "desc": "optional part (...)" } 2017-04-23 22:45:59 fixed_login authenticator failed for bad.host.example.com [192.0.2.2]:54412 I=[172.89.0.6]:587: 535 Incorrect authentication data (set_id=user@example.com) +# failJSON: { "time": "2017-05-01T07:42:42", "match": true , "host": "192.0.2.3", "desc": "rejected RCPT - Unrouteable address" } +2017-05-01 07:42:42 H=some.rev.dns.if.found (the.connector.reports.this.name) [192.0.2.3] F= rejected RCPT : Unrouteable address From bea3a62a37a6bbfdf65057d6769147a2bfe7cd5f Mon Sep 17 00:00:00 2001 From: sebres Date: Sun, 7 May 2017 13:56:24 +0200 Subject: [PATCH 31/33] update ChangeLog --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index 7d5929d7..c60ff660 100644 --- a/ChangeLog +++ b/ChangeLog @@ -24,6 +24,8 @@ releases. - Fixed filenames for apache and nginx log files (gh-1667) * filter.d/exim.conf - optional part `(...)` after host-name before `[IP]` (gh-1751) + - new reason "Unrouteable address" for "rejected RCPT" regex (gh-1762) + - match of complex time like `D=2m42s` in regex "no MAIL in SMTP connection" (gh-1766) * filter.d/sshd.conf - new aggressive rules (gh-864): - Connection reset by peer (multi-line rule during authorization process) From 663d526d7481228a7da568e2baf8b08e2924a3e1 Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Wed, 10 May 2017 21:31:09 -0400 Subject: [PATCH 32/33] Added newly added files to MANIFEST --- MANIFEST | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/MANIFEST b/MANIFEST index b12e3163..e91ccff0 100644 --- a/MANIFEST +++ b/MANIFEST @@ -37,6 +37,7 @@ config/action.d/mail-whois-common.conf config/action.d/mail-whois.conf config/action.d/mail-whois-lines.conf config/action.d/mynetwatchman.conf +config/action.d/netscaler.conf config/action.d/nftables-allports.conf config/action.d/nftables-common.conf config/action.d/nftables-multiport.conf @@ -83,6 +84,7 @@ config/filter.d/courier-auth.conf config/filter.d/courier-smtp.conf config/filter.d/cyrus-imap.conf config/filter.d/directadmin.conf +config/filter.d/domino-smtp.conf config/filter.d/dovecot.conf config/filter.d/dropbear.conf config/filter.d/drupal-auth.conf @@ -138,6 +140,7 @@ config/filter.d/sogo-auth.conf config/filter.d/solid-pop3d.conf config/filter.d/squid.conf config/filter.d/squirrelmail.conf +config/filter.d/sshd-aggressive.conf config/filter.d/sshd.conf config/filter.d/sshd-ddos.conf config/filter.d/stunnel.conf @@ -278,6 +281,7 @@ fail2ban/tests/files/logs/courier-auth fail2ban/tests/files/logs/courier-smtp fail2ban/tests/files/logs/cyrus-imap fail2ban/tests/files/logs/directadmin +fail2ban/tests/files/logs/domino-smtp fail2ban/tests/files/logs/dovecot fail2ban/tests/files/logs/dropbear fail2ban/tests/files/logs/drupal-auth @@ -330,6 +334,7 @@ fail2ban/tests/files/logs/solid-pop3d fail2ban/tests/files/logs/squid fail2ban/tests/files/logs/squirrelmail fail2ban/tests/files/logs/sshd +fail2ban/tests/files/logs/sshd-aggressive fail2ban/tests/files/logs/sshd-ddos fail2ban/tests/files/logs/stunnel fail2ban/tests/files/logs/suhosin From 35280044ffdb6a8166fc6ad5497cfae7032c71a6 Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Wed, 10 May 2017 21:38:57 -0400 Subject: [PATCH 33/33] Preparing for 0.9.7 release --- ChangeLog | 4 ++-- README.md | 2 +- fail2ban/version.py | 2 +- man/fail2ban-client.1 | 4 ++-- man/fail2ban-regex.1 | 2 +- man/fail2ban-server.1 | 4 ++-- man/fail2ban-testcases.1 | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index c60ff660..ec855ab0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,7 +7,7 @@ Fail2Ban: Changelog =================== -ver. 0.9.x (2016/??/??) - wanna-be-released +ver. 0.9.7 (2017/05/11) - awaiting-victory ----------- 0.9.x line is no longer heavily developed. If you are interested in @@ -40,7 +40,7 @@ releases. * filter.d/cyrus-imap.conf - accept entries without login-info resp. hostname before IP address (gh-1707) * Filter tests extended with check of all config-regexp, that contains greedy catch-all - before ``, that is hard-anchored at end or precise sub expression after `` + before ``, that is hard-anchored at end or precise sub expression after `` ### New Features * New Actions: diff --git a/README.md b/README.md index 3f0e3253..89844d1d 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ / _|__ _(_) |_ ) |__ __ _ _ _ | _/ _` | | |/ /| '_ \/ _` | ' \ |_| \__,_|_|_/___|_.__/\__,_|_||_| - v0.9.6.dev0 2016/??/?? + v0.9.7 2017/05/11 ## Fail2Ban: ban hosts that cause multiple authentication errors diff --git a/fail2ban/version.py b/fail2ban/version.py index c2a8dc59..e8344517 100644 --- a/fail2ban/version.py +++ b/fail2ban/version.py @@ -24,4 +24,4 @@ __author__ = "Cyril Jaquier, Yaroslav Halchenko, Steven Hiscocks, Daniel Black" __copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2005-2016 Yaroslav Halchenko, 2013-2014 Steven Hiscocks, Daniel Black" __license__ = "GPL-v2+" -version = "0.9.6.dev0" +version = "0.9.7" diff --git a/man/fail2ban-client.1 b/man/fail2ban-client.1 index ff3e5f77..34a9d894 100644 --- a/man/fail2ban-client.1 +++ b/man/fail2ban-client.1 @@ -1,12 +1,12 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH FAIL2BAN-CLIENT "1" "December 2016" "fail2ban-client v0.9.6" "User Commands" +.TH FAIL2BAN-CLIENT "1" "May 2017" "fail2ban-client v0.9.7" "User Commands" .SH NAME fail2ban-client \- configure and control the server .SH SYNOPSIS .B fail2ban-client [\fI\,OPTIONS\/\fR] \fI\,\/\fR .SH DESCRIPTION -Fail2Ban v0.9.6 reads log file that contains password failure report +Fail2Ban v0.9.7 reads log file that contains password failure report and bans the corresponding IP addresses using firewall rules. .SH OPTIONS .TP diff --git a/man/fail2ban-regex.1 b/man/fail2ban-regex.1 index 1ed2c327..d117ee38 100644 --- a/man/fail2ban-regex.1 +++ b/man/fail2ban-regex.1 @@ -1,5 +1,5 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH FAIL2BAN-REGEX "1" "December 2016" "fail2ban-regex 0.9.6" "User Commands" +.TH FAIL2BAN-REGEX "1" "May 2017" "fail2ban-regex 0.9.7" "User Commands" .SH NAME fail2ban-regex \- test Fail2ban "failregex" option .SH SYNOPSIS diff --git a/man/fail2ban-server.1 b/man/fail2ban-server.1 index 5278302c..b71f6b52 100644 --- a/man/fail2ban-server.1 +++ b/man/fail2ban-server.1 @@ -1,12 +1,12 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH FAIL2BAN-SERVER "1" "December 2016" "fail2ban-server v0.9.6" "User Commands" +.TH FAIL2BAN-SERVER "1" "May 2017" "fail2ban-server v0.9.7" "User Commands" .SH NAME fail2ban-server \- start the server .SH SYNOPSIS .B fail2ban-server [\fI\,OPTIONS\/\fR] .SH DESCRIPTION -Fail2Ban v0.9.6 reads log file that contains password failure report +Fail2Ban v0.9.7 reads log file that contains password failure report and bans the corresponding IP addresses using firewall rules. .PP Only use this command for debugging purpose. Start the server with diff --git a/man/fail2ban-testcases.1 b/man/fail2ban-testcases.1 index 658555ac..3d250f5c 100644 --- a/man/fail2ban-testcases.1 +++ b/man/fail2ban-testcases.1 @@ -1,5 +1,5 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.4. -.TH FAIL2BAN-TESTCASES "1" "December 2016" "fail2ban-testcases 0.9.6" "User Commands" +.TH FAIL2BAN-TESTCASES "1" "May 2017" "fail2ban-testcases 0.9.7" "User Commands" .SH NAME fail2ban-testcases \- run Fail2Ban unit-tests .SH SYNOPSIS