mirror of https://github.com/fail2ban/fail2ban
commit
78562fb700
18
ChangeLog
18
ChangeLog
|
@ -54,7 +54,6 @@ configuration before relying on it.
|
||||||
into logging messages in case of error or at DEBUG loglevel.
|
into logging messages in case of error or at DEBUG loglevel.
|
||||||
* Added action xarf-login-attack to report formatted attack messages
|
* Added action xarf-login-attack to report formatted attack messages
|
||||||
according to the XARF standard (v0.2). Close gh-105
|
according to the XARF standard (v0.2). Close gh-105
|
||||||
* Add filter for apache-modsecurity
|
|
||||||
* Support PyPy
|
* Support PyPy
|
||||||
|
|
||||||
- Enhancements
|
- Enhancements
|
||||||
|
@ -88,8 +87,11 @@ ver. 0.8.12 (2013/12/XX) - things-can-only-get-better
|
||||||
- Fix firewall-cmd actioncheck - patch from Adam Tkac. Redhat Bug #979622
|
- Fix firewall-cmd actioncheck - patch from Adam Tkac. Redhat Bug #979622
|
||||||
- Fix apache-common for apache-2.4 log file format. Thanks Mark White.
|
- Fix apache-common for apache-2.4 log file format. Thanks Mark White.
|
||||||
Closes gh-516
|
Closes gh-516
|
||||||
|
- Asynchat changed to use push method which verifys whether all data was
|
||||||
|
send. This ensures that all data is sent before closing the connection.
|
||||||
|
|
||||||
- Enhancements:
|
- Enhancements:
|
||||||
|
- added firewallcmd-ipset action
|
||||||
- long names on jails documented based on iptables limit of 30 less
|
- long names on jails documented based on iptables limit of 30 less
|
||||||
len("fail2ban-").
|
len("fail2ban-").
|
||||||
- remove indentation of name and loglevel while logging to SYSLOG to
|
- remove indentation of name and loglevel while logging to SYSLOG to
|
||||||
|
@ -98,14 +100,18 @@ ver. 0.8.12 (2013/12/XX) - things-can-only-get-better
|
||||||
- updated check_fail2ban to return performance data for all jails.
|
- updated check_fail2ban to return performance data for all jails.
|
||||||
- filter apache-noscript now includes php cgi scripts.
|
- filter apache-noscript now includes php cgi scripts.
|
||||||
Thanks dani. Closes gh-503
|
Thanks dani. Closes gh-503
|
||||||
|
- added ufw action. Thanks Guilhem Lettron. lp-#701522
|
||||||
|
- exim-spam filter to match spamassassin log entry for option SAdevnull.
|
||||||
|
Thanks Ivo Truxa. Closes gh-533
|
||||||
|
- filter.d/nsd.conf -- also amended Unix date template to match nsd format
|
||||||
|
- loglines now also report "[PID]" after the name portion
|
||||||
|
|
||||||
- New Features:
|
- New Features:
|
||||||
|
|
||||||
* filter.d/solid-pop3d -- added thanks to Jacques Lav!gnotte on mailinglist.
|
- Added filter for solid-pop3d -- thanks to Jacques Lav!gnotte on mailinglist.
|
||||||
* filter.d/nsd.conf -- also amended Unix date template to match nsd format
|
- Added filter for apache-modsecurity
|
||||||
|
- Added filter for openwebmail thanks Ivo Truxa. Closes gh-543
|
||||||
- Enhancements:
|
- Added filter for horde
|
||||||
- loglines now also report "[PID]" after the name portion
|
|
||||||
|
|
||||||
ver. 0.8.11 (2013/11/13) - loves-unittests-and-tight-DoS-free-filter-regexes
|
ver. 0.8.11 (2013/11/13) - loves-unittests-and-tight-DoS-free-filter-regexes
|
||||||
|
|
||||||
|
|
460
DEVELOP
460
DEVELOP
|
@ -34,465 +34,7 @@ When submitting pull requests on GitHub we ask you to:
|
||||||
* Include a change to the relevant section of the ChangeLog; and
|
* Include a change to the relevant section of the ChangeLog; and
|
||||||
* Include yourself in THANKS if not already there.
|
* Include yourself in THANKS if not already there.
|
||||||
|
|
||||||
Filters
|
If you are developing filters see the FILTERS file for documentation.
|
||||||
=======
|
|
||||||
|
|
||||||
Filters are tricky. They need to:
|
|
||||||
* work with a variety of the versions of the software that generates the logs;
|
|
||||||
* work with the range of logging configuration options available in the
|
|
||||||
software;
|
|
||||||
* work with multiple operating systems;
|
|
||||||
* not make assumptions about the log format in excess of the software
|
|
||||||
(e.g. do not assume a username doesn't contain spaces and use \S+ unless
|
|
||||||
you've checked the source code);
|
|
||||||
* account for how future versions of the software will log messages
|
|
||||||
(e.g. guess what would happen to the log message if different authentication
|
|
||||||
types are added);
|
|
||||||
* not be susceptible to DoS vulnerabilities (see Filter Security below); and
|
|
||||||
* match intended log lines only.
|
|
||||||
|
|
||||||
Please follow the steps from Filter Test Cases to Developing Filter Regular
|
|
||||||
Expressions and submit a GitHub pull request (PR) afterwards. If you get stuck,
|
|
||||||
you can push your unfinished changes and still submit a PR -- describe
|
|
||||||
what you have done, what is the hurdle, and we'll attempt to help (PR
|
|
||||||
will be automagically updated with future commits you would push to
|
|
||||||
complete it).
|
|
||||||
|
|
||||||
Filter test cases
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
Purpose:
|
|
||||||
|
|
||||||
Start by finding the log messages that the application generates related to
|
|
||||||
some form of authentication failure. If you are adding to an existing filter
|
|
||||||
think about whether the log messages are of a similar importance and purpose
|
|
||||||
to the existing filter. If you were a user of Fail2Ban, and did a package
|
|
||||||
update of Fail2Ban that started matching new log messages, would anything
|
|
||||||
unexpected happen? Would the bantime/findtime for the jail be appropriate for
|
|
||||||
the new log messages? If it doesn't, perhaps it needs to be in a separate
|
|
||||||
filter definition, for example like exim filter aims at authentication failures
|
|
||||||
and exim-spam at log messages related to spam.
|
|
||||||
|
|
||||||
Even if it is a new filter you may consider separating the log messages into
|
|
||||||
different filters based on purpose.
|
|
||||||
|
|
||||||
Cause:
|
|
||||||
|
|
||||||
Are some of the log lines a result of the same action? For example, is a PAM
|
|
||||||
failure log message, followed by an application specific failure message the
|
|
||||||
result of the same user/script action? If you add regular expressions for
|
|
||||||
both you would end up with two failures for a single action.
|
|
||||||
Therefore, select the most appropriate log message and document the other log
|
|
||||||
message) with a test case not to match it and a description as to why you chose
|
|
||||||
one over another.
|
|
||||||
|
|
||||||
With the selected log lines consider what action has caused those log
|
|
||||||
messages and whether they could have been generated by accident? Could
|
|
||||||
the log message be occurring due to the first step towards the application
|
|
||||||
asking for authentication? Could the log messages occur often? If some of
|
|
||||||
these are true make a note of this in the jail.conf example that you provide.
|
|
||||||
|
|
||||||
Samples:
|
|
||||||
|
|
||||||
It is important to include log file samples so any future change in the regular
|
|
||||||
expression will still work with the log lines you have identified.
|
|
||||||
|
|
||||||
The sample log messages are provided in a file under testcases/files/logs/
|
|
||||||
named identically as the corresponding filter (but without .conf extension).
|
|
||||||
Each log line should be preceded by a line with failJSON metadata (so the logs
|
|
||||||
lines are tested in the test suite) directly above the log line. If there is
|
|
||||||
any specific information about the log message, such as version or an
|
|
||||||
application configuration option that is needed for the message to occur,
|
|
||||||
include this in a comment (line beginning with #) above the failJSON metadata.
|
|
||||||
|
|
||||||
Log samples should include only one, definitely not more than 3, examples of
|
|
||||||
log messages of the same form. If log messages are different in different
|
|
||||||
versions of the application log messages that show this are encouraged.
|
|
||||||
|
|
||||||
Also attempt to inject an IP into the application (e.g. by specifying
|
|
||||||
it as a username) so that Fail2Ban possibly detects the IP
|
|
||||||
from user input rather than the true origin. See the Filter Security section
|
|
||||||
and the top example in testcases/files/logs/apache-auth as to how to do this.
|
|
||||||
One you have discovered that this is possible, correct the regex so it doesn't
|
|
||||||
match and provide this as a test case with "match": false (see failJSON below).
|
|
||||||
|
|
||||||
If the mechanism to create the log message isn't obvious provide a
|
|
||||||
configuration and/or sample scripts testcases/files/config/{filtername} and
|
|
||||||
reference these in the comments above the log line.
|
|
||||||
|
|
||||||
FailJSON metadata:
|
|
||||||
|
|
||||||
A failJSON metadata is a comment immediately above the log message. It will
|
|
||||||
look like:
|
|
||||||
|
|
||||||
# failJSON: { "time": "2013-06-10T10:10:59", "match": true , "host": "93.184.216.119" }
|
|
||||||
|
|
||||||
Time should match the time of the log message. It is in a specific format of
|
|
||||||
Year-Month-Day'T'Hour:minute:Second. If your log message does not include a
|
|
||||||
year, like the example below, the year should be listed as 2005, if before Sun
|
|
||||||
Aug 14 10am UTC, and 2004 if afterwards. Here is an example failJSON
|
|
||||||
line preceding a sample log line:
|
|
||||||
|
|
||||||
# failJSON: { "time": "2005-03-24T15:25:51", "match": true , "host": "198.51.100.87" }
|
|
||||||
Mar 24 15:25:51 buffalo1 dropbear[4092]: bad password attempt for 'root' from 198.51.100.87:5543
|
|
||||||
|
|
||||||
The "host" in failJSON should contain the IP or domain that should be blocked.
|
|
||||||
|
|
||||||
For long lines that you do not want to be matched (e.g. from log injection
|
|
||||||
attacks) and any log lines to be excluded (see "Cause" section above), set
|
|
||||||
"match": false in the failJSON and describe the reason in the comment above.
|
|
||||||
|
|
||||||
After developing regexes, the following command will test all failJSON metadata
|
|
||||||
against the log lines in all sample log files
|
|
||||||
|
|
||||||
./fail2ban-testcases testSampleRegex
|
|
||||||
|
|
||||||
Developing Filter Regular Expressions
|
|
||||||
-------------------------------------
|
|
||||||
|
|
||||||
Date/Time:
|
|
||||||
|
|
||||||
At the moment, Fail2Ban depends on log lines to have time stamps. That is why
|
|
||||||
before starting to develop failregex, check if your log line format known to
|
|
||||||
Fail2Ban. Copy the time component from the log line and append an IP address to
|
|
||||||
test with following command:
|
|
||||||
|
|
||||||
./fail2ban-regex "2013-09-19 02:46:12 1.2.3.4" "<HOST>"
|
|
||||||
|
|
||||||
Output of such command should contain something like:
|
|
||||||
|
|
||||||
Date template hits:
|
|
||||||
|- [# of hits] date format
|
|
||||||
| [1] Year-Month-Day Hour:Minute:Second
|
|
||||||
|
|
||||||
Ensure that the template description matches time/date elements in your log line
|
|
||||||
time stamp. If there is no matched format then date template needs to be added
|
|
||||||
to server/datedetector.py. Ensure that a new template is added in the order
|
|
||||||
that more specific matches occur first and that there is no confusion between a
|
|
||||||
Day and a Month.
|
|
||||||
|
|
||||||
Filter file:
|
|
||||||
|
|
||||||
The filter is specified in a config/filter.d/{filtername}.conf file. Filter file
|
|
||||||
can have sections INCLUDES (optional) and Definition as follows:
|
|
||||||
|
|
||||||
[INCLUDES]
|
|
||||||
|
|
||||||
before = common.conf
|
|
||||||
|
|
||||||
after = filtername.local
|
|
||||||
|
|
||||||
[Definition]
|
|
||||||
|
|
||||||
failregex = ....
|
|
||||||
|
|
||||||
ignoreregex = ....
|
|
||||||
|
|
||||||
This is also documented in the man page jail.conf (section 5). Other definitions
|
|
||||||
can be added to make failregex's more readable and maintainable to be used
|
|
||||||
through string Interpolations (see http://docs.python.org/2.7/library/configparser.html)
|
|
||||||
|
|
||||||
|
|
||||||
General rules:
|
|
||||||
|
|
||||||
Use "before" if you need to include a common set of rules, like syslog or if
|
|
||||||
there is a common set of regexes for multiple filters.
|
|
||||||
|
|
||||||
Use "after" if you wish to allow the user to overwrite a set of customisations
|
|
||||||
of the current filter. This file doesn't need to exist.
|
|
||||||
|
|
||||||
Try to avoid using ignoreregex mainly for performance reasons. The case when you
|
|
||||||
would use it is if in trying to avoid using it, you end up with an unreadable
|
|
||||||
failregex.
|
|
||||||
|
|
||||||
Syslog:
|
|
||||||
|
|
||||||
If your application logs to syslog you can take advantage of log line prefix
|
|
||||||
definitions present in common.conf. So as a base use:
|
|
||||||
|
|
||||||
[INCLUDES]
|
|
||||||
|
|
||||||
before = common.conf
|
|
||||||
|
|
||||||
[Definition]
|
|
||||||
|
|
||||||
_daemon = app
|
|
||||||
|
|
||||||
failregex = ^%(__prefix_line)s
|
|
||||||
|
|
||||||
In this example common.conf defines __prefix_line which also contains the
|
|
||||||
_daemon name (in syslog terms the service) you have just specified. _daemon
|
|
||||||
can also be a regex.
|
|
||||||
|
|
||||||
For example, to capture following line _daemon should be set to "dovecot"
|
|
||||||
|
|
||||||
Dec 12 11:19:11 dunnart dovecot: pop3-login: Aborted login (tried to use disabled plaintext auth): rip=190.210.136.21, lip=113.212.99.193
|
|
||||||
|
|
||||||
and then ^%(__prefix_line)s would match "Dec 12 11:19:11 dunnart dovecot:
|
|
||||||
". Note it matches the trailing space(s) as well.
|
|
||||||
|
|
||||||
Substitutions (AKA string interpolations):
|
|
||||||
|
|
||||||
We have used string interpolations in above examples. They are useful for
|
|
||||||
making the regexes more readable, reuse generic patterns in multiple failregex
|
|
||||||
lines, and also to refer definition of regex parts to specific filters or even
|
|
||||||
to the user. General principle is that value of a _name variable replaces
|
|
||||||
occurrences of %(_name)s within the same section or anywhere in the config file
|
|
||||||
if defined in [DEFAULT] section.
|
|
||||||
|
|
||||||
Regular Expressions:
|
|
||||||
|
|
||||||
Regular expressions (failregex, ignoreregex) assume that the date/time has been
|
|
||||||
removed from the log line (this is just how fail2ban works internally ATM).
|
|
||||||
|
|
||||||
If the format is like '<date...> error 1.2.3.4 is evil' then you need to match
|
|
||||||
the < at the start so regex should be similar to '^<> <HOST> is evil$' using
|
|
||||||
<HOST> where the IP/domain name appears in the log line.
|
|
||||||
|
|
||||||
The following general rules apply to regular expressions:
|
|
||||||
|
|
||||||
* ensure regexes start with a ^ and are as restrictive as possible. E.g. do not
|
|
||||||
use .* if \d+ is sufficient;
|
|
||||||
* use functionality of Python regexes defined in the standard Python re library
|
|
||||||
http://docs.python.org/2/library/re.html;
|
|
||||||
* make regular expressions readable (as much as possible). E.g.
|
|
||||||
(?:...) represents a non-capturing regex but (...) is more readable, thus
|
|
||||||
preferred.
|
|
||||||
|
|
||||||
If you have only a basic knowledge of regular repressions we advise to read
|
|
||||||
http://docs.python.org/2/library/re.html first. It doesn't take long and would
|
|
||||||
remind you e.g. which characters you need to escape and which you don't.
|
|
||||||
|
|
||||||
Developing/testing a regex:
|
|
||||||
|
|
||||||
You can develop a regex in a file or using command line depending on your
|
|
||||||
preference. You can also use samples you have already created in the test cases
|
|
||||||
or test them one at a time.
|
|
||||||
|
|
||||||
The general tool for testing Fail2Ban regexes is fail2ban-regex. To see how to
|
|
||||||
use it run:
|
|
||||||
|
|
||||||
./fail2ban-regex --help
|
|
||||||
|
|
||||||
Take note of -l heavydebug / -l debug and -v as they might be very useful.
|
|
||||||
|
|
||||||
TIP: Take a look at the source code of the application you are developing
|
|
||||||
failregex for. You may see optional or extra log messages, or parts there
|
|
||||||
of, that need to form part of your regex. It may also reveal how some
|
|
||||||
parts are constrained and different formats depending on configuration or
|
|
||||||
less common usages.
|
|
||||||
|
|
||||||
TIP: For looking through source code - http://sourcecodebrowser.com/ . It has
|
|
||||||
call graphs and can browse different versions.
|
|
||||||
|
|
||||||
TIP: Some applications log spaces at the end. If you are not sure add \s*$ as
|
|
||||||
the end part of the regex.
|
|
||||||
|
|
||||||
If your regex is not matching, http://www.debuggex.com/?flavor=python can help
|
|
||||||
to tune it. fail2ban-regex -D ... will present Debuggex URLs for the regexs
|
|
||||||
and sample log files that you pass into it.
|
|
||||||
|
|
||||||
In general use when using regex debuggers for generating fail2ban filters:
|
|
||||||
* use regex from the ./fail2ban-regex output (to ensure all substitutions are
|
|
||||||
done)
|
|
||||||
* replace <HOST> with (?&.ipv4)
|
|
||||||
* make sure that regex type set to Python
|
|
||||||
* for the test data put your log output with the date/time removed
|
|
||||||
|
|
||||||
When you have fixed the regex put it back into your filter file.
|
|
||||||
|
|
||||||
Please spread the good word about Debuggex - Serge Toarca is kindly continuing
|
|
||||||
its free availability to Open Source developers.
|
|
||||||
|
|
||||||
Finishing up:
|
|
||||||
|
|
||||||
If you've added a new filter, add a new entry in config/jail.conf. The theory
|
|
||||||
here is that a user will create a jail.local with [filtername]\nenable=true to
|
|
||||||
enable your jail.
|
|
||||||
|
|
||||||
So more specifically in the [filter] section in jail.conf:
|
|
||||||
* ensure that you have "enabled = false" (users will enable as needed);
|
|
||||||
* use "filter =" set to your filter name;
|
|
||||||
* use a typical action to disable ports associated with the application;
|
|
||||||
* set "logpath" to the usual location of application log file;
|
|
||||||
* if the default findtime or bantime isn't appropriate to the filter, specify
|
|
||||||
more appropriate choices (possibly with a brief comment line).
|
|
||||||
|
|
||||||
Submit github pull request (See "Pull Requests" above) for
|
|
||||||
github.com/fail2ban/fail2ban containing your great work.
|
|
||||||
|
|
||||||
Filter Security
|
|
||||||
---------------
|
|
||||||
|
|
||||||
Poor filter regular expressions are susceptible to DoS attacks.
|
|
||||||
|
|
||||||
When a remote user has the ability to introduce text that would match filter's
|
|
||||||
failregex, while matching inserted text to the <HOST> part, they have the
|
|
||||||
ability to deny any host they choose.
|
|
||||||
|
|
||||||
So the <HOST> part must be anchored on text generated by the application, and
|
|
||||||
not the user, to an extent sufficient to prevent user inserting the entire text
|
|
||||||
matching this or any other failregex.
|
|
||||||
|
|
||||||
Ideally filter regex should anchor at the beginning and at the end of log line.
|
|
||||||
However as more applications log at the beginning than the end, anchoring the
|
|
||||||
beginning is more important. If the log file used by the application is shared
|
|
||||||
with other applications, like system logs, ensure the other application that use
|
|
||||||
that log file do not log user generated text at the beginning of the line, or,
|
|
||||||
if they do, ensure the regexes of the filter are sufficient to mitigate the risk
|
|
||||||
of insertion.
|
|
||||||
|
|
||||||
|
|
||||||
Examples of poor filters
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
1. Too restrictive
|
|
||||||
|
|
||||||
We find a log message:
|
|
||||||
|
|
||||||
Apr-07-13 07:08:36 Invalid command fial2ban from 1.2.3.4
|
|
||||||
|
|
||||||
We make a failregex
|
|
||||||
|
|
||||||
^Invalid command \S+ from <HOST>
|
|
||||||
|
|
||||||
Now think evil. The user does the command 'blah from 1.2.3.44'
|
|
||||||
|
|
||||||
The program diligently logs:
|
|
||||||
|
|
||||||
Apr-07-13 07:08:36 Invalid command blah from 1.2.3.44 from 1.2.3.4
|
|
||||||
|
|
||||||
And fail2ban matches 1.2.3.44 as the IP that it ban. A DoS attack was successful.
|
|
||||||
|
|
||||||
The fix here is that the command can be anything so .* is appropriate.
|
|
||||||
|
|
||||||
^Invalid command .* from <HOST>
|
|
||||||
|
|
||||||
Here the .* will match until the end of the string. Then realise it has more to
|
|
||||||
match, i.e. "from <HOST>" and go back until it find this. Then it will ban
|
|
||||||
1.2.3.4 correctly. Since the <HOST> is always at the end, end the regex with a $.
|
|
||||||
|
|
||||||
^Invalid command .* from <HOST>$
|
|
||||||
|
|
||||||
Note if we'd just had the expression:
|
|
||||||
|
|
||||||
^Invalid command \S+ from <HOST>$
|
|
||||||
|
|
||||||
Then provided the user put a space in their command they would have never been
|
|
||||||
banned.
|
|
||||||
|
|
||||||
2. Unanchored regex can match other user injected data
|
|
||||||
|
|
||||||
From the Apache vulnerability CVE-2013-2178
|
|
||||||
( original ref: https://vndh.net/note:fail2ban-089-denial-service ).
|
|
||||||
|
|
||||||
An example bad regex for Apache:
|
|
||||||
|
|
||||||
failregex = [[]client <HOST>[]] user .* not found
|
|
||||||
|
|
||||||
Since the user can do a get request on:
|
|
||||||
|
|
||||||
GET /[client%20192.168.0.1]%20user%20root%20not%20found HTTP/1.0
|
|
||||||
Host: remote.site
|
|
||||||
|
|
||||||
Now the log line will be:
|
|
||||||
|
|
||||||
[Sat Jun 01 02:17:42 2013] [error] [client 192.168.33.1] File does not exist: /srv/http/site/[client 192.168.0.1] user root not found
|
|
||||||
|
|
||||||
As this log line doesn't match other expressions hence it matches the above
|
|
||||||
regex and blocks 192.168.33.1 as a denial of service from the HTTP requester.
|
|
||||||
|
|
||||||
3. Over greedy pattern matching
|
|
||||||
|
|
||||||
From: https://github.com/fail2ban/fail2ban/pull/426
|
|
||||||
|
|
||||||
An example ssh log (simplified)
|
|
||||||
|
|
||||||
Sep 29 17:15:02 spaceman sshd[12946]: Failed password for user from 127.0.0.1 port 20000 ssh1: ruser remoteuser
|
|
||||||
|
|
||||||
As we assume username can include anything including spaces its prudent to put
|
|
||||||
.* here. The remote user can also exist as anything so lets not make assumptions again.
|
|
||||||
|
|
||||||
failregex = ^%(__prefix_line)sFailed \S+ for .* from <HOST>( port \d*)?( ssh\d+)?(: ruser .*)?$
|
|
||||||
|
|
||||||
So this works. The problem is if the .* after remote user is injected by the
|
|
||||||
user to be 'from 1.2.3.4'. The resultant log line is.
|
|
||||||
|
|
||||||
Sep 29 17:15:02 spaceman sshd[12946]: Failed password for user from 127.0.0.1 port 20000 ssh1: ruser from 1.2.3.4
|
|
||||||
|
|
||||||
Testing with:
|
|
||||||
|
|
||||||
fail2ban-regex -v 'Sep 29 17:15:02 Failed password for user from 127.0.0.1 port 20000 ssh1: ruser from 1.2.3.4' '^ Failed \S+ for .* from <HOST>( port \d*)?( ssh\d+)?(: ruser .*)?$'
|
|
||||||
|
|
||||||
TIP: I've removed the bit that matches __prefix_line from the regex and log.
|
|
||||||
|
|
||||||
Shows:
|
|
||||||
|
|
||||||
1) [1] ^ Failed \S+ for .* from <HOST>( port \d*)?( ssh\d+)?(: ruser .*)?$
|
|
||||||
1.2.3.4 Sun Sep 29 17:15:02 2013
|
|
||||||
|
|
||||||
It should of matched 127.0.0.1. So the first greedy part of the greedy regex
|
|
||||||
matched until the end of the string. The was no "from <HOST>" so the regex
|
|
||||||
engine worked backwards from the end of the string until this was matched.
|
|
||||||
|
|
||||||
The result was that 1.2.3.4 was matched, injected by the user, and the wrong IP
|
|
||||||
was banned.
|
|
||||||
|
|
||||||
The solution here is to make the first .* non-greedy with .*?. Here it matches
|
|
||||||
as little as required and the fail2ban-regex tool shows the output:
|
|
||||||
|
|
||||||
fail2ban-regex -v 'Sep 29 17:15:02 Failed password for user from 127.0.0.1 port 20000 ssh1: ruser from 1.2.3.4' '^ Failed \S+ for .*? from <HOST>( port \d*)?( ssh\d+)?(: ruser .*)?$'
|
|
||||||
|
|
||||||
1) [1] ^ Failed \S+ for .*? from <HOST>( port \d*)?( ssh\d+)?(: ruser .*)?$
|
|
||||||
127.0.0.1 Sun Sep 29 17:15:02 2013
|
|
||||||
|
|
||||||
So the general case here is a log line that contains:
|
|
||||||
|
|
||||||
(fixed_data_1)<HOST>(fixed_data_2)(user_injectable_data)
|
|
||||||
|
|
||||||
Where the regex that matches fixed_data_1 is gready and matches the entire
|
|
||||||
string, before moving backwards and user_injectable_data can match the entire
|
|
||||||
string.
|
|
||||||
|
|
||||||
Another case:
|
|
||||||
|
|
||||||
ref: https://www.debuggex.com/r/CtAbeKMa2sDBEfA2/0
|
|
||||||
|
|
||||||
A webserver logs the following without URL escaping:
|
|
||||||
|
|
||||||
[error] 2865#0: *66647 user "xyz" was not found in "/file", client: 1.2.3.1, server: www.host.com, request: "GET ", client: 3.2.1.1, server: fake.com, request: "GET exploited HTTP/3.3", host: "injected.host", host: "www.myhost.com"
|
|
||||||
|
|
||||||
regex:
|
|
||||||
|
|
||||||
failregex = ^ \[error\] \d+#\d+: \*\d+ user "\S+":? (?:password mismatch|was not found in ".*"), client: <HOST>, server: \S+, request: "\S+ .+ HTTP/\d+\.\d+", host: "\S+"
|
|
||||||
|
|
||||||
The .* matches to the end of the string. Finds that it can't continue to match
|
|
||||||
", client ... so it moves from the back and find that the user injected web URL:
|
|
||||||
|
|
||||||
", client: 3.2.1.1, server: fake.com, request: "GET exploited HTTP/3.3", host: "injected.host
|
|
||||||
|
|
||||||
In this case there is a fixed host: "www.myhost.com" at the end so the solution
|
|
||||||
is to anchor the regex at the end with a $.
|
|
||||||
|
|
||||||
If this wasn't the case then first .* needed to be made so it didn't capture
|
|
||||||
beyond <HOST>.
|
|
||||||
|
|
||||||
4. Application generates two identical log messages with different meanings
|
|
||||||
|
|
||||||
If the application generates the following two messages under different
|
|
||||||
circumstances:
|
|
||||||
|
|
||||||
client <IP>: authentication failed
|
|
||||||
client <USER>: authentication failed
|
|
||||||
|
|
||||||
|
|
||||||
Then it's obvious that a regex of "^client <HOST>: authentication
|
|
||||||
failed$" will still cause problems if the user can trigger the second
|
|
||||||
log message with a <USER> of 123.1.1.1.
|
|
||||||
|
|
||||||
Here there's nothing to do except request/change the application so it logs
|
|
||||||
messages differently.
|
|
||||||
|
|
||||||
|
|
||||||
Code Testing
|
Code Testing
|
||||||
============
|
============
|
||||||
|
|
|
@ -0,0 +1,469 @@
|
||||||
|
__ _ _ ___ _
|
||||||
|
/ _|__ _(_) |_ ) |__ __ _ _ _
|
||||||
|
| _/ _` | | |/ /| '_ \/ _` | ' \
|
||||||
|
|_| \__,_|_|_/___|_.__/\__,_|_||_|
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
Developing Filters
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
Filters
|
||||||
|
=======
|
||||||
|
|
||||||
|
Filters are tricky. They need to:
|
||||||
|
* work with a variety of the versions of the software that generates the logs;
|
||||||
|
* work with the range of logging configuration options available in the
|
||||||
|
software;
|
||||||
|
* work with multiple operating systems;
|
||||||
|
* not make assumptions about the log format in excess of the software
|
||||||
|
(e.g. do not assume a username doesn't contain spaces and use \S+ unless
|
||||||
|
you've checked the source code);
|
||||||
|
* account for how future versions of the software will log messages
|
||||||
|
(e.g. guess what would happen to the log message if different authentication
|
||||||
|
types are added);
|
||||||
|
* not be susceptible to DoS vulnerabilities (see Filter Security below); and
|
||||||
|
* match intended log lines only.
|
||||||
|
|
||||||
|
Please follow the steps from Filter Test Cases to Developing Filter Regular
|
||||||
|
Expressions and submit a GitHub pull request (PR) afterwards. If you get stuck,
|
||||||
|
you can push your unfinished changes and still submit a PR -- describe
|
||||||
|
what you have done, what is the hurdle, and we'll attempt to help (PR
|
||||||
|
will be automagically updated with future commits you would push to
|
||||||
|
complete it).
|
||||||
|
|
||||||
|
Filter test cases
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
|
||||||
|
Start by finding the log messages that the application generates related to
|
||||||
|
some form of authentication failure. If you are adding to an existing filter
|
||||||
|
think about whether the log messages are of a similar importance and purpose
|
||||||
|
to the existing filter. If you were a user of Fail2Ban, and did a package
|
||||||
|
update of Fail2Ban that started matching new log messages, would anything
|
||||||
|
unexpected happen? Would the bantime/findtime for the jail be appropriate for
|
||||||
|
the new log messages? If it doesn't, perhaps it needs to be in a separate
|
||||||
|
filter definition, for example like exim filter aims at authentication failures
|
||||||
|
and exim-spam at log messages related to spam.
|
||||||
|
|
||||||
|
Even if it is a new filter you may consider separating the log messages into
|
||||||
|
different filters based on purpose.
|
||||||
|
|
||||||
|
Cause:
|
||||||
|
|
||||||
|
Are some of the log lines a result of the same action? For example, is a PAM
|
||||||
|
failure log message, followed by an application specific failure message the
|
||||||
|
result of the same user/script action? If you add regular expressions for
|
||||||
|
both you would end up with two failures for a single action.
|
||||||
|
Therefore, select the most appropriate log message and document the other log
|
||||||
|
message) with a test case not to match it and a description as to why you chose
|
||||||
|
one over another.
|
||||||
|
|
||||||
|
With the selected log lines consider what action has caused those log
|
||||||
|
messages and whether they could have been generated by accident? Could
|
||||||
|
the log message be occurring due to the first step towards the application
|
||||||
|
asking for authentication? Could the log messages occur often? If some of
|
||||||
|
these are true make a note of this in the jail.conf example that you provide.
|
||||||
|
|
||||||
|
Samples:
|
||||||
|
|
||||||
|
It is important to include log file samples so any future change in the regular
|
||||||
|
expression will still work with the log lines you have identified.
|
||||||
|
|
||||||
|
The sample log messages are provided in a file under testcases/files/logs/
|
||||||
|
named identically as the corresponding filter (but without .conf extension).
|
||||||
|
Each log line should be preceded by a line with failJSON metadata (so the logs
|
||||||
|
lines are tested in the test suite) directly above the log line. If there is
|
||||||
|
any specific information about the log message, such as version or an
|
||||||
|
application configuration option that is needed for the message to occur,
|
||||||
|
include this in a comment (line beginning with #) above the failJSON metadata.
|
||||||
|
|
||||||
|
Log samples should include only one, definitely not more than 3, examples of
|
||||||
|
log messages of the same form. If log messages are different in different
|
||||||
|
versions of the application log messages that show this are encouraged.
|
||||||
|
|
||||||
|
Also attempt to inject an IP into the application (e.g. by specifying
|
||||||
|
it as a username) so that Fail2Ban possibly detects the IP
|
||||||
|
from user input rather than the true origin. See the Filter Security section
|
||||||
|
and the top example in testcases/files/logs/apache-auth as to how to do this.
|
||||||
|
One you have discovered that this is possible, correct the regex so it doesn't
|
||||||
|
match and provide this as a test case with "match": false (see failJSON below).
|
||||||
|
|
||||||
|
If the mechanism to create the log message isn't obvious provide a
|
||||||
|
configuration and/or sample scripts testcases/files/config/{filtername} and
|
||||||
|
reference these in the comments above the log line.
|
||||||
|
|
||||||
|
FailJSON metadata:
|
||||||
|
|
||||||
|
A failJSON metadata is a comment immediately above the log message. It will
|
||||||
|
look like:
|
||||||
|
|
||||||
|
# failJSON: { "time": "2013-06-10T10:10:59", "match": true , "host": "93.184.216.119" }
|
||||||
|
|
||||||
|
Time should match the time of the log message. It is in a specific format of
|
||||||
|
Year-Month-Day'T'Hour:minute:Second. If your log message does not include a
|
||||||
|
year, like the example below, the year should be listed as 2005, if before Sun
|
||||||
|
Aug 14 10am UTC, and 2004 if afterwards. Here is an example failJSON
|
||||||
|
line preceding a sample log line:
|
||||||
|
|
||||||
|
# failJSON: { "time": "2005-03-24T15:25:51", "match": true , "host": "198.51.100.87" }
|
||||||
|
Mar 24 15:25:51 buffalo1 dropbear[4092]: bad password attempt for 'root' from 198.51.100.87:5543
|
||||||
|
|
||||||
|
The "host" in failJSON should contain the IP or domain that should be blocked.
|
||||||
|
|
||||||
|
For long lines that you do not want to be matched (e.g. from log injection
|
||||||
|
attacks) and any log lines to be excluded (see "Cause" section above), set
|
||||||
|
"match": false in the failJSON and describe the reason in the comment above.
|
||||||
|
|
||||||
|
After developing regexes, the following command will test all failJSON metadata
|
||||||
|
against the log lines in all sample log files
|
||||||
|
|
||||||
|
./fail2ban-testcases testSampleRegex
|
||||||
|
|
||||||
|
Developing Filter Regular Expressions
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
Date/Time:
|
||||||
|
|
||||||
|
At the moment, Fail2Ban depends on log lines to have time stamps. That is why
|
||||||
|
before starting to develop failregex, check if your log line format known to
|
||||||
|
Fail2Ban. Copy the time component from the log line and append an IP address to
|
||||||
|
test with following command:
|
||||||
|
|
||||||
|
./fail2ban-regex "2013-09-19 02:46:12 1.2.3.4" "<HOST>"
|
||||||
|
|
||||||
|
Output of such command should contain something like:
|
||||||
|
|
||||||
|
Date template hits:
|
||||||
|
|- [# of hits] date format
|
||||||
|
| [1] Year-Month-Day Hour:Minute:Second
|
||||||
|
|
||||||
|
Ensure that the template description matches time/date elements in your log line
|
||||||
|
time stamp. If there is no matched format then date template needs to be added
|
||||||
|
to server/datedetector.py. Ensure that a new template is added in the order
|
||||||
|
that more specific matches occur first and that there is no confusion between a
|
||||||
|
Day and a Month.
|
||||||
|
|
||||||
|
Filter file:
|
||||||
|
|
||||||
|
The filter is specified in a config/filter.d/{filtername}.conf file. Filter file
|
||||||
|
can have sections INCLUDES (optional) and Definition as follows:
|
||||||
|
|
||||||
|
[INCLUDES]
|
||||||
|
|
||||||
|
before = common.conf
|
||||||
|
|
||||||
|
after = filtername.local
|
||||||
|
|
||||||
|
[Definition]
|
||||||
|
|
||||||
|
failregex = ....
|
||||||
|
|
||||||
|
ignoreregex = ....
|
||||||
|
|
||||||
|
This is also documented in the man page jail.conf (section 5). Other definitions
|
||||||
|
can be added to make failregex's more readable and maintainable to be used
|
||||||
|
through string Interpolations (see http://docs.python.org/2.7/library/configparser.html)
|
||||||
|
|
||||||
|
|
||||||
|
General rules:
|
||||||
|
|
||||||
|
Use "before" if you need to include a common set of rules, like syslog or if
|
||||||
|
there is a common set of regexes for multiple filters.
|
||||||
|
|
||||||
|
Use "after" if you wish to allow the user to overwrite a set of customisations
|
||||||
|
of the current filter. This file doesn't need to exist.
|
||||||
|
|
||||||
|
Try to avoid using ignoreregex mainly for performance reasons. The case when you
|
||||||
|
would use it is if in trying to avoid using it, you end up with an unreadable
|
||||||
|
failregex.
|
||||||
|
|
||||||
|
Syslog:
|
||||||
|
|
||||||
|
If your application logs to syslog you can take advantage of log line prefix
|
||||||
|
definitions present in common.conf. So as a base use:
|
||||||
|
|
||||||
|
[INCLUDES]
|
||||||
|
|
||||||
|
before = common.conf
|
||||||
|
|
||||||
|
[Definition]
|
||||||
|
|
||||||
|
_daemon = app
|
||||||
|
|
||||||
|
failregex = ^%(__prefix_line)s
|
||||||
|
|
||||||
|
In this example common.conf defines __prefix_line which also contains the
|
||||||
|
_daemon name (in syslog terms the service) you have just specified. _daemon
|
||||||
|
can also be a regex.
|
||||||
|
|
||||||
|
For example, to capture following line _daemon should be set to "dovecot"
|
||||||
|
|
||||||
|
Dec 12 11:19:11 dunnart dovecot: pop3-login: Aborted login (tried to use disabled plaintext auth): rip=190.210.136.21, lip=113.212.99.193
|
||||||
|
|
||||||
|
and then ^%(__prefix_line)s would match "Dec 12 11:19:11 dunnart dovecot:
|
||||||
|
". Note it matches the trailing space(s) as well.
|
||||||
|
|
||||||
|
Substitutions (AKA string interpolations):
|
||||||
|
|
||||||
|
We have used string interpolations in above examples. They are useful for
|
||||||
|
making the regexes more readable, reuse generic patterns in multiple failregex
|
||||||
|
lines, and also to refer definition of regex parts to specific filters or even
|
||||||
|
to the user. General principle is that value of a _name variable replaces
|
||||||
|
occurrences of %(_name)s within the same section or anywhere in the config file
|
||||||
|
if defined in [DEFAULT] section.
|
||||||
|
|
||||||
|
Regular Expressions:
|
||||||
|
|
||||||
|
Regular expressions (failregex, ignoreregex) assume that the date/time has been
|
||||||
|
removed from the log line (this is just how fail2ban works internally ATM).
|
||||||
|
|
||||||
|
If the format is like '<date...> error 1.2.3.4 is evil' then you need to match
|
||||||
|
the < at the start so regex should be similar to '^<> <HOST> is evil$' using
|
||||||
|
<HOST> where the IP/domain name appears in the log line.
|
||||||
|
|
||||||
|
The following general rules apply to regular expressions:
|
||||||
|
|
||||||
|
* ensure regexes start with a ^ and are as restrictive as possible. E.g. do not
|
||||||
|
use .* if \d+ is sufficient;
|
||||||
|
* use functionality of Python regexes defined in the standard Python re library
|
||||||
|
http://docs.python.org/2/library/re.html;
|
||||||
|
* make regular expressions readable (as much as possible). E.g.
|
||||||
|
(?:...) represents a non-capturing regex but (...) is more readable, thus
|
||||||
|
preferred.
|
||||||
|
|
||||||
|
If you have only a basic knowledge of regular repressions we advise to read
|
||||||
|
http://docs.python.org/2/library/re.html first. It doesn't take long and would
|
||||||
|
remind you e.g. which characters you need to escape and which you don't.
|
||||||
|
|
||||||
|
Developing/testing a regex:
|
||||||
|
|
||||||
|
You can develop a regex in a file or using command line depending on your
|
||||||
|
preference. You can also use samples you have already created in the test cases
|
||||||
|
or test them one at a time.
|
||||||
|
|
||||||
|
The general tool for testing Fail2Ban regexes is fail2ban-regex. To see how to
|
||||||
|
use it run:
|
||||||
|
|
||||||
|
./fail2ban-regex --help
|
||||||
|
|
||||||
|
Take note of -l heavydebug / -l debug and -v as they might be very useful.
|
||||||
|
|
||||||
|
TIP: Take a look at the source code of the application you are developing
|
||||||
|
failregex for. You may see optional or extra log messages, or parts there
|
||||||
|
of, that need to form part of your regex. It may also reveal how some
|
||||||
|
parts are constrained and different formats depending on configuration or
|
||||||
|
less common usages.
|
||||||
|
|
||||||
|
TIP: For looking through source code - http://sourcecodebrowser.com/ . It has
|
||||||
|
call graphs and can browse different versions.
|
||||||
|
|
||||||
|
TIP: Some applications log spaces at the end. If you are not sure add \s*$ as
|
||||||
|
the end part of the regex.
|
||||||
|
|
||||||
|
If your regex is not matching, http://www.debuggex.com/?flavor=python can help
|
||||||
|
to tune it. fail2ban-regex -D ... will present Debuggex URLs for the regexs
|
||||||
|
and sample log files that you pass into it.
|
||||||
|
|
||||||
|
In general use when using regex debuggers for generating fail2ban filters:
|
||||||
|
* use regex from the ./fail2ban-regex output (to ensure all substitutions are
|
||||||
|
done)
|
||||||
|
* replace <HOST> with (?&.ipv4)
|
||||||
|
* make sure that regex type set to Python
|
||||||
|
* for the test data put your log output with the date/time removed
|
||||||
|
|
||||||
|
When you have fixed the regex put it back into your filter file.
|
||||||
|
|
||||||
|
Please spread the good word about Debuggex - Serge Toarca is kindly continuing
|
||||||
|
its free availability to Open Source developers.
|
||||||
|
|
||||||
|
Finishing up:
|
||||||
|
|
||||||
|
If you've added a new filter, add a new entry in config/jail.conf. The theory
|
||||||
|
here is that a user will create a jail.local with [filtername]\nenable=true to
|
||||||
|
enable your jail.
|
||||||
|
|
||||||
|
So more specifically in the [filter] section in jail.conf:
|
||||||
|
* ensure that you have "enabled = false" (users will enable as needed);
|
||||||
|
* use "filter =" set to your filter name;
|
||||||
|
* use a typical action to disable ports associated with the application;
|
||||||
|
* set "logpath" to the usual location of application log file;
|
||||||
|
* if the default findtime or bantime isn't appropriate to the filter, specify
|
||||||
|
more appropriate choices (possibly with a brief comment line).
|
||||||
|
|
||||||
|
Submit github pull request (See "Pull Requests" above) for
|
||||||
|
github.com/fail2ban/fail2ban containing your great work.
|
||||||
|
|
||||||
|
Filter Security
|
||||||
|
---------------
|
||||||
|
|
||||||
|
Poor filter regular expressions are susceptible to DoS attacks.
|
||||||
|
|
||||||
|
When a remote user has the ability to introduce text that would match filter's
|
||||||
|
failregex, while matching inserted text to the <HOST> part, they have the
|
||||||
|
ability to deny any host they choose.
|
||||||
|
|
||||||
|
So the <HOST> part must be anchored on text generated by the application, and
|
||||||
|
not the user, to an extent sufficient to prevent user inserting the entire text
|
||||||
|
matching this or any other failregex.
|
||||||
|
|
||||||
|
Ideally filter regex should anchor at the beginning and at the end of log line.
|
||||||
|
However as more applications log at the beginning than the end, anchoring the
|
||||||
|
beginning is more important. If the log file used by the application is shared
|
||||||
|
with other applications, like system logs, ensure the other application that use
|
||||||
|
that log file do not log user generated text at the beginning of the line, or,
|
||||||
|
if they do, ensure the regexes of the filter are sufficient to mitigate the risk
|
||||||
|
of insertion.
|
||||||
|
|
||||||
|
|
||||||
|
Examples of poor filters
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
1. Too restrictive
|
||||||
|
|
||||||
|
We find a log message:
|
||||||
|
|
||||||
|
Apr-07-13 07:08:36 Invalid command fial2ban from 1.2.3.4
|
||||||
|
|
||||||
|
We make a failregex
|
||||||
|
|
||||||
|
^Invalid command \S+ from <HOST>
|
||||||
|
|
||||||
|
Now think evil. The user does the command 'blah from 1.2.3.44'
|
||||||
|
|
||||||
|
The program diligently logs:
|
||||||
|
|
||||||
|
Apr-07-13 07:08:36 Invalid command blah from 1.2.3.44 from 1.2.3.4
|
||||||
|
|
||||||
|
And fail2ban matches 1.2.3.44 as the IP that it ban. A DoS attack was successful.
|
||||||
|
|
||||||
|
The fix here is that the command can be anything so .* is appropriate.
|
||||||
|
|
||||||
|
^Invalid command .* from <HOST>
|
||||||
|
|
||||||
|
Here the .* will match until the end of the string. Then realise it has more to
|
||||||
|
match, i.e. "from <HOST>" and go back until it find this. Then it will ban
|
||||||
|
1.2.3.4 correctly. Since the <HOST> is always at the end, end the regex with a $.
|
||||||
|
|
||||||
|
^Invalid command .* from <HOST>$
|
||||||
|
|
||||||
|
Note if we'd just had the expression:
|
||||||
|
|
||||||
|
^Invalid command \S+ from <HOST>$
|
||||||
|
|
||||||
|
Then provided the user put a space in their command they would have never been
|
||||||
|
banned.
|
||||||
|
|
||||||
|
2. Unanchored regex can match other user injected data
|
||||||
|
|
||||||
|
From the Apache vulnerability CVE-2013-2178
|
||||||
|
( original ref: https://vndh.net/note:fail2ban-089-denial-service ).
|
||||||
|
|
||||||
|
An example bad regex for Apache:
|
||||||
|
|
||||||
|
failregex = [[]client <HOST>[]] user .* not found
|
||||||
|
|
||||||
|
Since the user can do a get request on:
|
||||||
|
|
||||||
|
GET /[client%20192.168.0.1]%20user%20root%20not%20found HTTP/1.0
|
||||||
|
Host: remote.site
|
||||||
|
|
||||||
|
Now the log line will be:
|
||||||
|
|
||||||
|
[Sat Jun 01 02:17:42 2013] [error] [client 192.168.33.1] File does not exist: /srv/http/site/[client 192.168.0.1] user root not found
|
||||||
|
|
||||||
|
As this log line doesn't match other expressions hence it matches the above
|
||||||
|
regex and blocks 192.168.33.1 as a denial of service from the HTTP requester.
|
||||||
|
|
||||||
|
3. Over greedy pattern matching
|
||||||
|
|
||||||
|
From: https://github.com/fail2ban/fail2ban/pull/426
|
||||||
|
|
||||||
|
An example ssh log (simplified)
|
||||||
|
|
||||||
|
Sep 29 17:15:02 spaceman sshd[12946]: Failed password for user from 127.0.0.1 port 20000 ssh1: ruser remoteuser
|
||||||
|
|
||||||
|
As we assume username can include anything including spaces its prudent to put
|
||||||
|
.* here. The remote user can also exist as anything so lets not make assumptions again.
|
||||||
|
|
||||||
|
failregex = ^%(__prefix_line)sFailed \S+ for .* from <HOST>( port \d*)?( ssh\d+)?(: ruser .*)?$
|
||||||
|
|
||||||
|
So this works. The problem is if the .* after remote user is injected by the
|
||||||
|
user to be 'from 1.2.3.4'. The resultant log line is.
|
||||||
|
|
||||||
|
Sep 29 17:15:02 spaceman sshd[12946]: Failed password for user from 127.0.0.1 port 20000 ssh1: ruser from 1.2.3.4
|
||||||
|
|
||||||
|
Testing with:
|
||||||
|
|
||||||
|
fail2ban-regex -v 'Sep 29 17:15:02 Failed password for user from 127.0.0.1 port 20000 ssh1: ruser from 1.2.3.4' '^ Failed \S+ for .* from <HOST>( port \d*)?( ssh\d+)?(: ruser .*)?$'
|
||||||
|
|
||||||
|
TIP: I've removed the bit that matches __prefix_line from the regex and log.
|
||||||
|
|
||||||
|
Shows:
|
||||||
|
|
||||||
|
1) [1] ^ Failed \S+ for .* from <HOST>( port \d*)?( ssh\d+)?(: ruser .*)?$
|
||||||
|
1.2.3.4 Sun Sep 29 17:15:02 2013
|
||||||
|
|
||||||
|
It should of matched 127.0.0.1. So the first greedy part of the greedy regex
|
||||||
|
matched until the end of the string. The was no "from <HOST>" so the regex
|
||||||
|
engine worked backwards from the end of the string until this was matched.
|
||||||
|
|
||||||
|
The result was that 1.2.3.4 was matched, injected by the user, and the wrong IP
|
||||||
|
was banned.
|
||||||
|
|
||||||
|
The solution here is to make the first .* non-greedy with .*?. Here it matches
|
||||||
|
as little as required and the fail2ban-regex tool shows the output:
|
||||||
|
|
||||||
|
fail2ban-regex -v 'Sep 29 17:15:02 Failed password for user from 127.0.0.1 port 20000 ssh1: ruser from 1.2.3.4' '^ Failed \S+ for .*? from <HOST>( port \d*)?( ssh\d+)?(: ruser .*)?$'
|
||||||
|
|
||||||
|
1) [1] ^ Failed \S+ for .*? from <HOST>( port \d*)?( ssh\d+)?(: ruser .*)?$
|
||||||
|
127.0.0.1 Sun Sep 29 17:15:02 2013
|
||||||
|
|
||||||
|
So the general case here is a log line that contains:
|
||||||
|
|
||||||
|
(fixed_data_1)<HOST>(fixed_data_2)(user_injectable_data)
|
||||||
|
|
||||||
|
Where the regex that matches fixed_data_1 is gready and matches the entire
|
||||||
|
string, before moving backwards and user_injectable_data can match the entire
|
||||||
|
string.
|
||||||
|
|
||||||
|
Another case:
|
||||||
|
|
||||||
|
ref: https://www.debuggex.com/r/CtAbeKMa2sDBEfA2/0
|
||||||
|
|
||||||
|
A webserver logs the following without URL escaping:
|
||||||
|
|
||||||
|
[error] 2865#0: *66647 user "xyz" was not found in "/file", client: 1.2.3.1, server: www.host.com, request: "GET ", client: 3.2.1.1, server: fake.com, request: "GET exploited HTTP/3.3", host: "injected.host", host: "www.myhost.com"
|
||||||
|
|
||||||
|
regex:
|
||||||
|
|
||||||
|
failregex = ^ \[error\] \d+#\d+: \*\d+ user "\S+":? (?:password mismatch|was not found in ".*"), client: <HOST>, server: \S+, request: "\S+ .+ HTTP/\d+\.\d+", host: "\S+"
|
||||||
|
|
||||||
|
The .* matches to the end of the string. Finds that it can't continue to match
|
||||||
|
", client ... so it moves from the back and find that the user injected web URL:
|
||||||
|
|
||||||
|
", client: 3.2.1.1, server: fake.com, request: "GET exploited HTTP/3.3", host: "injected.host
|
||||||
|
|
||||||
|
In this case there is a fixed host: "www.myhost.com" at the end so the solution
|
||||||
|
is to anchor the regex at the end with a $.
|
||||||
|
|
||||||
|
If this wasn't the case then first .* needed to be made so it didn't capture
|
||||||
|
beyond <HOST>.
|
||||||
|
|
||||||
|
4. Application generates two identical log messages with different meanings
|
||||||
|
|
||||||
|
If the application generates the following two messages under different
|
||||||
|
circumstances:
|
||||||
|
|
||||||
|
client <IP>: authentication failed
|
||||||
|
client <USER>: authentication failed
|
||||||
|
|
||||||
|
|
||||||
|
Then it's obvious that a regex of "^client <HOST>: authentication
|
||||||
|
failed$" will still cause problems if the user can trigger the second
|
||||||
|
log message with a <USER> of 123.1.1.1.
|
||||||
|
|
||||||
|
Here there's nothing to do except request/change the application so it logs
|
||||||
|
messages differently.
|
||||||
|
|
||||||
|
|
23
MANIFEST
23
MANIFEST
|
@ -5,6 +5,7 @@ TODO
|
||||||
THANKS
|
THANKS
|
||||||
COPYING
|
COPYING
|
||||||
DEVELOP
|
DEVELOP
|
||||||
|
FILTERS
|
||||||
fail2ban-2to3
|
fail2ban-2to3
|
||||||
fail2ban-testcases-all
|
fail2ban-testcases-all
|
||||||
fail2ban-testcases-all-python3
|
fail2ban-testcases-all-python3
|
||||||
|
@ -25,6 +26,7 @@ fail2ban/client/__init__.py
|
||||||
fail2ban/client/configurator.py
|
fail2ban/client/configurator.py
|
||||||
fail2ban/client/csocket.py
|
fail2ban/client/csocket.py
|
||||||
fail2ban/server/asyncserver.py
|
fail2ban/server/asyncserver.py
|
||||||
|
fail2ban/server/database.py
|
||||||
fail2ban/server/filter.py
|
fail2ban/server/filter.py
|
||||||
fail2ban/server/filterpyinotify.py
|
fail2ban/server/filterpyinotify.py
|
||||||
fail2ban/server/filtergamin.py
|
fail2ban/server/filtergamin.py
|
||||||
|
@ -62,6 +64,10 @@ fail2ban/tests/sockettestcase.py
|
||||||
fail2ban/tests/utils.py
|
fail2ban/tests/utils.py
|
||||||
fail2ban/tests/misctestcase.py
|
fail2ban/tests/misctestcase.py
|
||||||
fail2ban/tests/databasetestcase.py
|
fail2ban/tests/databasetestcase.py
|
||||||
|
fail2ban/tests/config/jail.conf
|
||||||
|
fail2ban/tests/config/fail2ban.conf
|
||||||
|
fail2ban/tests/config/filter.d/simple.conf
|
||||||
|
fail2ban/tests/config/action.d/brokenaction.conf
|
||||||
fail2ban/tests/files/config/apache-auth/digest/.htaccess
|
fail2ban/tests/files/config/apache-auth/digest/.htaccess
|
||||||
fail2ban/tests/files/config/apache-auth/digest/.htpasswd
|
fail2ban/tests/files/config/apache-auth/digest/.htpasswd
|
||||||
fail2ban/tests/files/config/apache-auth/digest_time/.htaccess
|
fail2ban/tests/files/config/apache-auth/digest_time/.htaccess
|
||||||
|
@ -155,6 +161,7 @@ setup.py
|
||||||
setup.cfg
|
setup.cfg
|
||||||
kill-server
|
kill-server
|
||||||
config/jail.conf
|
config/jail.conf
|
||||||
|
config/fail2ban.conf
|
||||||
config/filter.d/common.conf
|
config/filter.d/common.conf
|
||||||
config/filter.d/apache-auth.conf
|
config/filter.d/apache-auth.conf
|
||||||
config/filter.d/apache-badbots.conf
|
config/filter.d/apache-badbots.conf
|
||||||
|
@ -169,13 +176,17 @@ config/filter.d/exim.conf
|
||||||
config/filter.d/gssftpd.conf
|
config/filter.d/gssftpd.conf
|
||||||
config/filter.d/suhosin.conf
|
config/filter.d/suhosin.conf
|
||||||
config/filter.d/named-refused.conf
|
config/filter.d/named-refused.conf
|
||||||
|
config/filter.d/openwebmail.conf
|
||||||
|
config/filter.d/pam-generic.conf
|
||||||
|
config/filter.d/php-url-fopen.conf
|
||||||
|
config/filter.d/postfix-sasl.conf
|
||||||
|
config/filter.d/pam-generic.conf
|
||||||
|
config/filter.d/php-url-fopen.conf
|
||||||
|
config/filter.d/postfix-sasl.conf
|
||||||
config/filter.d/postfix.conf
|
config/filter.d/postfix.conf
|
||||||
config/filter.d/proftpd.conf
|
config/filter.d/proftpd.conf
|
||||||
config/filter.d/pure-ftpd.conf
|
config/filter.d/pure-ftpd.conf
|
||||||
config/filter.d/qmail.conf
|
config/filter.d/qmail.conf
|
||||||
config/filter.d/pam-generic.conf
|
|
||||||
config/filter.d/php-url-fopen.conf
|
|
||||||
config/filter.d/postfix-sasl.conf
|
|
||||||
config/filter.d/sieve.conf
|
config/filter.d/sieve.conf
|
||||||
config/filter.d/solid-pop3d.conf
|
config/filter.d/solid-pop3d.conf
|
||||||
config/filter.d/sshd.conf
|
config/filter.d/sshd.conf
|
||||||
|
@ -212,7 +223,8 @@ config/action.d/osx-ipfw.conf
|
||||||
config/action.d/sendmail-common.conf
|
config/action.d/sendmail-common.conf
|
||||||
config/action.d/bsd-ipfw.conf
|
config/action.d/bsd-ipfw.conf
|
||||||
config/action.d/dummy.conf
|
config/action.d/dummy.conf
|
||||||
config/action.d/firewall-cmd-direct-new.conf
|
config/action.d/firewallcmd-new.conf
|
||||||
|
config/action.d/firewallcmd-ipset.conf
|
||||||
config/action.d/iptables-ipset-proto6-allports.conf
|
config/action.d/iptables-ipset-proto6-allports.conf
|
||||||
config/action.d/iptables-blocktype.conf
|
config/action.d/iptables-blocktype.conf
|
||||||
config/action.d/iptables-ipset-proto4.conf
|
config/action.d/iptables-ipset-proto4.conf
|
||||||
|
@ -241,7 +253,8 @@ config/action.d/sendmail-whois-ipmatches.conf
|
||||||
config/action.d/sendmail-whois.conf
|
config/action.d/sendmail-whois.conf
|
||||||
config/action.d/sendmail-whois-lines.conf
|
config/action.d/sendmail-whois-lines.conf
|
||||||
config/action.d/shorewall.conf
|
config/action.d/shorewall.conf
|
||||||
config/fail2ban.conf
|
config/action.d/xarf-login-attack.conf
|
||||||
|
config/action.d/ufw.conf
|
||||||
doc/run-rootless.txt
|
doc/run-rootless.txt
|
||||||
man/fail2ban-client.1
|
man/fail2ban-client.1
|
||||||
man/fail2ban.1
|
man/fail2ban.1
|
||||||
|
|
2
THANKS
2
THANKS
|
@ -35,9 +35,11 @@ ftoppi
|
||||||
François Boulogne
|
François Boulogne
|
||||||
Frédéric
|
Frédéric
|
||||||
Georgiy Mernov
|
Georgiy Mernov
|
||||||
|
Guilhem Lettron
|
||||||
Guillaume Delvit
|
Guillaume Delvit
|
||||||
Hanno 'Rince' Wagner
|
Hanno 'Rince' Wagner
|
||||||
Iain Lea
|
Iain Lea
|
||||||
|
Ivo Truxa
|
||||||
John Thoe
|
John Thoe
|
||||||
Jacques Lav!gnotte
|
Jacques Lav!gnotte
|
||||||
Ioan Indreias
|
Ioan Indreias
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
# Fail2Ban action file for firewall-cmd/ipset
|
||||||
|
#
|
||||||
|
# This requires:
|
||||||
|
# ipset (package: ipset)
|
||||||
|
# firewall-cmd (package: firewalld)
|
||||||
|
#
|
||||||
|
# This is for ipset protocol 6 (and hopefully later) (ipset v6.14).
|
||||||
|
# Use ipset -V to see the protocol and version.
|
||||||
|
#
|
||||||
|
# IPset was a feature introduced in the linux kernel 2.6.39 and 3.0.0 kernels.
|
||||||
|
#
|
||||||
|
# If you are running on an older kernel you make need to patch in external
|
||||||
|
# modules.
|
||||||
|
|
||||||
|
[INCLUDES]
|
||||||
|
|
||||||
|
before = iptables-blocktype.conf
|
||||||
|
|
||||||
|
[Definition]
|
||||||
|
|
||||||
|
actionstart = ipset create fail2ban-<name> hash:ip timeout <bantime>
|
||||||
|
firewall-cmd --direct --add-rule ipv4 filter <chain> 0 -p <protocol> -m multiport --dports <port> -m set --match-set fail2ban-<name> src -j <blocktype>
|
||||||
|
|
||||||
|
actionstop = firewall-cmd --direct --remove-rule ipv4 filter <chain> 0 -p <protocol> -m multiport --dports <port> -m set --match-set fail2ban-<name> src -j <blocktype>
|
||||||
|
ipset flush fail2ban-<name>
|
||||||
|
ipset destroy fail2ban-<name>
|
||||||
|
|
||||||
|
actioncheck = firewall-cmd --direct --get-chains ipv4 filter | grep -q '^fail2ban-<name>$'
|
||||||
|
|
||||||
|
actionban = ipset add fail2ban-<name> <ip> timeout <bantime> -exist
|
||||||
|
|
||||||
|
actionunban = ipset del fail2ban-<name> <ip> -exist
|
||||||
|
|
||||||
|
[Init]
|
||||||
|
|
||||||
|
# Default name of the chain
|
||||||
|
#
|
||||||
|
name = default
|
||||||
|
|
||||||
|
# Option: port
|
||||||
|
# Notes.: specifies port to monitor
|
||||||
|
# Values: [ NUM | STRING ]
|
||||||
|
#
|
||||||
|
port = ssh
|
||||||
|
|
||||||
|
# Option: protocol
|
||||||
|
# Notes.: internally used by config reader for interpolations.
|
||||||
|
# Values: [ tcp | udp | icmp | all ]
|
||||||
|
#
|
||||||
|
protocol = tcp
|
||||||
|
|
||||||
|
# Option: chain
|
||||||
|
# Notes specifies the iptables chain to which the fail2ban rules should be
|
||||||
|
# added
|
||||||
|
# Values: [ STRING ]
|
||||||
|
#
|
||||||
|
chain = INPUT_direct
|
||||||
|
|
||||||
|
# Option: bantime
|
||||||
|
# Notes: specifies the bantime in seconds (handled internally rather than by fail2ban)
|
||||||
|
# Values: [ NUM ] Default: 600
|
||||||
|
|
||||||
|
bantime = 600
|
||||||
|
|
||||||
|
|
||||||
|
# DEV NOTES:
|
||||||
|
#
|
||||||
|
# Author: Edgar Hoch and Daniel Black
|
||||||
|
# firewallcmd-new / iptables-ipset-proto6 combined for maximium goodness
|
|
@ -0,0 +1,40 @@
|
||||||
|
# Fail2Ban action configuration file for ufw
|
||||||
|
#
|
||||||
|
# You are required to run "ufw enable" before this will have an effect.
|
||||||
|
#
|
||||||
|
# The insert position should be approprate to block the required traffic.
|
||||||
|
# A number after an allow rule to the application won't be much use.
|
||||||
|
|
||||||
|
[Definition]
|
||||||
|
|
||||||
|
actionstart =
|
||||||
|
|
||||||
|
actionstop =
|
||||||
|
|
||||||
|
actioncheck =
|
||||||
|
|
||||||
|
actionban = [ -n "<application>" ] && app="app <application>" ; ufw insert <insertpos> <blocktype> from <ip> to <destination> $app
|
||||||
|
|
||||||
|
actionunban = [ -n "<application>" ] && app="app <application>" ; ufw delete <blocktype> from <ip> to <destination> $app
|
||||||
|
|
||||||
|
[Init]
|
||||||
|
# Option: insertpos
|
||||||
|
# Notes.: The postition number in the firewall list to insert the block rule
|
||||||
|
insertpos = 1
|
||||||
|
|
||||||
|
# Option: blocktype
|
||||||
|
# Notes.: reject or deny
|
||||||
|
blocktype = reject
|
||||||
|
|
||||||
|
# Option: destination
|
||||||
|
# Notes.: The destination address to block in the ufw rule
|
||||||
|
destination = any
|
||||||
|
|
||||||
|
# Option: application
|
||||||
|
# Notes.: application from sudo ufw app list
|
||||||
|
application =
|
||||||
|
|
||||||
|
# DEV NOTES:
|
||||||
|
#
|
||||||
|
# Author: Guilhem Lettron
|
||||||
|
# Enhancements: Daniel Black
|
|
@ -1,5 +1,6 @@
|
||||||
# Fail2Ban filter for exim the spam rejection messages
|
# Fail2Ban filter for exim the spam rejection messages
|
||||||
#
|
#
|
||||||
|
## For the SA: Action: silently tossed message... to be logged exim's SAdevnull option needs to be used.
|
||||||
|
|
||||||
[INCLUDES]
|
[INCLUDES]
|
||||||
|
|
||||||
|
@ -12,6 +13,7 @@ before = exim-common.conf
|
||||||
failregex = ^%(pid)s \S+ F=(<>|\S+@\S+) %(host_info)srejected by local_scan\(\): .{0,256}$
|
failregex = ^%(pid)s \S+ F=(<>|\S+@\S+) %(host_info)srejected by local_scan\(\): .{0,256}$
|
||||||
^%(pid)s %(host_info)sF=(<>|[^@]+@\S+) rejected RCPT [^@]+@\S+: .*dnsbl.*\s*$
|
^%(pid)s %(host_info)sF=(<>|[^@]+@\S+) rejected RCPT [^@]+@\S+: .*dnsbl.*\s*$
|
||||||
^%(pid)s \S+ %(host_info)sF=(<>|[^@]+@\S+) rejected after DATA: This message contains a virus \(\S+\)\.\s*$
|
^%(pid)s \S+ %(host_info)sF=(<>|[^@]+@\S+) rejected after DATA: This message contains a virus \(\S+\)\.\s*$
|
||||||
|
^%(pid)s \S+ SA: Action: silently tossed message: score=\d+\.\d+ required=\d+\.\d+ trigger=\d+\.\d+ \(scanned in \d+/\d+ secs \| Message-Id: \S+\)\. From \S+ \(host=(\S+ )?\[<HOST>\]\) for \S+$
|
||||||
|
|
||||||
ignoreregex =
|
ignoreregex =
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
# fail2ban filter configuration for horde
|
||||||
|
|
||||||
|
|
||||||
|
[Definition]
|
||||||
|
|
||||||
|
|
||||||
|
failregex = ^ HORDE \[error\] \[(horde|imp)\] FAILED LOGIN for \S+ \[<HOST>\](\(forwarded for \[\S+\]\))? to (Horde|{[^}]+}) \[(pid \d+ )?on line \d+ of \S+\]$
|
||||||
|
|
||||||
|
|
||||||
|
ignoreregex =
|
||||||
|
|
||||||
|
# DEV NOTES:
|
||||||
|
# https://github.com/horde/horde/blob/master/imp/lib/Auth.php#L132
|
||||||
|
# https://github.com/horde/horde/blob/master/horde/login.php
|
||||||
|
#
|
||||||
|
# Author: Daniel Black
|
|
@ -0,0 +1,15 @@
|
||||||
|
# Fail2Ban filter for Openwebmail
|
||||||
|
# banning hosts with authentication errors in /var/log/openwebmail.log
|
||||||
|
# OpenWebMail http://openwebmail.org
|
||||||
|
#
|
||||||
|
|
||||||
|
[Definition]
|
||||||
|
|
||||||
|
failregex = ^ - \[\d+\] \(<HOST>\) (?P<USER>\S+) - login error - (no such user - loginname=(?P=USER)|auth_unix.pl, ret -4, Password incorrect)$
|
||||||
|
^ - \[\d+\] \(<HOST>\) (?P<USER>\S+) - userinfo error - auth_unix.pl, ret -4, User (?P=USER) doesn't exist$
|
||||||
|
|
||||||
|
ignoreregex =
|
||||||
|
|
||||||
|
# DEV Notes:
|
||||||
|
#
|
||||||
|
# Author: Ivo Truxa (c) 2013 truXoft.com
|
|
@ -390,6 +390,11 @@ port = http,https
|
||||||
logpath = /var/log/roundcube/userlogins
|
logpath = /var/log/roundcube/userlogins
|
||||||
|
|
||||||
|
|
||||||
|
[openwebmail]
|
||||||
|
|
||||||
|
port = http,https
|
||||||
|
logpath = /var/log/openwebmail.log`
|
||||||
|
|
||||||
[sogo-auth]
|
[sogo-auth]
|
||||||
# Monitor SOGo groupware server
|
# Monitor SOGo groupware server
|
||||||
# without proxy this would be:
|
# without proxy this would be:
|
||||||
|
|
|
@ -76,7 +76,7 @@ class RequestHandler(asynchat.async_chat):
|
||||||
# Serializes the response.
|
# Serializes the response.
|
||||||
message = dumps(message, HIGHEST_PROTOCOL)
|
message = dumps(message, HIGHEST_PROTOCOL)
|
||||||
# Sends the response to the client.
|
# Sends the response to the client.
|
||||||
self.send(message + RequestHandler.END_STRING)
|
self.push(message + RequestHandler.END_STRING)
|
||||||
# Closes the channel.
|
# Closes the channel.
|
||||||
self.close_when_done()
|
self.close_when_done()
|
||||||
|
|
||||||
|
|
|
@ -32,10 +32,13 @@ from fail2ban.client.configurator import Configurator
|
||||||
from fail2ban.tests.utils import LogCaptureTestCase
|
from fail2ban.tests.utils import LogCaptureTestCase
|
||||||
|
|
||||||
TEST_FILES_DIR = os.path.join(os.path.dirname(__file__), "files")
|
TEST_FILES_DIR = os.path.join(os.path.dirname(__file__), "files")
|
||||||
if os.path.exists('config/fail2ban.conf'):
|
if os.path.exists(os.path.join('config','fail2ban.conf')):
|
||||||
CONFIG_DIR='config'
|
CONFIG_DIR='config'
|
||||||
else:
|
else:
|
||||||
CONFIG_DIR='/etc/fail2ban'
|
CONFIG_DIR=os.path.join('etc','fail2ban')
|
||||||
|
|
||||||
|
IMPERFECT_CONFIG = os.path.join('fail2ban', 'tests','config')
|
||||||
|
|
||||||
|
|
||||||
IMPERFECT_CONFIG = os.path.join('fail2ban', 'tests','config')
|
IMPERFECT_CONFIG = os.path.join('fail2ban', 'tests','config')
|
||||||
|
|
||||||
|
|
|
@ -14,4 +14,11 @@
|
||||||
2013-06-15 11:20:36 [2516] 1Unmew-0000ea-SE H=egeftech.static.otenet.gr [83.235.177.148]:32706 I=[1.2.3.4]:25 F=auguriesvbd40@google.com rejected after DATA: This message contains a virus (Sanesecurity.Junk.39934.UNOFFICIAL).
|
2013-06-15 11:20:36 [2516] 1Unmew-0000ea-SE H=egeftech.static.otenet.gr [83.235.177.148]:32706 I=[1.2.3.4]:25 F=auguriesvbd40@google.com rejected after DATA: This message contains a virus (Sanesecurity.Junk.39934.UNOFFICIAL).
|
||||||
# failJSON: { "time": "2013-06-16T02:50:43", "match": true , "host": "111.67.203.114" }
|
# failJSON: { "time": "2013-06-16T02:50:43", "match": true , "host": "111.67.203.114" }
|
||||||
2013-06-16 02:50:43 H=dbs.marsukov.com [111.67.203.114] F=<trudofspiori@mail.ru> rejected RCPT <info@nanomedtech.ua>: rejected because 111.67.203.114 is in a black list at dnsbl.sorbs.net\nCurrently Sending Spam See: http://www.sorbs.net/lookup.shtml?111.67.203.114
|
2013-06-16 02:50:43 H=dbs.marsukov.com [111.67.203.114] F=<trudofspiori@mail.ru> rejected RCPT <info@nanomedtech.ua>: rejected because 111.67.203.114 is in a black list at dnsbl.sorbs.net\nCurrently Sending Spam See: http://www.sorbs.net/lookup.shtml?111.67.203.114
|
||||||
|
# https://github.com/fail2ban/fail2ban/issues/533
|
||||||
|
# failJSON: { "time": "2013-12-29T15:34:12", "match": true , "host": "188.76.45.72" }
|
||||||
|
2013-12-29 15:34:12 1VxHRO-000NiI-Ly SA: Action: silently tossed message: score=31.0 required=5.0 trigger=30.0 (scanned in 6/6 secs | Message-Id: etPan.09bd0c40.c3d5f675.fdf7@server.local). From <Flossiedpd@jazztel.es> (host=72.45.76.188.dynamic.jazztel.es [188.76.45.72]) for me@my.com
|
||||||
|
# https://github.com/fail2ban/fail2ban/issues/533
|
||||||
|
# failJSON: { "time": "2013-12-29T15:39:11", "match": true , "host": "178.123.108.196" }
|
||||||
|
2013-12-29 15:39:11 1VxHWD-000NuW-83 SA: Action: silently tossed message: score=35.8 required=5.0 trigger=30.0 (scanned in 6/6 secs | Message-Id: 1VxHWD-000NuW-83). From <> (host=NULL [178.123.108.196]) for me@my.com
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
# failJSON: { "time": "2004-11-11T18:57:57", "match": true , "host": "203.16.208.190" }
|
||||||
|
Nov 11 18:57:57 HORDE [error] [horde] FAILED LOGIN for graham [203.16.208.190] to Horde [on line 116 of "/home/ace-hosting/public_html/horde/login.php"]
|
||||||
|
|
||||||
|
# failJSON: { "time": "2004-12-15T08:59:59", "match": true , "host": "1.2.3.4" }
|
||||||
|
Dec 15 08:59:59 HORDE [error] [imp] FAILED LOGIN for emai.user@somedomain.com [1.2.3.4] to {mx.somedomain.com:993 [imap/ssl/novalidate-cert]} [pid 68394 on line 139 of /usr/local/www/www.somedomain.com/public_html/horde/imp/lib/Auth/imp.php"]
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
# failJSON: { "time": "2013-12-28T19:03:53", "match": true , "host": "178.123.108.196" }
|
||||||
|
Sat Dec 28 19:03:53 2013 - [72926] (178.123.108.196) gsdfg - userinfo error - auth_unix.pl, ret -4, User gsdfg doesn't exist
|
||||||
|
# failJSON: { "time": "2013-12-28T19:04:03", "match": true , "host": "178.123.108.196" }
|
||||||
|
Sat Dec 28 19:04:03 2013 - [72926] (178.123.108.196) gsdfg - login error - no such user - loginname=gsdfg
|
||||||
|
# failJSON: { "time": "2013-12-28T19:05:38", "match": true , "host": "178.123.108.196" }
|
||||||
|
Sat Dec 28 19:05:38 2013 - [73540] (178.123.108.196) myname - login error - auth_unix.pl, ret -4, Password incorrect
|
|
@ -67,6 +67,7 @@ def testSampleRegexsFactory(name):
|
||||||
# Check filter exists
|
# Check filter exists
|
||||||
filterConf = FilterReader(name, "jail", {}, basedir=CONFIG_DIR)
|
filterConf = FilterReader(name, "jail", {}, basedir=CONFIG_DIR)
|
||||||
self.assertEqual(filterConf.getFile(), name)
|
self.assertEqual(filterConf.getFile(), name)
|
||||||
|
self.assertEqual(filterConf.getJailName(), "jail")
|
||||||
filterConf.read()
|
filterConf.read()
|
||||||
filterConf.getOptions({})
|
filterConf.getOptions({})
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue