인터페이스는 현지화되어 있으며, Skill 소개와 설명 문서는 선택한 언어로 AI가 자동 번역합니다. 코드·명령어·경로·전문 용어는 원문을 유지하며 원작자 문서가 우선합니다.
Skills 둘러보기
생산성 및 협업 · SKILL.md

detecting-port-scanning-with-fail2ban

detecting-port-scanning-with-fail2ban

使用自定义过滤器和动作配置 Fail2ban,检测端口扫描活动、SSH 暴力破解尝试和网络侦察,自动封禁攻击 IP 并向安全团队告警可疑的网络探测行为。

Independent GitHub snapshot · Automated classification · Original documentation governs

Skill 문서

GitHub

name: detecting-port-scanning-with-fail2ban description: > 使用自定义过滤器和动作配置 Fail2ban,检测端口扫描活动、SSH 暴力破解尝试和网络侦察,自动封禁攻击 IP 并向安全团队告警可疑的网络探测行为。 domain: cybersecurity subdomain: network-security tags: [network-security, fail2ban, port-scanning, intrusion-prevention, automated-defense] version: "1.0" author: mahipal license: Apache-2.0

使用 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

# 安装 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

步骤 2:创建自定义端口扫描检测过滤器

# 为丢弃的连接创建 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

步骤 3:为端口扫描配置 Jail

# 将端口扫描 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

步骤 4:配置高级封禁动作

# 创建自定义动作,封禁并发送 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

步骤 5:测试和验证检测

# 重启 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>

步骤 6:监控和维护

# 实时查看封禁活动
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

核心概念

术语定义
JailFail2ban 配置单元,将过滤器(检测内容)、动作(执行操作)和参数(阈值、时间)组合在一起,用于特定服务
Filter(过滤器)Fail2ban 应用于日志文件的正则表达式模式,用于识别认证失败、扫描或其他恶意活动
Recidive Jail元 Jail,监控 Fail2ban 自身日志以发现重复违规者,对多次被封禁的 IP 应用递进封禁时长
Find TimeFail2ban 统计匹配日志条目的时间窗口(秒);在 findtime 内达到 maxretry 次失败则触发封禁
Ban ActionIP 被封禁时执行的命令或脚本,通常添加防火墙规则,也可扩展为 Webhook、SIEM 告警或黑名单更新
Ignore IP永不封禁的 IP 地址或 CIDR 范围白名单,防止锁定可信网络和监控系统

工具与系统

  • Fail2ban 0.11+:基于日志解析的入侵防御框架,根据对任意日志文件的模式匹配来封禁 IP 地址
  • iptables/nftables:Fail2ban 封禁动作用于在网络层封锁攻击 IP 的 Linux 内核防火墙
  • 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. 将 maxretry 设为 10,findtime 为 5 分钟,首次违规的 bantime 为 1 小时
  4. 启用 recidive jail,对重复违规者将封禁时长升级为 7 天
  5. 配置 Webhook 通知至 Slack,实时可见封禁活动
  6. 为到关闭端口的 SYN 数据包添加 iptables 日志规则,检测端口扫描
  7. 创建每日报告脚本,显示封禁 IP、攻击模式和地理分布

常见陷阱:

  • maxretry 设置过低(如 1-2),导致输错 URL 的合法用户被封禁
  • 未将监控系统(Nagios、UptimeRobot)加入白名单,其健康检查可能触发过滤器
  • 忘记持久化 iptables 规则,重启后所有封禁丢失
  • 部署前未用 fail2ban-regex 测试过滤器,导致无匹配或大量误报

输出格式

## 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 |
저장한 Skills