mcpField
D
detecting-port-scanning-with-fail2ban

detecting-port-scanning-with-fail2ban

github.com/mukul975安全35.2k79 次安装8 周前更新
代码仓库

关于 detecting-port-scanning-with-fail2ban

这项安全技能指导使用 Fail2ban 从日志识别端口扫描和暴力破解,并通过防火墙封禁来源 IP。适用于管理联网服务器的运维与安全人员,涵盖自定义过滤器、封禁动作和验证流程。

主要功能

  1. 01按日志模式检测扫描与暴力破解
  2. 02配置 Fail2ban jail 和过滤器
  3. 03通过 iptables 或 nftables 封禁 IP
  4. 04测试过滤器并查看封禁状态

适用场景

  1. 01阻止公共服务器上的自动化端口扫描
  2. 02为 SSH、HTTP 或 FTP 防范暴力破解
  3. 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 外,安装时一起下载的参考资料和脚本。

LICENSE
references/
api-reference.md
scripts/
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

核心概念

术语定义
JailFail2ban 配置单元,针对特定服务组合过滤器(检测什么)、操作(采取什么措施)和参数(阈值、时间)
FilterFail2ban 应用于日志文件的正则表达式模式,用于识别身份验证失败尝试、扫描或其他恶意活动
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。

方案:

  1. 安装 Fail2ban,并将其配置为监控 Nginx 访问日志中的扫描模式(对已知漏洞路径返回 404/403 响应)
  2. 创建自定义的 http-scan 过滤器,以匹配常见的扫描器特征和漏洞探测 URI
  3. 在 5 分钟的 findtime 内将 maxretry 设为 10,对首次违规封禁 1 小时
  4. 启用 recidive jail,将屡次违规者的封禁时长延长至 7 天
  5. 配置发送至 Slack 的 webhook 通知,实时了解封禁活动
  6. 为发往已关闭端口的 SYN 数据包添加 iptables 日志规则,以检测端口扫描
  7. 创建每日报告脚本,显示被封禁的 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