Merge branch '0.11' into master

pull/2875/head
sebres 2020-11-11 11:19:05 +01:00
commit f5ea40c7da
11 changed files with 77 additions and 8 deletions

View File

@ -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
(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 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/bitwarden.conf` enhanced to support syslog (gh-2778)
* introduced new prefix `{UNB}` for `datepattern` to disable word boundaries in regex;
* datetemplate: improved anchor detection for capturing groups `(^...)`;
* datepattern: improved handling with wrong recognized timestamps (timezones, no datepattern, etc)

View File

@ -2,5 +2,12 @@
# Detecting failed login attempts
# Logged in bwdata/logs/identity/Identity/log.txt
[INCLUDES]
before = common.conf
[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.

View File

@ -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>$

View File

@ -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>\.$

View File

@ -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"]
%(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]
port = http,https
logpath = /var/log/gitlab/gitlab-rails/application.log
[grafana]
port = http,https
logpath = /var/log/grafana/grafana.log
[bitwarden]
port = http,https
logpath = /home/*/bwdata/logs/identity/Identity/log.txt

View File

@ -455,7 +455,18 @@ class CommandAction(ActionBase):
ret = True
# avoid double execution of same command for both families:
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
if afterExec: afterExec(famoper, ret)
self._operationExecuted(tag, famoper, cmd if ret else None)

View File

@ -457,7 +457,9 @@ class Actions(JailThread, Mapping):
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)
return aInfo
@ -491,7 +493,7 @@ class Actions(JailThread, Mapping):
bTicket = BanTicket.wrap(ticket)
btime = ticket.getBanTime(self.__banManager.getBanTime())
ip = bTicket.getIP()
aInfo = self.__getActionInfo(bTicket)
aInfo = self._getActionInfo(bTicket)
reason = {}
if self.__banManager.addBanTicket(bTicket, reason=reason):
cnt += 1
@ -568,7 +570,7 @@ class Actions(JailThread, Mapping):
"""
actions = actions or self._actions
ip = ticket.getIP()
aInfo = self.__getActionInfo(ticket)
aInfo = self._getActionInfo(ticket)
if log:
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():
@ -602,7 +604,7 @@ class Actions(JailThread, Mapping):
if not action._prolongable:
continue
if aInfo is None:
aInfo = self.__getActionInfo(ticket)
aInfo = self._getActionInfo(ticket)
if not aInfo.immutable: aInfo.reset()
action.prolong(aInfo)
except Exception as e:
@ -696,7 +698,7 @@ class Actions(JailThread, Mapping):
else:
unbactions = actions
ip = ticket.getIP()
aInfo = self.__getActionInfo(ticket)
aInfo = self._getActionInfo(ticket)
if log:
logSys.notice("[%s] Unban %s", self._jail.name, aInfo["ip"])
for name, action in unbactions.iteritems():

View File

@ -3,3 +3,9 @@
# 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
# 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

View File

@ -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

View File

@ -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.

View File

@ -1448,9 +1448,10 @@ class ServerConfigReaderTests(LogCaptureTestCase):
),
}),
# 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',),
'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"`',
),
'flush': (