如何教fail2ban检测和阻止来自整个网络块的攻击?

Rma*_*ano 5 fail2ban

我已正确安装fail2ban在我的机器上,激活了ssh,ssh-dos和的规则recidive;一切正常。

最近,我看到越来越多的来自不同主机的重复攻击模式形成相同的网络,通过在禁止后切换 IP 来规避“recidive”规则:

2015-01-25 11:12:11,976 fail2ban.actions: WARNING [ssh] Ban XXX.41.124.29
2015-01-25 11:12:13,165 fail2ban.actions: WARNING [ssh] Ban XXX.41.124.42
2015-01-25 11:12:16,297 fail2ban.actions: WARNING [ssh] Ban XXX.41.124.28
2015-01-25 11:12:20,446 fail2ban.actions: WARNING [ssh] Ban XXX.41.124.104
Run Code Online (Sandbox Code Playgroud)

我想检测它并制定一个“recidive24”规则来阻止所有这些禁止整个/24块的攻击。

我在debian 错误档案中找到了一个关于 fail2ban的建议,我已经应用了它,但是:

  1. 如果我/24ssh监狱被触发时应用完全禁令,我会遇到一个问题,我的同一网络上的某个人很容易通过从一个 IP 进行攻击来阻止我;

  2. recidive监狱将是完美的,但它不是由风暴改变IP地址触发...

所以我想更改recidive过滤器规范,以便它只查看 IP 的前三个字节,但我在这里不知所措......执行禁令的正则表达式是 (from /etc/fail2ban/recidive.conf)

# The name of the jail that this filter is used for. In jail.conf, name the 
# jail using this filter 'recidive', or change this line!
_jailname = recidive

failregex = ^(%(__prefix_line)s|,\d{3} fail2ban.actions:\s+)WARNING\s+\[(?!%(_jailname)s\])(?:.*)\]\s+Ban\s+<HOST>\s*$
Run Code Online (Sandbox Code Playgroud)

...它将匹配一个完整的 IP。

问题:如何更改此故障正则表达式,使其仅匹配主机 IP 的前三个字节?

请注意,当检测到垃圾邮件 IP 时,问题不会阻塞整个子网——这相对容易。问题是触发一种情况subnet-recidive,例如,recidive同一子网有五个或更多点击......


我想用另一个守护进程过滤fail2ban日志文件并写入第二个文件,其中最后一个字节每次都是0,并使用它触发recidive jail,但它看起来真的很笨拙......

iki*_*ddo 2

Fail2ban 没有自动阻止来自整个子网的攻击的简洁功能。不过,使用最新版本的fail2ban(我使用v0.11)、一些简单的fail2ban脚本和一个小型的纯python3脚本是可以做到的。

注意:问题涉及“整个子网”(我将其称为 CIDR 块或 IP 范围)。这是一件困难的事情,因为我们不知道攻击者控制了多大的地址块。攻击者甚至可能偶然控制同一块中的少数地址,而中间地址是合法的。

步骤1.获取主机的CIDR

fail2ban 监控的日志文件通常显示主机(例如 127.0.0.1),而不是 CIDR 块(127.0.0.0/24)或 IP 范围(127.0.0.0 - 127.0.0.255)。

解决方案可能是首先假设一个小的 CIDR 块,然后随着日志报告更多行为不当的主机而扩大它。显然,如果这些主机来自相邻地址,则只应增加 CIDR。但这很复杂,无论算法多么复杂,合法地址都可能会被捕获。

相反,我们也可以简单地在whois中查找CIDR。这会导致 whois 查找出现一些延迟,并产生一些流量。但是解析whois的脚本,可以将CIDR写入syslog,然后可以再次被fail2ban捕获。

注意:不要忘记将此脚本挂接到您首选的 action.d/lorem-ipsum.conf 脚本的 actionban 中。请注意,如果其 maxretry > 1,那么您将无法捕获主机仅失败一次的 CIDR 块!

#!/usr/bin/python

import sys, subprocess, ipaddress, syslog

def narrowest_cidr(cidrA, cidrB):
    _ip, subA = cidrA.split('/')
    _ip, subB = cidrB.split('/')

    if int(subA) > int(subB):
        return cidrA
    else:
        return cidrB

bad_ip = sys.argv[1]
cidrs = []
inetnums = []
ret = None

whois = subprocess.run(['whois', bad_ip], text=True,
        stdout=subprocess.PIPE, check=True)

for line in whois.stdout.split('\n'):
    if 'CIDR:' in line:
        cidrs.append(line.replace('CIDR:', '').strip())
    if 'inetnum:' in line:
        inetnums.append(line.replace('inetnum:', '').strip())

if len(cidrs) >= 1:
    if len(cidrs) == 1:
        cidr = cidrs[0]
    else:
        cidr = narrowest_cidr(cidrs[0], cidrs[-1])
elif len(inetnums) > 0:
    if len(inetnums) == 1:
        inetnum = inetnums[0]
        startip, endip = inetnum.split(' - ')
        cidrs = [ipaddr for ipaddr in ipaddress.summarize_address_range(ipaddress.IPv4Address(startip), ipaddress.IPv4Address(endip))]
        if len(cidrs) == 1:
            cidr = cidrs[0]
        else:
            cidr = narrowest_cidr(cidrs[0], cidrs[-1])
else:
    cidr = "no CIDR found"

syslog.openlog(ident="suspectrange")
syslog.syslog("{} has CIDR {}".format(bad_ip, cidr))
Run Code Online (Sandbox Code Playgroud)

步骤 2. 确定何时阻止 CIDR

如果我们有动态 CIDR 确定,这可能会变得有点复杂,因为我们必须更改我们所禁止的内容。但通过 whois 查找,我们可以根据我们认为合适的 maxretry 和 findtime 简单地禁止我们找到的 CIDR 块。这是我使用的监狱:

[fail2ban-cidr-recidive]
filter = fail2ban-cidr-recidive
action = nftables-common[name=BADRANGE]
logpath = /var/log/everything/current

#5 bans in 12hrs is 48hr ban
maxretry = 5
findtime = 12h
bantime = 2d
Run Code Online (Sandbox Code Playgroud)

以及附带的过滤器

[Definition]

failregex = \[suspectrange\] .* has CIDR <SUBNET>
Run Code Online (Sandbox Code Playgroud)

步骤 3. 实际阻止 CIDR

您可能已经注意到,我使用 action.d/nft-common.conf。nftables 允许阻止 CIDR 块而不是单个主机。这需要对操作脚本的 actionstart 部分的第一行进行一些小更改:

actionstart = nft add set netdev f2b <set_name> \{ type ipv4_addr\; \}
Run Code Online (Sandbox Code Playgroud)

应修改为:

actionstart = nft add set netdev f2b <set_name> \{ type ipv4_addr\; flags interval\; \}
Run Code Online (Sandbox Code Playgroud)