mirror of https://github.com/fail2ban/fail2ban
Merge branch '0.11' into master
commit
f5ea40c7da
|
@ -55,7 +55,10 @@ ver. 1.0.1-dev-1 (20??/??/??) - development nightly edition
|
||||||
* parsing of action in jail-configs considers space between action-names as separator also
|
* parsing of action in jail-configs considers space between action-names as separator also
|
||||||
(previously only new-line was allowed), for example `action = a b` would specify 2 actions `a` and `b`
|
(previously only new-line was allowed), for example `action = a b` would specify 2 actions `a` and `b`
|
||||||
* new filter and jail for GitLab recognizing failed application logins (gh-2689)
|
* new filter and jail for GitLab recognizing failed application logins (gh-2689)
|
||||||
|
* new filter and jail for Grafana recognizing failed application logins (gh-2855)
|
||||||
|
* new filter and jail for SoftEtherVPN recognizing failed application logins (gh-2723)
|
||||||
* `filter.d/guacamole.conf` extended with `logging` parameter to follow webapp-logging if it's configured (gh-2631)
|
* `filter.d/guacamole.conf` extended with `logging` parameter to follow webapp-logging if it's configured (gh-2631)
|
||||||
|
* `filter.d/bitwarden.conf` enhanced to support syslog (gh-2778)
|
||||||
* introduced new prefix `{UNB}` for `datepattern` to disable word boundaries in regex;
|
* introduced new prefix `{UNB}` for `datepattern` to disable word boundaries in regex;
|
||||||
* datetemplate: improved anchor detection for capturing groups `(^...)`;
|
* datetemplate: improved anchor detection for capturing groups `(^...)`;
|
||||||
* datepattern: improved handling with wrong recognized timestamps (timezones, no datepattern, etc)
|
* datepattern: improved handling with wrong recognized timestamps (timezones, no datepattern, etc)
|
||||||
|
|
|
@ -2,5 +2,12 @@
|
||||||
# Detecting failed login attempts
|
# Detecting failed login attempts
|
||||||
# Logged in bwdata/logs/identity/Identity/log.txt
|
# Logged in bwdata/logs/identity/Identity/log.txt
|
||||||
|
|
||||||
|
[INCLUDES]
|
||||||
|
before = common.conf
|
||||||
|
|
||||||
[Definition]
|
[Definition]
|
||||||
failregex = ^\s*\[WRN\]\s+Failed login attempt(?:, 2FA invalid)?\. <HOST>$
|
_daemon = Bitwarden-Identity
|
||||||
|
failregex = ^%(__prefix_line)s\s*\[(?:W(?:RN|arning)|Bit\.Core\.[^\]]+)\]\s+Failed login attempt(?:, 2FA invalid)?\. <ADDR>$
|
||||||
|
|
||||||
|
# DEV Notes:
|
||||||
|
# __prefix_line can result to an empty string, so it can support syslog and non-syslog at once.
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Fail2Ban filter for Grafana
|
||||||
|
# Detecting unauthorized access
|
||||||
|
# Typically logged in /var/log/grafana/grafana.log
|
||||||
|
|
||||||
|
[Init]
|
||||||
|
datepattern = ^t=%%Y-%%m-%%dT%%H:%%M:%%S%%z
|
||||||
|
|
||||||
|
[Definition]
|
||||||
|
failregex = ^(?: lvl=err?or)? msg="Invalid username or password"(?: uname=(?:"<F-ALT_USER>[^"]+</F-ALT_USER>"|<F-USER>\S+</F-USER>)| error="<F-ERROR>[^"]+</F-ERROR>"| \S+=(?:\S*|"[^"]+"))* remote_addr=<ADDR>$
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Fail2Ban filter for SoftEtherVPN
|
||||||
|
# Detecting unauthorized access to SoftEtherVPN
|
||||||
|
# typically logged in /usr/local/vpnserver/security_log/*/sec.log, or in syslog, depending on configuration
|
||||||
|
|
||||||
|
[INCLUDES]
|
||||||
|
before = common.conf
|
||||||
|
|
||||||
|
[Definition]
|
||||||
|
failregex = ^%(__prefix_line)s(?:(?:\([\d\-]+ [\d:.]+\) )?<SECURITY_LOG>: )?Connection "[^"]+": User authentication failed. The user name that has been provided was "<F-USER>(?:[^"]+|.+)</F-USER>", from <ADDR>\.$
|
|
@ -857,10 +857,19 @@ udpport = 1200,27000,27001,27002,27003,27004,27005,27006,27007,27008,27009,27010
|
||||||
action_ = %(default/action_)s[name=%(__name__)s-tcp, port="%(tcpport)s", protocol="tcp"]
|
action_ = %(default/action_)s[name=%(__name__)s-tcp, port="%(tcpport)s", protocol="tcp"]
|
||||||
%(default/action_)s[name=%(__name__)s-udp, port="%(udpport)s", protocol="udp"]
|
%(default/action_)s[name=%(__name__)s-udp, port="%(udpport)s", protocol="udp"]
|
||||||
|
|
||||||
|
[softethervpn]
|
||||||
|
port = 500,4500
|
||||||
|
protocol = udp
|
||||||
|
logpath = /usr/local/vpnserver/security_log/*/sec.log
|
||||||
|
|
||||||
[gitlab]
|
[gitlab]
|
||||||
port = http,https
|
port = http,https
|
||||||
logpath = /var/log/gitlab/gitlab-rails/application.log
|
logpath = /var/log/gitlab/gitlab-rails/application.log
|
||||||
|
|
||||||
|
[grafana]
|
||||||
|
port = http,https
|
||||||
|
logpath = /var/log/grafana/grafana.log
|
||||||
|
|
||||||
[bitwarden]
|
[bitwarden]
|
||||||
port = http,https
|
port = http,https
|
||||||
logpath = /home/*/bwdata/logs/identity/Identity/log.txt
|
logpath = /home/*/bwdata/logs/identity/Identity/log.txt
|
||||||
|
|
|
@ -455,7 +455,18 @@ class CommandAction(ActionBase):
|
||||||
ret = True
|
ret = True
|
||||||
# avoid double execution of same command for both families:
|
# avoid double execution of same command for both families:
|
||||||
if cmd and cmd not in self._operationExecuted(tag, lambda f: f != famoper):
|
if cmd and cmd not in self._operationExecuted(tag, lambda f: f != famoper):
|
||||||
ret = self.executeCmd(cmd, self.timeout)
|
realCmd = cmd
|
||||||
|
if self._jail:
|
||||||
|
# simulate action info with "empty" ticket:
|
||||||
|
aInfo = getattr(self._jail.actions, 'actionInfo', None)
|
||||||
|
if not aInfo:
|
||||||
|
aInfo = self._jail.actions._getActionInfo(None)
|
||||||
|
setattr(self._jail.actions, 'actionInfo', aInfo)
|
||||||
|
aInfo['time'] = MyTime.time()
|
||||||
|
aInfo['family'] = famoper
|
||||||
|
# replace dynamical tags, important - don't cache, no recursion and auto-escape here
|
||||||
|
realCmd = self.replaceDynamicTags(cmd, aInfo)
|
||||||
|
ret = self.executeCmd(realCmd, self.timeout)
|
||||||
res &= ret
|
res &= ret
|
||||||
if afterExec: afterExec(famoper, ret)
|
if afterExec: afterExec(famoper, ret)
|
||||||
self._operationExecuted(tag, famoper, cmd if ret else None)
|
self._operationExecuted(tag, famoper, cmd if ret else None)
|
||||||
|
|
|
@ -457,7 +457,9 @@ class Actions(JailThread, Mapping):
|
||||||
return mi[idx] if mi[idx] is not None else self.__ticket
|
return mi[idx] if mi[idx] is not None else self.__ticket
|
||||||
|
|
||||||
|
|
||||||
def __getActionInfo(self, ticket):
|
def _getActionInfo(self, ticket):
|
||||||
|
if not ticket:
|
||||||
|
ticket = BanTicket("", MyTime.time())
|
||||||
aInfo = Actions.ActionInfo(ticket, self._jail)
|
aInfo = Actions.ActionInfo(ticket, self._jail)
|
||||||
return aInfo
|
return aInfo
|
||||||
|
|
||||||
|
@ -491,7 +493,7 @@ class Actions(JailThread, Mapping):
|
||||||
bTicket = BanTicket.wrap(ticket)
|
bTicket = BanTicket.wrap(ticket)
|
||||||
btime = ticket.getBanTime(self.__banManager.getBanTime())
|
btime = ticket.getBanTime(self.__banManager.getBanTime())
|
||||||
ip = bTicket.getIP()
|
ip = bTicket.getIP()
|
||||||
aInfo = self.__getActionInfo(bTicket)
|
aInfo = self._getActionInfo(bTicket)
|
||||||
reason = {}
|
reason = {}
|
||||||
if self.__banManager.addBanTicket(bTicket, reason=reason):
|
if self.__banManager.addBanTicket(bTicket, reason=reason):
|
||||||
cnt += 1
|
cnt += 1
|
||||||
|
@ -568,7 +570,7 @@ class Actions(JailThread, Mapping):
|
||||||
"""
|
"""
|
||||||
actions = actions or self._actions
|
actions = actions or self._actions
|
||||||
ip = ticket.getIP()
|
ip = ticket.getIP()
|
||||||
aInfo = self.__getActionInfo(ticket)
|
aInfo = self._getActionInfo(ticket)
|
||||||
if log:
|
if log:
|
||||||
logSys.notice("[%s] Reban %s%s", self._jail.name, aInfo["ip"], (', action %r' % actions.keys()[0] if len(actions) == 1 else ''))
|
logSys.notice("[%s] Reban %s%s", self._jail.name, aInfo["ip"], (', action %r' % actions.keys()[0] if len(actions) == 1 else ''))
|
||||||
for name, action in actions.iteritems():
|
for name, action in actions.iteritems():
|
||||||
|
@ -602,7 +604,7 @@ class Actions(JailThread, Mapping):
|
||||||
if not action._prolongable:
|
if not action._prolongable:
|
||||||
continue
|
continue
|
||||||
if aInfo is None:
|
if aInfo is None:
|
||||||
aInfo = self.__getActionInfo(ticket)
|
aInfo = self._getActionInfo(ticket)
|
||||||
if not aInfo.immutable: aInfo.reset()
|
if not aInfo.immutable: aInfo.reset()
|
||||||
action.prolong(aInfo)
|
action.prolong(aInfo)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -696,7 +698,7 @@ class Actions(JailThread, Mapping):
|
||||||
else:
|
else:
|
||||||
unbactions = actions
|
unbactions = actions
|
||||||
ip = ticket.getIP()
|
ip = ticket.getIP()
|
||||||
aInfo = self.__getActionInfo(ticket)
|
aInfo = self._getActionInfo(ticket)
|
||||||
if log:
|
if log:
|
||||||
logSys.notice("[%s] Unban %s", self._jail.name, aInfo["ip"])
|
logSys.notice("[%s] Unban %s", self._jail.name, aInfo["ip"])
|
||||||
for name, action in unbactions.iteritems():
|
for name, action in unbactions.iteritems():
|
||||||
|
|
|
@ -3,3 +3,9 @@
|
||||||
|
|
||||||
# failJSON: { "time": "2019-11-25T21:39:58", "match": true , "host": "192.168.0.21" }
|
# failJSON: { "time": "2019-11-25T21:39:58", "match": true , "host": "192.168.0.21" }
|
||||||
2019-11-25 21:39:58.464 +01:00 [WRN] Failed login attempt, 2FA invalid. 192.168.0.21
|
2019-11-25 21:39:58.464 +01:00 [WRN] Failed login attempt, 2FA invalid. 192.168.0.21
|
||||||
|
|
||||||
|
# failJSON: { "time": "2019-11-25T21:39:58", "match": true , "host": "192.168.0.21" }
|
||||||
|
2019-11-25 21:39:58.464 +01:00 [Warning] Failed login attempt, 2FA invalid. 192.168.0.21
|
||||||
|
|
||||||
|
# failJSON: { "time": "2019-09-24T13:16:50", "match": true , "host": "192.168.0.23" }
|
||||||
|
2019-09-24T13:16:50 e5a81dbf7fd1 Bitwarden-Identity[1]: [Bit.Core.IdentityServer.ResourceOwnerPasswordValidator] Failed login attempt. 192.168.0.23
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Access of unauthorized host in /var/log/grafana/grafana.log
|
||||||
|
# failJSON: { "time": "2020-10-19T17:44:33", "match": true , "host": "182.56.23.12" }
|
||||||
|
t=2020-10-19T17:44:33+0200 lvl=eror msg="Invalid username or password" logger=context userId=0 orgId=0 uname= error="Invalid Username or Password" remote_addr=182.56.23.12
|
||||||
|
# failJSON: { "time": "2020-10-19T18:44:33", "match": true , "host": "182.56.23.13" }
|
||||||
|
t=2020-10-19T18:44:33+0200 lvl=eror msg="Invalid username or password" logger=context userId=0 orgId=0 uname= error="User not found" remote_addr=182.56.23.13
|
|
@ -0,0 +1,7 @@
|
||||||
|
# Access of unauthorized host in /usr/local/vpnserver/security_log/*/sec.log
|
||||||
|
# failJSON: { "time": "2020-05-12T10:53:19", "match": true , "host": "80.10.11.12" }
|
||||||
|
2020-05-12 10:53:19.781 Connection "CID-72": User authentication failed. The user name that has been provided was "bob", from 80.10.11.12.
|
||||||
|
|
||||||
|
# Access of unauthorized host in syslog
|
||||||
|
# failJSON: { "time": "2020-05-13T10:53:19", "match": true , "host": "80.10.11.13" }
|
||||||
|
2020-05-13T10:53:19 localhost [myserver.com/VPN/defaultvpn] (2020-05-13 10:53:19.591) <SECURITY_LOG>: Connection "CID-594": User authentication failed. The user name that has been provided was "alice", from 80.10.11.13.
|
|
@ -1448,9 +1448,10 @@ class ServerConfigReaderTests(LogCaptureTestCase):
|
||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
# dummy --
|
# dummy --
|
||||||
('j-dummy', 'dummy[name=%(__name__)s, init="==", target="/tmp/fail2ban.dummy"]', {
|
('j-dummy', '''dummy[name=%(__name__)s, init="=='<family>/<ip>'==bt:<bantime>==bc:<bancount>==", target="/tmp/fail2ban.dummy"]''', {
|
||||||
'ip4': ('family: inet4',), 'ip6': ('family: inet6',),
|
'ip4': ('family: inet4',), 'ip6': ('family: inet6',),
|
||||||
'start': (
|
'start': (
|
||||||
|
'''`printf %b "=='/'==bt:600==bc:0==\\n"''', ## empty family (independent in this action, same for both), no ip on start, initial bantime and bancount
|
||||||
'`echo "[j-dummy] dummy /tmp/fail2ban.dummy -- started"`',
|
'`echo "[j-dummy] dummy /tmp/fail2ban.dummy -- started"`',
|
||||||
),
|
),
|
||||||
'flush': (
|
'flush': (
|
||||||
|
|
Loading…
Reference in New Issue