Configures Fail2ban with custom filters and actions to detect port scans, SSH brute force, and network reconnaissance; auto-bans attacker IPs and alerts security teams on Linux servers.
npx claudepluginhub killvxk/cybersecurity-skills-zhThis skill uses the workspace's default tool permissions.
- 自动封禁对互联网暴露服务器执行端口扫描的 IP 地址
Configures Fail2ban with custom filters and actions to detect port scanning, SSH brute force, and network reconnaissance; bans offending IPs and alerts teams. For Linux servers facing automated probes.
Configures Fail2ban on Linux with custom filters and iptables rules to detect port scans, SSH brute force, ban IPs, and send alerts. For securing internet-facing servers.
Detects network reconnaissance and port scanning using Suricata and Snort IDS signatures, threshold rules, and traffic anomaly analysis. Identifies Nmap, Masscan, and custom scans.
Share bugs, ideas, or general feedback.
不适用场景:作为唯一的网络安全控制;防御来自大量源 IP 的分布式攻击;替代正确的防火墙规则和网络分段。
fail2ban-client --version)# 安装 Fail2ban
sudo apt install -y fail2ban
# 创建本地配置(不要直接编辑 jail.conf)
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
# 配置全局默认值
sudo tee /etc/fail2ban/jail.local << 'EOF'
[DEFAULT]
# 封禁时长(默认 1 小时,对重复违规者逐步升级)
bantime = 3600
# 检测窗口
findtime = 600
# 封禁前的最大失败次数
maxretry = 5
# 使用 iptables 的封禁动作
banaction = iptables-multiport
banaction_allports = iptables-allports
# 邮件通知
destemail = security@example.com
sender = fail2ban@example.com
mta = sendmail
action = %(action_mwl)s
# 忽略内网
ignoreip = 127.0.0.1/8 ::1 10.10.0.0/16
# 在可用时使用 systemd journal 后端
backend = systemd
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 7200
findtime = 300
[sshd-ddos]
enabled = true
port = ssh
filter = sshd-ddos
logpath = /var/log/auth.log
maxretry = 6
bantime = 3600
EOF
# 为丢弃的连接创建 iptables 日志规则
sudo iptables -N PORTSCAN
sudo iptables -A PORTSCAN -j LOG --log-prefix "PORTSCAN_DETECTED: " --log-level 4
sudo iptables -A PORTSCAN -j DROP
# 记录到关闭端口的 SYN 数据包(表明有扫描)
sudo iptables -A INPUT -p tcp --tcp-flags SYN,ACK,FIN,RST SYN -m state --state NEW \
-m recent --name portscan --set
sudo iptables -A INPUT -p tcp --tcp-flags SYN,ACK,FIN,RST SYN -m state --state NEW \
-m recent --name portscan --rcheck --seconds 10 --hitcount 20 -j PORTSCAN
# 为端口扫描创建 Fail2ban 过滤器
sudo tee /etc/fail2ban/filter.d/portscan.conf << 'EOF'
[Definition]
# 匹配 iptables 端口扫描日志条目
failregex = PORTSCAN_DETECTED: .* SRC=<HOST> DST=\S+ .* DPT=\d+
ignoreregex =
datepattern = {^LN-BEG}
EOF
# 为通过内核日志检测 Nmap 创建 Fail2ban 过滤器
sudo tee /etc/fail2ban/filter.d/nmap-scan.conf << 'EOF'
[Definition]
# 检测来自同一来源的多个端口的快速连接尝试
failregex = kernel: \[.*\] PORTSCAN_DETECTED: .* SRC=<HOST>
iptables: .* PORTSCAN .* SRC=<HOST>
ignoreregex =
datepattern = {^LN-BEG}
EOF
# 为 HTTP 扫描/探测创建过滤器
sudo tee /etc/fail2ban/filter.d/http-scan.conf << 'EOF'
[Definition]
# 检测探测常见漏洞的扫描器
failregex = ^<HOST> .* "(GET|POST|HEAD) /(wp-login|wp-admin|phpmyadmin|admin|.env|xmlrpc|wp-content/uploads).*" (403|404|444)
^<HOST> .* "(GET|POST) /.*\.(php|asp|aspx|jsp|cgi)\?.*" (403|404)
^<HOST> .* "() .*" 400
^<HOST> .* "(GET|POST) /.*" 400
ignoreregex =
datepattern = {^LN-BEG}
EOF
# 将端口扫描 jail 添加到 jail.local
sudo tee -a /etc/fail2ban/jail.local << 'EOF'
[portscan]
enabled = true
filter = portscan
logpath = /var/log/kern.log
maxretry = 10
findtime = 60
bantime = 86400
banaction = iptables-allports
action = %(action_mwl)s
[nmap-scan]
enabled = true
filter = nmap-scan
logpath = /var/log/kern.log
maxretry = 5
findtime = 30
bantime = 86400
banaction = iptables-allports
action = %(action_mwl)s
[http-scan]
enabled = true
filter = http-scan
logpath = /var/log/nginx/access.log
maxretry = 10
findtime = 300
bantime = 3600
banaction = iptables-multiport
port = http,https
[recidive]
enabled = true
filter = recidive
logpath = /var/log/fail2ban.log
bantime = 604800
findtime = 86400
maxretry = 3
banaction = iptables-allports
action = %(action_mwl)s
EOF
# 创建自定义动作,封禁并发送 Webhook 通知
sudo tee /etc/fail2ban/action.d/iptables-webhook.conf << 'EOF'
[Definition]
actionstart = <iptables> -N f2b-<name>
<iptables> -A f2b-<name> -j RETURN
<iptables> -I <chain> -p <protocol> -j f2b-<name>
actionstop = <iptables> -D <chain> -p <protocol> -j f2b-<name>
<iptables> -F f2b-<name>
<iptables> -X f2b-<name>
actioncheck = <iptables> -n -L <chain> | grep -q 'f2b-<name>[ \t]'
actionban = <iptables> -I f2b-<name> 1 -s <ip> -j <blocktype>
curl -s -X POST "<webhook_url>" \
-H "Content-Type: application/json" \
-d '{"text":"[Fail2ban] Banned <ip> from <name> jail (failures: <failures>)"}'
actionunban = <iptables> -D f2b-<name> -s <ip> -j <blocktype>
[Init]
chain = INPUT
blocktype = DROP
webhook_url = https://hooks.slack.com/services/XXXX/YYYY/ZZZZ
EOF
# 为重复违规者创建递进封禁动作
sudo tee /etc/fail2ban/action.d/escalating-ban.conf << 'EOF'
[Definition]
actionban = <iptables> -I f2b-<name> 1 -s <ip> -j DROP
echo "$(date) BAN <ip> jail=<name> failures=<failures> bantime=<bantime>" >> /var/log/fail2ban-bans.log
actionunban = <iptables> -D f2b-<name> -s <ip> -j DROP
echo "$(date) UNBAN <ip> jail=<name>" >> /var/log/fail2ban-bans.log
EOF
# 重启 Fail2ban
sudo systemctl restart fail2ban
# 验证 jail 是否激活
sudo fail2ban-client status
sudo fail2ban-client status sshd
sudo fail2ban-client status portscan
# 用正则表达式检查测试端口扫描过滤器
sudo fail2ban-regex /var/log/kern.log /etc/fail2ban/filter.d/portscan.conf
# 测试 HTTP 扫描过滤器
sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/http-scan.conf
# 从测试机器模拟端口扫描(已授权)
# 在测试机器上执行:
nmap -sS -p 1-1000 <target_ip>
# 验证扫描器被封禁
sudo fail2ban-client status portscan
# 应显示测试 IP 在封禁列表中
# 检查 iptables 中的封禁规则
sudo iptables -L f2b-portscan -n
# 解封测试 IP
sudo fail2ban-client set portscan unbanip <test_ip>
# 实时查看封禁活动
sudo tail -f /var/log/fail2ban.log | grep -E "Ban|Unban"
# 生成每日摘要报告
sudo tee /usr/local/bin/fail2ban-report.sh << 'SCRIPT'
#!/bin/bash
echo "=== Fail2ban 每日报告 $(date) ==="
echo ""
echo "活跃 Jail:"
sudo fail2ban-client status | grep "Jail list"
echo ""
echo "当前封禁 IP:"
for jail in $(sudo fail2ban-client status | grep "Jail list" | sed 's/.*://;s/,//g'); do
count=$(sudo fail2ban-client status "$jail" | grep "Currently banned" | awk '{print $NF}')
if [ "$count" -gt 0 ]; then
echo " $jail: $count 已封禁"
sudo fail2ban-client status "$jail" | grep "Banned IP"
fi
done
echo ""
echo "过去 24 小时——按 Jail 统计封禁数:"
grep "Ban " /var/log/fail2ban.log | grep "$(date +%Y-%m-%d)" | awk '{print $NF}' | sort | uniq -c | sort -rn
SCRIPT
chmod +x /usr/local/bin/fail2ban-report.sh
# 定时每日报告
echo "0 8 * * * root /usr/local/bin/fail2ban-report.sh | mail -s 'Fail2ban Report' security@example.com" | sudo tee /etc/cron.d/fail2ban-report
# 跨重启持久化 iptables 规则
sudo apt install iptables-persistent
sudo netfilter-persistent save
| 术语 | 定义 |
|---|---|
| Jail | Fail2ban 配置单元,将过滤器(检测内容)、动作(执行操作)和参数(阈值、时间)组合在一起,用于特定服务 |
| Filter(过滤器) | Fail2ban 应用于日志文件的正则表达式模式,用于识别认证失败、扫描或其他恶意活动 |
| Recidive Jail | 元 Jail,监控 Fail2ban 自身日志以发现重复违规者,对多次被封禁的 IP 应用递进封禁时长 |
| Find Time | Fail2ban 统计匹配日志条目的时间窗口(秒);在 findtime 内达到 maxretry 次失败则触发封禁 |
| Ban Action | IP 被封禁时执行的命令或脚本,通常添加防火墙规则,也可扩展为 Webhook、SIEM 告警或黑名单更新 |
| Ignore IP | 永不封禁的 IP 地址或 CIDR 范围白名单,防止锁定可信网络和监控系统 |
背景:某公司运营着一台公开的 Web 服务器,每天收到数千次自动扫描尝试,机器人探测 /wp-admin、/phpmyadmin、/.env 等易受攻击的路径。安全团队希望在允许合法流量通过的同时自动封锁扫描器。服务器在 Ubuntu 22.04 上运行 Nginx。
方法:
http-scan 过滤器,匹配常见扫描器签名和漏洞探测 URI常见陷阱:
## Fail2ban 端口扫描防御报告
**服务器**:web-prod-01(203.0.113.50)
**报告周期**:2024-03-15 00:00 至 2024-03-16 00:00 UTC
### 活跃 Jail
| Jail | 过滤器 | 最大重试 | 封禁时长 | 当前封禁 |
|------|--------|-----------|----------|------------------|
| sshd | sshd | 3 | 2 小时 | 12 个 IP |
| portscan | portscan | 10 | 24 小时 | 47 个 IP |
| http-scan | http-scan | 10 | 1 小时 | 89 个 IP |
| recidive | recidive | 3 | 7 天 | 8 个 IP |
### 24 小时摘要
- 封禁事件总数:347
- 唯一 IP 封禁数:156
- 主要攻击来源:CN(67 个 IP),RU(34 个 IP),US(21 个 IP)
- 最频繁攻击服务:HTTP 扫描(214 次封禁)
- 重复违规升级:8 个 IP 被封禁 7 天
### 前 5 封禁 IP
| IP 地址 | Jail | 封禁次数 | 首次发现 | 最后发现 |
|------------|------|-----------|------------|-----------|
| 45.33.32.156 | portscan | 12 | 00:15 | 23:47 |
| 198.51.100.23 | http-scan | 8 | 02:30 | 18:22 |
| 203.0.113.100 | sshd | 6 | 05:12 | 21:33 |