关于 detecting-port-scanning-with-fail2ban
这项安全技能指导使用 Fail2ban 从日志识别端口扫描和暴力破解,并通过防火墙封禁来源 IP。适用于管理联网服务器的运维与安全人员,涵盖自定义过滤器、封禁动作和验证流程。
主要功能
- 01按日志模式检测扫描与暴力破解
- 02配置 Fail2ban jail 和过滤器
- 03通过 iptables 或 nftables 封禁 IP
- 04测试过滤器并查看封禁状态
适用场景
- 01阻止公共服务器上的自动化端口扫描
- 02为 SSH、HTTP 或 FTP 防范暴力破解
- 03按组织特有日志模式创建检测规则
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ mukul975/ anthropic-cybersecurity-skills --skill detecting-port-scanning-with-fail2ban安装后在 Claude Code 中输入/detecting-port-scanning-with-fail2ban确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
LICENSEreferences/api-reference.mdscripts/agent.py详细介绍
使用 Fail2ban 检测端口扫描
适用场景
- 自动封禁针对面向互联网的服务器执行端口扫描的 IP 地址
- 通过自动封禁 IP,保护 SSH、HTTP、FTP 和其他服务免受暴力破解攻击
- 为日志文件中的组织特定攻击模式创建自定义检测过滤器
- 在流量到达 IDS/IPS 进行深入分析之前,减少自动扫描机器人产生的噪声
- 通过为网络监控添加基于主机的自动响应,实现纵深防御
请勿将其用作唯一的网络安全控制措施,也不要用它来防御来自大量源 IP 的分布式攻击,或取代适当的防火墙规则和网络分段。
前提条件
- 已安装 Fail2ban 0.11+(
fail2ban-client --version) - 拥有用于操作 iptables/nftables 的 Root/sudo 权限
- 服务会将连接尝试记录到可解析的日志文件中(syslog、auth.log、access.log)
- 已安装并启用 iptables 或 nftables 作为主机防火墙
- 可选:用于在封禁事件发生时发送邮件通知的 SMTP 服务器
工作流
步骤 1:安装并配置 Fail2ban
# Install Fail2ban
sudo apt install -y fail2ban
# Create local configuration (never edit jail.conf directly)
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
# Configure global defaults
sudo tee /etc/fail2ban/jail.local << 'EOF'
[DEFAULT]
# Ban duration (1 hour default, escalates for repeat offenders)
bantime = 3600
# Detection window
findtime = 600
# Max failures before ban
maxretry = 5
# Ban action using iptables
banaction = iptables-multiport
banaction_allports = iptables-allports
# Email notifications
destemail = [email protected]
sender = [email protected]
mta = sendmail
action = %(action_mwl)s
# Ignore internal networks
ignoreip = 127.0.0.1/8 ::1 10.10.0.0/16
# Use systemd journal backend where available
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
步骤 2:创建自定义端口扫描检测过滤器
# Create iptables logging rule for dropped connections
sudo iptables -N PORTSCAN
sudo iptables -A PORTSCAN -j LOG --log-prefix "PORTSCAN_DETECTED: " --log-level 4
sudo iptables -A PORTSCAN -j DROP
# Log SYN packets to closed ports (indicates scanning)
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
# Create Fail2ban filter for port scanning
sudo tee /etc/fail2ban/filter.d/portscan.conf << 'EOF'
[Definition]
# Match iptables port scan log entries
failregex = PORTSCAN_DETECTED: .* SRC=<HOST> DST=\S+ .* DPT=\d+
ignoreregex =
datepattern = {^LN-BEG}
EOF
# Create Fail2ban filter for Nmap detection via kernel logs
sudo tee /etc/fail2ban/filter.d/nmap-scan.conf << 'EOF'
[Definition]
# Detect rapid connection attempts to multiple ports from same source
failregex = kernel: \[.*\] PORTSCAN_DETECTED: .* SRC=<HOST>
iptables: .* PORTSCAN .* SRC=<HOST>
ignoreregex =
datepattern = {^LN-BEG}
EOF
# Create filter for HTTP scanning/probing
sudo tee /etc/fail2ban/filter.d/http-scan.conf << 'EOF'
[Definition]
# Detect scanners probing for common vulnerabilities
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
步骤 3:配置端口扫描 Jail
# Add port scan jails to 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
步骤 4:配置高级封禁操作
# Create custom action that blocks and sends webhook notification
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
# Create escalating ban action for repeat offenders
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
步骤 5:测试并验证检测效果
# Restart Fail2ban
sudo systemctl restart fail2ban
# Verify jails are active
sudo fail2ban-client status
sudo fail2ban-client status sshd
sudo fail2ban-client status portscan
# Test the port scan filter with a regex check
sudo fail2ban-regex /var/log/kern.log /etc/fail2ban/filter.d/portscan.conf
# Test the HTTP scan filter
sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/http-scan.conf
# Simulate a port scan from a test machine (authorized)
# From the test machine:
nmap -sS -p 1-1000 <target_ip>
# Verify the scanner gets banned
sudo fail2ban-client status portscan
# Should show the test IP in the banned list
# Check iptables for the ban rule
sudo iptables -L f2b-portscan -n
# Unban the test IP
sudo fail2ban-client set portscan unbanip <test_ip>
步骤 6:监控和维护
# View real-time ban activity
sudo tail -f /var/log/fail2ban.log | grep -E "Ban|Unban"
# Generate daily summary report
sudo tee /usr/local/bin/fail2ban-report.sh << 'SCRIPT'
#!/bin/bash
echo "=== Fail2ban Daily Report $(date) ==="
echo ""
echo "Active Jails:"
sudo fail2ban-client status | grep "Jail list"
echo ""
echo "Currently Banned IPs:"
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 banned"
sudo fail2ban-client status "$jail" | grep "Banned IP"
fi
done
echo ""
echo "Last 24 hours - Ban count by 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
# Schedule daily report
echo "0 8 * * * root /usr/local/bin/fail2ban-report.sh | mail -s 'Fail2ban Report' [email protected]" | sudo tee /etc/cron.d/fail2ban-report
# Persist iptables rules across reboots
sudo apt install iptables-persistent
sudo netfilter-persistent save
核心概念
| 术语 | 定义 |
|---|---|
| Jail | Fail2ban 配置单元,针对特定服务组合过滤器(检测什么)、操作(采取什么措施)和参数(阈值、时间) |
| Filter | Fail2ban 应用于日志文件的正则表达式模式,用于识别身份验证失败尝试、扫描或其他恶意活动 |
| Recidive Jail | 一种元 Jail,用于监控 Fail2ban 自身的日志,查找屡次违规者,并对多次被封禁的 IP 逐步延长封禁时间 |
| 查找时间 | Fail2ban 统计匹配日志条目的时间窗口,单位为秒;在 findtime 时间内达到 maxretry 次失败将触发封禁 |
| 封禁操作 | 封禁 IP 时执行的命令或脚本,通常用于添加防火墙规则,也可扩展为调用 Webhook、发送 SIEM 警报或更新封锁列表 |
| 忽略 IP | 永不封禁的 IP 地址或 CIDR 网段白名单,可防止可信网络和监控系统被锁定 |
工具与系统
- Fail2ban 0.11+:日志解析入侵防御框架,可基于任意日志文件中的模式匹配封禁 IP 地址
- iptables/nftables:Linux 内核防火墙,Fail2ban 的封禁操作会通过它在网络层阻止违规 IP 地址
- fail2ban-regex:测试工具,可在部署到生产环境之前,根据实际日志文件验证过滤器正则表达式
- fail2ban-client:命令行管理工具,可查询 Jail 状态、手动封禁或解封 IP,以及重新加载配置
- rsyslog/syslog-ng:系统日志守护进程,用于生成 Fail2ban 监控的日志文件,以检测攻击
常见场景
场景:抵御针对公网 Web 服务器的自动化扫描
背景:一家公司运行着一台公网 Web 服务器,每天都会收到数千次来自机器人的自动扫描尝试,这些机器人会探测易受攻击的路径(/wp-admin、/phpmyadmin、/.env)。安全团队希望自动封禁扫描器,同时允许合法流量通过。服务器在 Ubuntu 22.04 上运行 Nginx。
方案:
- 安装 Fail2ban,并将其配置为监控 Nginx 访问日志中的扫描模式(对已知漏洞路径返回 404/403 响应)
- 创建自定义的
http-scan过滤器,以匹配常见的扫描器特征和漏洞探测 URI - 在 5 分钟的 findtime 内将 maxretry 设为 10,对首次违规封禁 1 小时
- 启用 recidive jail,将屡次违规者的封禁时长延长至 7 天
- 配置发送至 Slack 的 webhook 通知,实时了解封禁活动
- 为发往已关闭端口的 SYN 数据包添加 iptables 日志规则,以检测端口扫描
- 创建每日报告脚本,显示被封禁的 IP、攻击模式和地理分布
注意事项:
- 将 maxretry 设得过低(例如 1-2),导致输错 URL 的合法用户也被封禁
- 未将监控系统(Nagios、UptimeRobot)列入白名单,它们的运行状况检查可能会触发过滤器
- 忘记持久化 iptables 规则,导致重启后所有封禁规则丢失
- 部署前未使用 fail2ban-regex 测试过滤器,导致无法匹配或产生大量误报
输出格式
## Fail2ban Port Scan Defense Report
**Server**: web-prod-01 (203.0.113.50)
**Reporting Period**: 2024-03-15 00:00 to 2024-03-16 00:00 UTC
### Active Jails
| Jail | Filter | Max Retry | Ban Time | Currently Banned |
|------|--------|-----------|----------|------------------|
| sshd | sshd | 3 | 2 hours | 12 IPs |
| portscan | portscan | 10 | 24 hours | 47 IPs |
| http-scan | http-scan | 10 | 1 hour | 89 IPs |
| recidive | recidive | 3 | 7 days | 8 IPs |
### 24-Hour Summary
- Total ban events: 347
- Unique IPs banned: 156
- Top attacking country: CN (67 IPs), RU (34 IPs), US (21 IPs)
- Most targeted service: HTTP scanning (214 bans)
- Recidive escalations: 8 IPs banned for 7 days
### Top 5 Banned IPs
| IP Address | Jail | Ban Count | First Seen | Last Seen |
|------------|------|-----------|------------|-----------|
| 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 |
评论
支持 Markdown