fail2ban

最後更新: 2019-09-12

 

介紹

Fail2ban 是透過定時讀取特定 Service 的 log 檔,
(i.e. /var/log/maillog)

並根據 log 的內容, 去建立 iptable 的 rule 阻攔"壞人"

Version

fail2ban-client -V

Fail2Ban v0.8.8

目錄

 


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

...

python regex

 


Debug Filter

 

filter 的載入次序

datepattern
    prefregex (daemon / subroutine / pid /severity level)
        ignoreregex
        failregex

fail2ban-regex

fail2ban-regex log_file config_file

Example

postfix-sasl.conf

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

相當於:

  1. iptables -N fail2ban-ssh
  2. iptables -A fail2ban-ssh -j RETURN
  3. 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

 


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

 

postfix-sasl.conf

# 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