最後更新: 2019-09-12
介紹
Fail2ban 是透過定時讀取特定 Service 的 log 檔,
(i.e. /var/log/maillog)
並根據 log 的內容, 去建立 iptable 的 rule 阻攔"壞人"
Version
fail2ban-client -V
Fail2Ban v0.8.8
目錄
- iptables with fail2ban
- 設定
- 進階
- Jail 設定
- 查看某 jail 的資料
- 查看設定
- Filter
- Debug Filter
- Macro
- Action
- ...
- 人手 ban / unban ip
- 優化設定 - postfix-sasl
- SQLite DB
- Variable - %(postfix_log)s
- 常用 Filter
- Cheatsheet
- 詳見
fail2ban-client
Version
fail2ban-client -V
fail2ban-client version
0.9.3
查看 fail2ban-server 是否在執行
fail2ban-client ping
Server replied: pong
start / stop
fail2ban-client start [jail]
fail2ban-client stop [jail]
重讀 config file
fail2ban-client reload
查看有什麼 Service 被保護中
fail2ban-client status
Status |- Number of jail: 6 `- Jail list: pureftpd, dovecot, ssh, postfix, ssh-ddos
查看其中一個 Service 的情況:
fail2ban-client status dovecot
Status for the jail: dovecot |- Filter | |- Currently failed: 7 | |- Total failed: 10 | `- File list: /var/log/maillog `- Actions |- Currently banned: 0 |- Total banned: 0 `- Banned IP list:
設定
所有設定檔都是存放在以下目錄裡
/etc/fail2ban/
fail2ban.conf: (基本上不用修改它)
[Definition] # 2=WARN, 3=INFO, 4=DEBUG loglevel = 2 #logtarget = SYSLOG logtarget = /var/log/fail2ban.log socket = /var/run/fail2ban/fail2ban.sock pidfile = /var/run/fail2ban/fail2ban.pid # DB # fail2ban persistent data to be stored dbfile = /var/lib/fail2ban/fail2ban.sqlite3 # age at which bans should be purged from the database(86400 (24hours)) dbpurgeage = 86400
jail.conf:(Global Settings)
基本設定及 Jail 的預設值
[INCLUDES] before = paths-fedora.conf [DEFAULT] findtime = 600 # 幾耐先分析一次 log 檔 (sec). 觸發 maxfailures, 或重置 failcount ignoreip = 127.0.0.1 # white list 某些 IP bantime = 600 # IP 將會被 ban 幾耐 (sec) maxfailures = 5 # Default 幾多次嘗試失敗後才會被 ban # auto: inotify > gamin > polling backend = auto # jails should trust hostnames in logs # warn: (Default)if a hostname is encountered, a DNS lookup will be performed, # but it will be logged as a warning. usedns = no enabled = false destemail = root@localhost mta = sendmail banaction = firewallcmd-ipset
banaction
用來設定怎麼 call 什麼 action 去 ban IP (action.d/*.conf)
firewallcmd-ipset 對應 action.d/firewallcmd-ipset.conf
iptables 的 action 有:
- iptables-allports.conf
- iptables.conf
- iptables-ipset-proto4.conf
- iptables-multiport.conf
- iptables-multiport-log.conf
- iptables-new.conf
- iptables-xt_recent-echo.conf
進階
get
查看某 Service 的白名單
get <JAIL> ignoreip
fail2ban-client get sasl ignoreip These IP addresses/networks are ignored: `- 127.0.0.1
set
設定某 Service 的 findtime ( reload 後將會重置 )
fail2ban-client get vsftpd findtime
fail2ban-client set vsftpd findtime 300
把某 IP 加在白名單上:
fail2ban-client set <JAIL> addignoreip <IP>
從白名單上移除某 IP:
fail2ban-client set <JAIL> delignoreip <IP>
Jail 設定
jail.local
一般唔會修改 jail.conf , 因為它是跟 Package 而來 (deb/rpm)
所以我們多數係會修改 local config - jail.lcao
開始自定設定
[DEFAULT] findtime = 300 bantime = 3600 ignoreip = 127.0.0.1 192.168.123.0/24 maxfailures = 4 usedns = no [sshd] enabled = true [sshd-ddos] enabled = true [postfix-sasl] enabled = true
Notes
1) [sshd] 相當於 "filter = sshd" 亦即是 /etc/fail2ban/filter.d/sshd.conf
2) 在 [DEFAULT] 有預設的 "enabled = false"
filter.d/sshd.conf:
before = common.conf [Definition] _daemon = sshd failregex = ...
jail.local
[postfix-sasl] enabled = true logpath = /var/log/maillog.warn port = smtp,465,submission
P.S.
The range of port exmaple
port = 1000:2000
查看某 jail 的資料
訊息來源
fail2ban-client get sasl logpath
幾多次失敗才被 ban
fail2ban-client get sasl maxretry
幾耐進行一次 ban
fail2ban-client get <JAIL> findtime
將會被 ban 幾耐
fail2ban-client get <JAIL> bantime
什麼人被 ban
iptables -nL
Chain fail2ban-pureftpd (1 references) target prot opt source destination DROP all -- IP 0.0.0.0/0 RETURN all -- 0.0.0.0/0 0.0.0.0/0
查看設定
# -d # dump configuration
fail2ban-client -d
['add', 'ssh', 'polling'] ['set', 'ssh', 'addlogpath', '/var/log/auth.log'] ['set', 'ssh', 'maxretry', 6] ['set', 'ssh', 'addignoreip', '127.0.0.1'] ['set', 'ssh', 'addignoreip', '192.168.123.0/24'] ['set', 'ssh', 'findtime', 300] ['set', 'ssh', 'bantime', 1800] ....
Filter
原理:
找出有 FAIL LOGIN log 的那一行, 之後用 "<HOST>" 提取對方的 IP
* failregex 每一行是 OR 的關係
* <HOST> is an alias for (?:::f{4,6}:)?(?P<host>\S+)
<HOST> - common regex for IP addresses and hostnames <ADDR> - regex for IP addresses (both families) <IP4> - regex for IPv4 addresses. <IP6> - regex for IPv6 addresses (also IP enclosed in brackets)
* 在 action scripts 內的 <ip> tag 是對應 failregex 內的 <host>/<HOST> tag
Example:
"[Definition]" 是 filter rule 的核心部份. failregex 是必須的
[Definition] failregex = Authentication failure for .* from <HOST> Failed [-/\w]+ for .* from <HOST> [iI](?:llegal|nvalid) user .* from <HOST>
以下 log 會中第 2 行的 rule:
Jan 10 07:02:37 homebrou sshd[18419]: Failed password for root from 222.76.213.151 port 55236 ssh2
ignoreregex
The regex to identify log entries that should be ignored by Fail2Ban, even if they match failregex.
prefregex
To parse a common part containing in every message
在 datepattern 之後如果找不到 prefregex 就會跳過此行 log (prefregex 在 failregex 之前執行)
(略過 failregex / ignoreregex)
datepattern
...
Debug Filter
filter 的載入次序
datepattern prefregex (daemon / subroutine / pid /severity level) ignoreregex failregex
fail2ban-regex
fail2ban-regex log_file config_file
Example
fail2ban-regex /var/log/maillog /etc/fail2ban/filter.d/postfix-sasl.conf
Running tests
=============
Use failregex file : /etc/fail2ban/filter.d/postfix-sasl.conf
Use log file : /var/log/maillog
Results
=======
Failregex: 13632 total
|- #) [# of hits] regular expression
| 1) [13632] (?i): warning: .*\[<HOST>\]: SASL (?:LOGIN|PLAIN|(?:CRAM|DIGEST)-MD5) authentication failed(:.*)$
`-
Ignoreregex: 0 total
Date template hits:
|- [# of hits] date format
| [72387] MONTH Day Hour:Minute:Second
`-
Lines: 72387 lines, 0 ignored, 13632 matched, 58755 missed
Missed line(s): too many to print. Use --print-all-missed to print all 58755 lines
測試方式2
# 失敗 !!
fail2ban-regex '18-7-2008 12:13:01 [1.2.3.4] authentication failed' '\[<HOST>\] authentication failed'
原因: fail2ban 理解不到這 log 的 timestamp
Macro
filter.d/service.conf
# 載入所需的設定
[INCLUDES] after = after-common.conf before = before-common.conf
定義 macro
[DEFAULT]
_apache_error_client = \[[^]]+\] \[error\] \[client <HOST>\]
使用 macro
%(_apache_error_client)s
詳見:
https://datahunter.org/py_re
Example: vsftpd.conf
[Definition]
_daemon = vsftpd
_hostname = \S+
_pid_re = (?:\[\d+\])
prefregex = %(_hostname)s %(_daemon)s%(_pid_re)s: <F-CONTENT>.+</F-CONTENT>$
failregex = [\S+] FAIL LOGIN: Client "<HOST>"$
P.S. "<F-CONTENT>...</F-CONTENT>$"
If prefregex contains <F-CONTENT>...</F-CONTENT>,
the part of message enclosed between this tags will be extracted and
herafter used as whole message for search with failregex or ignoreregex.
Log
Aug 31 13:28:14 backup1 vsftpd[10158]: CONNECT: Client "x.x.x.x" Aug 31 13:28:14 backup1 vsftpd[10157]: [tim] FAIL LOGIN: Client "x.x.x.x"
Action
Action example:
- mail[name=?, dest=?]
- iptables-multiport[name=?, port="pop3,pop3s", protocol=tcp]
- ...
jail.conf Default 有以下設定:
# Default banning action banaction = iptables-multiport # The simplest action to take: ban only action_ = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"] ... # Choose default ban action action = %(action_)s
i.e.
在 iptables-multiport.conf 內有設定:
[Definition] actionstart = iptables -N fail2ban-<name> iptables -A fail2ban-<name> -j RETURN iptables -I INPUT -p <protocol> -m multiport --dports <port> -j fail2ban-<name> actionstop = iptables -D INPUT -p <protocol> -m multiport --dports <port> -j fail2ban-<name> iptables -F fail2ban-<name> iptables -X fail2ban-<name> actioncheck = iptables -n -L INPUT | grep -q fail2ban-<name> actionban = iptables -I fail2ban-<name> 1 -s <ip> -j DROP actionunban = iptables -D fail2ban-<name> -s <ip> -j DROP
由 actionstart 可以看出它會用 jail 的 name 及會調用它的 post 設定
i.e. jail.local
[postfix-sasl] enabled = true port = smtp,465,submission logpath = /var/log/maillog.warn
Dual action
Example:
action = iptables-multiport[name=dovecot-pop3imap, port="pop3,pop3s,imap,imaps", protocol=tcp] mail[name=dovecot-pop3imap, [email protected]]
notify admin when ban
action.d/mail.conf
# Notes.: command executed once at the start of Fail2Ban. #actionstart = ... # Notes.: command executed once at the end of Fail2Ban #actionstop = ... actionban = printf %%b "Hi,\n The IP <ip> has just been banned by Fail2Ban after <failures> attempts against <name>.\n Regards,\n Fail2Ban"|mail -s "[Fail2Ban] <name>: banned <ip> from `uname -n`" <dest>
jail.local
... action = iptables-multiport[name=mail-service, port="smtp,submission,pop3,pop3s,imap,imaps", protocol=tcp] mail[name=ban-ip, dest=a@b x@y]
fail2ban 的 iptable rule
fail2ban-ssh tcp -- 0.0.0.0/0 0.0.0.0/0 multiport dports 22 Chain fail2ban-ssh (1 references) target prot opt source destination RETURN all -- 0.0.0.0/0 0.0.0.0/0
相當於:
- iptables -N fail2ban-ssh
- iptables -A fail2ban-ssh -j RETURN
- iptables -I INPUT -p tcp --dport ssh -j fail2ban-ssh
# 更新 iptables:
/etc/init.d/fail2ban reload
ban 人時是把 rule 插入 fail2ban-ssh
Example:
Chain fail2ban-dovecot-pop3imap (1 references) target prot opt source destination DROP all -- 213.98.x.xx 0.0.0.0/0 RETURN all -- 0.0.0.0/0 0.0.0.0/0
iptables with fail2ban
準備
fail2ban-server -V
Fail2Ban v0.9.2
filter
/etc/fail2ban/filters.d/httpdos.conf
[Definition] # -A <chain_name> -j LOG --log-level 4 --log-prefix 'HTTPDOS' #failregex = .* HTTPDDOS .* SRC=<HOST> failregex = 'HTTPDOS'.*SRC=<HOST> DST=.*
test filter
fail2ban-regex /var/log/iptables.log /etc/fail2ban/filter.d/httpdos.conf
jail
/etc/fail2ban/jail.conf
[DEFAULT] ignoreip = 127.0.0.1/8 bantime = 1800 findtime = 60 maxretry = 5 backend = auto usedns = warn logencoding = auto [httpdos] enabled = true filter = httpdos logpath = /var/log/iptables.log action = iptables-multiport[name=httpdos,port=80]
start service
service fail2ban restart
cleanup state
rm /var/lib/fail2ban/fail2ban.sqlite3
testing: fail2ban
fail2ban-client ping
Server replied: pong
fail2ban-client status
Status |- Number of jail: 1 `- Jail list:
人手 ban / unban ip
# 暫時 ban 一 IP
set <JAIL> banip <IP>
# 查看
fail2ban-client status vsftpd
Status for the jail: vsftpd |- Filter | |- Currently failed: 0 | |- Total failed: 3 | `- File list: /var/log/vsftpd.log `- Actions |- Currently banned: 1 |- Total banned: 2 `- Banned IP list: x.x.x.x
fail2ban-client banned
[{'vsftpd': ['x.x.x.x']}]
# unbanip IP
set <JAIL> unbanip <IP>
# 當 unban 了 1 粒 IP 時
1
* 當 IP 再錯 Login 後會再次被 ban
* IP 可以表達成 "--all" / "IP1 IP2 ..."
# 查看永欠不 ban 的 IP
get <JAIL> ignoreip
優化設定 - postfix-sasl
原理: Login fail 記錄到獨立的 file(/var/log/maillog.warn) 以減小 scan log 的工作量
log msg:
DATE HOSTNAME postfix/smtpd[PID]: warning: unknown[X.X.X.X]: SASL LOGIN authentication failed: UGFzc3dvcmQ6
fail2ban-regex /var/log/maillog.warn /etc/fail2ban/filter.d/postfix.conf
Log Settings
/etc/rsyslog.conf
mail.warn -/var/log/maillog.warn
mail -/var/log/maillog.warn
systemctl restart rsyslog
/etc/logrotate.d/syslog
... /var/log/maillog.warn /var/log/maillog ...
jail.local Setting
[DEFAULT] ignoreip = 127.0.0.1/8 R.R.R.R findtime = 5m bantime = 60m [postfix-sasl] enabled = true port = smtp,465,submission,1025 logpath = /var/log/maillog.warn maxretry = 3 findtime = 600 bantime = 3600
systemctl restart fail2ban
Checking
fail2ban-client status postfix-sasl
P.S.
如果 X.warn 沒有 login info, 那可以用 rsyslog 的 expression-based filter
應用: vsftpd
log 的設定
/etc/rsyslog.conf
# ftp log ftp.* -/var/log/vsftpd.log
sed -i '1i /var/log/vsftpd.log' /etc/logrotate.d/syslog
jail.local
[vsftpd] enabled = true findtime = 60 bantime = 86400 maxretry = 3 logpath = /var/log/vsftpd.log port = 21, 9001:9100
filter.d/vsftpd.conf
[Definition] _daemon = vsftpd _hostname = \S+ _pid_re = (?:\[\d+\]) prefregex = %(_hostname)s %(_daemon)s%(_pid_re)s: <F-CONTENT>.+</F-CONTENT>$ failregex = [\S+] FAIL LOGIN: Client "<HOST>"$
Test
- wget ftp://user:pw@server:port/test.txt
- iptables -nL | grep -e2121 -e9001
SQLite DB
dbfile
get dbfile # get the location of fail2ban persistent datastore
Current database file is: `- /var/lib/fail2ban/fail2ban.sqlite3
set dbfile <FILE> # set the location of fail2ban persistent datastore. Set to "None" to disable
dbpurgeage
get dbpurgeage # gets the max age in seconds that history of bans will be kept
Current database purge age is: `- 86400seconds
set dbpurgeage <SECONDS> # sets the max age in <SECONDS> that history of bans will be kept
schema
table|fail2banDb|fail2banDb|2|CREATE TABLE fail2banDb(version INTEGER) table|jails|jails|3|CREATE TABLE jails(name TEXT NOT NULL UNIQUE, enabled INTEGER NOT NULL DEFAULT 1) table|logs|logs|6|CREATE TABLE logs (...) table|bans|bans|11|CREATE TABLE bans (...)
Table: fail2banDb
2
Table: jails
sshd|1 sshd-ddos|1 roundcube|1 dovecot|1 postfix|1
Table: logs
sshd|/var/log/secure|e301af9233559f9a2c05ee56dcfd4d60|924886 sshd-ddos|/var/log/secure|e301af9233559f9a2c05ee56dcfd4d60|924886 roundcube|/var/log/maillog|deb6c71c7434ecc1f49d4912c581766b|641446 dovecot|/var/log/dovecot.log|e9fd7598f3b4e3865e9439065702a043|104886 postfix|/var/log/maillog|deb6c71c7434ecc1f49d4912c581766b|641446
Table: bans
* 很大的 Tables 來
Variable - %(postfix_log)s
jail.conf 有以下 Setting
[postfix-sasl] enabled = true port = smtp,465,submission,imap3,imaps,pop3,pop3s logpath = %(postfix_log)s backend = %(postfix_backend)s
%(postfix_log)s 的由來
jail.conf 內有
[INCLUDES] before = paths-common.conf
paths-common.conf 內有
[INCLUDES]
before = paths-fedora.conf
[DEFAULT]
postfix_log = %(syslog_mail_warn)s
syslog_mail_warn = /var/log/mail.warn
paths-fedora.conf
[DEFAULT] syslog_mail = /var/log/maillog syslog_mail_warn = /var/log/maillog
firewallcmd & ipset
要有 action.d/firewallcmd-ipset.conf, 內有 actionstart, actionstop, actionban, actionunban
jail.local
[postfix-sasl] enabled = true port = smtp,smtps,submission logpath = %(postfix_log)s backend = %(postfix_backend)s action = firewallcmd-ipset[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s"] mail[name=ban-ip, [email protected]]
Checking & Troubleshoot
ipset list
Name: fail2ban-postfix-sasl Type: hash:ip Revision: 1 Header: family inet hashsize 1024 maxelem 65536 timeout 600 Size in memory: 16720 References: 1 Members: n.n.n.n timeout 3574 <= bantime # INPUT -> ctstate RELATED,ESTABLISHED -> lo -> INPUT_direct -> INPUT_ZONES_SOURCE ...
firewall-cmd --direct --get-all-rules
ipv4 filter INPUT_direct 0 -p tcp -m multiport --dports smtp,smtps,submission -m set --match-set fail2ban-postfix-sasl src -j REJECT --reject-with icmp-port-unreachable
Backend
backend used to get files modification
Available options are "pyinotify", "gamin", "polling", "systemd" and "auto"
auto: will try to use the following backends, in order: pyinotify, gamin, polling.
systemd: uses systemd python library to access the systemd journal.
Specifying "logpath" is not valid for this backend.
See "journalmatch" in the jails associated filter config
blocktype
firewallcmd-ipset.conf
[Init] blocktype = DROP
Default blocktype: REJECT --reject-with icmp-port-unreachable
常用 Filter
# Fail2Ban filter for postfix authentication failures [INCLUDES] before = common.conf [Definition] _daemon = postfix(-\w+)?/(?:submission/|smtps/)?smtp[ds] failregex = ^%(__prefix_line)swarning: [-._\w]+\[<HOST>\]: SASL ((?i)LOGIN|PLAIN|(?:CRAM|DIGEST)-MD5) authentication failed(:[ A-Za-z0-9+/:]*={0,2})?\s*$ ignoreregex = authentication failed: Connection lost to authentication server$ [Init] journalmatch = _SYSTEMD_UNIT=postfix.service
log msg
Jul 5 13:14:28 vps postfix/smtpd[28968]: warning: unknown[N.N.N.N]: SASL LOGIN authentication failed: UGFzc3dvcmQ6
Filter mode
mode = normal
Example: Postfix
Parameter
"mode": more (default combines normal and rbl), auth, normal, rbl, ddos, extra or aggressive (combines all)
Usage example (for jail.local):
[postfix] mode = aggressive
# 用 "mode" 建立另一個 jail (rewrite filter parameters of jail):
[postfix-rbl] filter = postfix[mode=rbl]
Cheatsheet
- fail2ban-client -V
- fail2ban-client status
- fail2ban-client status dovecot
- fail2ban-client get dovecot findtime
- fail2ban-client get dovecot bantime
- fail2ban-client get dovecot ignoreip
- fail2ban-client reload
- fail2ban-client set dovecot banip x.x.x.x
- fail2ban-client set dovecot unbanip x.x.x.x
- fail2ban-client get dovecot ignoreip
詳見
http://www.fail2ban.org/wiki/index.php