Fail2ban

我如何教 fail2ban 檢測和阻止來自整個網路塊的攻擊?

  • April 9, 2021

我已經正確安裝fail2ban在我的機器上,啟動了ssh,ssh-dosrecidive;的規則 一切正常。

最近,我看到越來越多的來自不同主機的重複攻擊來自同一網路,它們通過在禁止​​後切換 IP 來規避“重複”規則:

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

我想檢測它並製定一個“recidive24”規則來阻止所有這些禁止整個/24區塊的攻擊。

我在debian 錯誤檔案中找到了一個關於 fail2ban 的建議,我已經應用了它,但是:

  1. 如果我/24在監獄被觸發時應用完全禁令ssh,我會遇到一個問題,即我的同一網路上的某人很容易阻止我,只需從一個 IP 進行攻擊;
  2. 監獄將recidive是完美的,但它不是由更改 IP 引發的風暴……

所以我想更改recidive過濾器規範,使其只查看IP的前三個字節,但我在這裡不知所措……執行禁令的正則表達式是(來自/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*$

…它將匹配一個完整的IP。

問題:如何更改此失敗正則表達式,使其僅匹配主機 IP 的前三個字節?

請注意,當檢測到垃圾郵件 IP 時,問題不是阻塞整個子網 — 這相對容易。問題是觸發一種情況subnet-recidive,例如,recidive同一子網有五個或更多命中…


我雖然關於用另一個守護程序過濾fail2ban日誌文件並編寫第二個文件,其中最後一個字節每次都是0,並使用它觸發recive jail,但它看起來真的很笨拙……

Fail2ban 沒有自動阻止來自整個子網的攻擊的簡潔功能。不過,可以使用最新版本的 fail2ban(我使用 v0.11)、一些簡單的 fail2ban 腳本和一個小的純 python3 腳本。

注意:問題指的是“整個子網”(我將其稱為 CIDR 塊或 IP 範圍)。這是一件困難的事情,因為我們不知道攻擊者控制的地址塊有多大。甚至可能是攻擊者偶然控制了同一塊中的少數地址,中間地址是合法的。

Step 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))

步驟 2. 確定何時阻止 CIDR

如果我們有動態 CIDR 確定,這可能會變得有點複雜,因為我們必須改變我們禁止的內容。但是通過 whois 查詢,我們可以簡單地禁止我們發現的 CIDR 塊,基於我們認為合適的 maxretry 和 findtime。這是我使用的監獄:

[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

和隨附的過濾器

[Definition]

failregex = \[suspectrange\] .* has CIDR <SUBNET>

步驟 3. 實際阻止 CIDR

您可能已經註意到,我使用 action.d/nft-common.conf。nftables 允許阻止 CIDR 塊而不是單個主機。這需要對動作腳本的 actionstart 部分的第一行做一個小的改動:

actionstart = nft add set netdev f2b <set_name> \{ type ipv4_addr\; \}

應修改為:

actionstart = nft add set netdev f2b <set_name> \{ type ipv4_addr\; flags interval\; \}

將這種魔法/24(有些人甚至可能喜歡/22)添加到iptables所有 jails 的命令中的最簡單方法是添加兩個文件:

/etc/fail2ban/action.d/iptables-multiport.local
/etc/fail2ban/action.d/iptables-allports.local

內容如下:

[Definition]
actionban = <iptables> -I f2b-<name> 1 -s <ip>/24 -j <blocktype>
actionunban = <iptables> -D f2b-<name> -s <ip>/24 -j <blocktype>

對於檢測部分,您需要修改過濾器……這有點棘手。但好的部分是 - 沒有必要!這個子網阻塞的東西工作得很好。

引用自:https://unix.stackexchange.com/questions/181114