环境:
主机名 | 地区 | OS |
BJN | 北京-京东云 | Ubuntu24 |
BJT | 北京-腾讯云 | Ubuntu24 |
JPT | 东京-腾讯云 | Ubuntu24 |
USW | 加州 | Ubuntu24 |
所有主机 SSH 连接使用 KEY 登录
被攻击现象:disabled SSH 服务
BJN:
BJT:
JPT 与 USW 的内容与 BJN 差不多, 我用文字表述一下: 造成 SSH 服务 disabled,如果我有重启主机, SSH 就不可再连接,结果是终端不能登录。
root@usw:/etc/ssh# sudo systemctl restart ssh sudo systemctl status ssh ● ssh.service - OpenBSD Secure Shell server Loaded: loaded (/usr/lib/systemd/system/ssh.service; disabled; preset: enab led) Active: active (running) since Thu 2025-06-26 12:16:28 PDT; 54ms ago TriggeredBy: ● ssh.socket Docs: man:sshd(8) man:sshd_config(5) Process: 1175 ExecStartPre=/usr/sbin/sshd -t (code=exited, status=0/SUCCESS) Main PID: 1177 (sshd) Tasks: 1 (limit: 1071) Memory: 1.2M (peak: 1.4M) CPU: 59ms CGroup: /system.slice/ssh.service └─1177 "sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups" Jun 26 12:16:28 usw systemd[1]: Starting ssh.service - OpenBSD Secure Shell server... Jun 26 12:16:28 usw sshd[1177]: Server listening on :: port 9922. Jun 26 12:16:28 usw systemd[1]: Started ssh.service - OpenBSD Secure Shell server.
root@jpt:~# systemctl status ssh ● ssh.service - OpenBSD Secure Shell server Loaded: loaded (/usr/lib/systemd/system/ssh.service; disabled; preset: enabled) Active: active (running) since Mon 2025-06-23 21:54:29 CST; 3 days ago TriggeredBy: ● ssh.socket Docs: man:sshd(8) man:sshd_config(5) Main PID: 662224 (sshd) Tasks: 1 (limit: 1888) Memory: 3.9M (peak: 15.5M) CPU: 3min 29.833s CGroup: /system.slice/ssh.service └─662224 "sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups" Jun 27 03:16:48 jpt sshd[729063]: Connection closed by invalid user jenkins 206.123.145.237 port 47252 [preauth] Jun 27 03:17:01 jpt sshd[729065]: Connection closed by authenticating user root 93.123.109.117 port 51774 [preauth] Jun 27 03:17:26 jpt sshd[729075]: Connection closed by authenticating user root 45.148.10.189 port 36270 [preauth] Jun 27 03:17:26 jpt sshd[729077]: Invalid user git from 206.123.145.237 port 34648 Jun 27 03:17:26 jpt sshd[729077]: Connection closed by invalid user git 206.123.145.237 port 34648 [preauth] Jun 27 03:18:04 jpt sshd[729086]: Connection closed by authenticating user root 206.123.145.237 port 37318 [preauth] Jun 27 03:18:41 jpt sshd[729088]: Accepted publickey for root from 12.75.157.1 port 16389 ssh2: ED25519 SHA256:jpUCXR/o4OM5+8TNsIYfpJyZWHLLxghIOe36RMVEx+0 Jun 27 03:18:41 jpt sshd[729088]: pam_unix(sshd:session): session opened for user root(uid=0) by root(uid=0) Jun 27 03:18:42 jpt sshd[729090]: Invalid user hadoop from 206.123.145.237 port 56434 Jun 27 03:18:42 jpt sshd[729090]: Connection closed by invalid user hadoop 206.123.145.237 port 56434 [preauth]
USW 在多个终端里尝试登录,10钟后,总算登录进入。
分析:
主机 JPT:仅使用运营商的防火墙
SSH 更换了默认端口 | 是 |
SSH 使用密钥登录 | 是 |
SSH 密钥有口令 | 是 |
- 攻击频率: 每分钟20-50次尝试
- 攻击持续时间: 48小时不间断
- 攻击IP数量: 50+ 个不同IP地址
- 尝试用户名: 1000+ 个不同用户名
有组织的 SSH 暴力破解
sudo journalctl -u ssh -n 1000 | grep Invalid
结果是:256
下面是:
systemctl status sshd
输出:
System information as of Fri Jun 27 03:35:35 AM CST 2025
System load: 0.0 Processes: 139
Usage of /: 68.8% of 49.10GB Users logged in: 0
Memory usage: 39% IPv4 address for eth0: 10.7.0.16
Swap usage: 0%* Strictly confined Kubernetes makes edge and IoT secure. Learn how MicroK8s
just raised the bar for easy, resilient and secure K8s cluster deployment.https://ubuntu.com/engage/secure-kubernetes-at-the-edge
*** System restart required ***
Last login: Fri Jun 27 03:18:43 2025 from 12.75.157.1
root@jpt:~# journalctl -u ssh -f
Jun 27 03:42:05 jpt sshd[729851]: Connection closed by authenticating user root 206.123.145.237 port 35220 [preauth]
Jun 27 03:42:43 jpt sshd[729853]: Invalid user teresa from 206.123.145.237 port 48576
Jun 27 03:42:43 jpt sshd[729853]: Connection closed by invalid user teresa 206.123.145.237 port 48576 [preauth]
Jun 27 03:42:49 jpt sshd[729855]: Connection closed by authenticating user root 93.123.109.118 port 32774 [preauth]
Jun 27 03:43:00 jpt sshd[729857]: Accepted publickey for root from 15.181.97.115 port 57992 ssh2: ED25519 SHA256:jpUCXR/o4OM5+8TNsIYfpJyZWHLLxghIOe36RMVEx+0
Jun 27 03:43:00 jpt sshd[729857]: pam_unix(sshd:session): session opened for user root(uid=0) by root(uid=0)
Jun 27 03:43:21 jpt sshd[729955]: Invalid user lionel from 206.123.145.237 port 41072
Jun 27 03:43:21 jpt sshd[729955]: Connection closed by invalid user lionel 206.123.145.237 port 41072 [preauth]
Jun 27 03:43:59 jpt sshd[729957]: Invalid user server11 from 206.123.145.237 port 48786
Jun 27 03:43:59 jpt sshd[729957]: Connection closed by invalid user server11 206.123.145.237 port 48786 [preauth]
Jun 27 03:44:37 jpt sshd[729966]: Connection closed by authenticating user root 206.123.145.237 port 50302 [preauth]
Jun 27 03:45:15 jpt sshd[729976]: Invalid user jgaona from 206.123.145.237 port 46572
Jun 27 03:45:15 jpt sshd[729976]: Connection closed by invalid user jgaona 206.123.145.237 port 46572 [preauth]
Jun 27 03:45:52 jpt sshd[729979]: Connection closed by authenticating user root 93.123.109.117 port 51514 [preauth]
Jun 27 03:45:53 jpt sshd[729981]: Connection closed by authenticating user messagebus 206.123.145.237 port 41498 [preauth]
Jun 27 03:46:16 jpt sshd[729988]: Accepted publickey for root from 15.181.97.115 port 58113 ssh2: ED25519 SHA256:jpUCXR/o4OM5+8TNsIYfpJyZWHLLxghIOe36RMVEx+0
Jun 27 03:46:16 jpt sshd[729988]: pam_unix(sshd:session): session opened for user root(uid=0) by root(uid=0)
Jun 27 03:46:30 jpt sshd[730084]: Invalid user colorado from 206.123.145.237 port 54534
Jun 27 03:46:31 jpt sshd[730084]: Connection closed by invalid user colorado 206.123.145.237 port 54534 [preauth]
Jun 27 03:47:08 jpt sshd[730095]: Invalid user dbird from 206.123.145.237 port 38548
Jun 27 03:47:09 jpt sshd[730095]: Connection closed by invalid user dbird 206.123.145.237 port 38548 [preauth]
Jun 27 03:47:46 jpt sshd[730099]: Invalid user 1p from 206.123.145.237 port 34708
Jun 27 03:47:46 jpt sshd[730099]: Connection closed by invalid user 1p 206.123.145.237 port 34708 [preauth]
Jun 27 03:48:05 jpt sshd[730106]: Connection closed by authenticating user root 45.148.10.189 port 55664 [preauth]
Jun 27 03:48:24 jpt sshd[730109]: Invalid user zhangxiaomei from 206.123.145.237 port 42700
Jun 27 03:48:25 jpt sshd[730109]: Connection closed by invalid user zhangxiaomei 206.123.145.237 port 42700 [preauth]
Jun 27 03:49:02 jpt sshd[730122]: Invalid user matt from 206.123.145.237 port 57886
Jun 27 03:49:02 jpt sshd[730120]: Connection closed by authenticating user root 93.123.109.127 port 58754 [preauth]
Jun 27 03:49:03 jpt sshd[730122]: Connection closed by invalid user matt 206.123.145.237 port 57886 [preauth]
Jun 27 03:49:40 jpt sshd[730125]: Invalid user tmax from 206.123.145.237 port 40428
Jun 27 03:49:40 jpt sshd[730125]: Connection closed by invalid user tmax 206.123.145.237 port 40428 [preauth]
Jun 27 03:50:18 jpt sshd[730133]: Invalid user krzysiek from 206.123.145.237 port 38650
Jun 27 03:50:19 jpt sshd[730133]: Connection closed by invalid user krzysiek 206.123.145.237 port 38650 [preauth]
Jun 27 03:50:56 jpt sshd[730136]: Invalid user oracle from 206.123.145.237 port 58568
Jun 27 03:50:56 jpt sshd[730136]: Connection closed by invalid user oracle 206.123.145.237 port 58568 [preauth]
Jun 27 03:51:34 jpt sshd[730173]: Invalid user marekg from 206.123.145.237 port 43232
Jun 27 03:51:35 jpt sshd[730173]: Connection closed by invalid user marekg 206.123.145.237 port 43232 [preauth]
Jun 27 03:52:12 jpt sshd[730190]: Invalid user jerry from 206.123.145.237 port 38580
Jun 27 03:52:12 jpt sshd[730190]: Connection closed by invalid user jerry 206.123.145.237 port 38580 [preauth]
Jun 27 03:52:40 jpt sshd[730193]: Connection closed by authenticating user root 93.123.109.128 port 51364 [preauth]
Jun 27 03:52:42 jpt sshd[730195]: Connection closed by authenticating user root 93.123.109.115 port 44990 [preauth]
Jun 27 03:52:46 jpt sshd[730197]: Connection closed by authenticating user root 45.148.10.179 port 58018 [preauth]
Jun 27 03:52:46 jpt sshd[730198]: Connection closed by authenticating user root 45.148.10.232 port 40528 [preauth]
Jun 27 03:52:51 jpt sshd[730201]: Connection closed by authenticating user mysql 206.123.145.237 port 38632 [preauth]
Jun 27 03:53:00 jpt sshd[730203]: Invalid user jenkins from 180.168.95.234 port 41486
Jun 27 03:53:00 jpt sshd[730203]: Received disconnect from 180.168.95.234 port 41486:11: Bye Bye [preauth]
Jun 27 03:53:00 jpt sshd[730203]: Disconnected from invalid user jenkins 180.168.95.234 port 41486 [preauth]
Jun 27 03:53:28 jpt sshd[730224]: Invalid user zhaoxh from 206.123.145.237 port 33774
Jun 27 03:53:29 jpt sshd[730224]: Connection closed by invalid user zhaoxh 206.123.145.237 port 33774 [preauth]
上面的引用,我加粗了前后的时间,可以看到这台主机,正在被攻击。 很显然,对方找到了我的 SSH 使用的端口号,在不断的测试。我想统计有多少,卡住了我也在等结果。
仅是 SSH 尝试登录,就有有 一百一十万次(1,103,255 次攻击)。这不是全部,其实是当前的日志,只是从:5月11日 开始记录,之前的已经打包。下面是日志截图(仅 SSH)
因为性能上没体现出下降,所以没有留意到被攻击这么久。
当前的基础保护
- 在运营商(腾讯云)的主机 防火墙只保留最少端口
- 使用 SSH + 密钥 登录
- 因为用了 iptables 维护路由策略,所有没有使用 ufw
- 没有安装 fail2ban
下载日志,进行分析
下载速度 400KB/s 够慢的,回头要找腾旭。
文件:
这么多内容,还是扔给 AI 就帮助。
1 解决方法:
1)安装 fail2ban
sudo apt update && sudo apt install fail2ban iptables-persistent -y
清除旧的配置(这台曾用 ufw + fail2ban ,但为了支持 tailscale 改用 iptables)
sudo rm -f /var/lib/fail2ban/fail2ban.sqlite3
sudo rm -f /etc/fail2ban/jail.local
2)创建 fail2ban 使用 iptables 后端工作配置
sudo tee /etc/fail2ban/jail.local << 'EOF'
[DEFAULT]
bantime = -1
findtime = 1800
maxretry = 3
backend = auto
banaction = iptables-multiport
banaction_allports = iptables-allports
[sshd]
enabled = true
port = 9922
filter = sshd
logpath = /var/log/auth.log
backend = auto
bantime = -1
findtime = 1800
maxretry = 3
action = iptables-multiport[name=SSH, port=9922, protocol=tcp]
EOF
注:
- 不要全抄运行!
- SSH 使用的是 9922 端口,以你的情况更改
- 这台用的是 iptables,没有使用 ufw,现在是“使用 iptables 后端”
- -1 要永久封禁
- 使用了 iptables链(Chain),不需要在 iptables drop ip 方法
3)查看生效(状态查看)
i. 服务状态
sudo systemctl status fail2ban
ii. 查看 ssh 状态
sudo fail2ban-client status sshd
iii. 查看所有已封禁的 IP
sudo fail2ban-client banned
iv. 查看 F2J 的配置信息
sudo fail2ban-client get sshd findtime
sudo fail2ban-client get sshd maxretry
sudo fail2ban-client get sshd bantime
v. 实时监控 SSH 攻击
sudo tail -f /var/log/auth.log | grep "Invalid user"
vi. 查看防火墙 iptables 中的 Fail2Ban 规则
sudo iptables -L f2b-sshd -n -v
sudo iptables -L INPUT -n --line-numbers | grep f2b
4)推荐使用这个 fail2ban-Chain.sh 管理脚本
#!/bin/bash
# Fail2Ban 统一管理工具
# 集成监控、分析、封禁功能
# By Dave + Claude
# Version 0.1
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
BOLD='\033[1m'
NC='\033[0m' # No Color
# 全局变量
SCRIPT_NAME="Fail2Ban统一管理工具"
VERSION="1.0"
LOG_FILE="/tmp/f2b_tool_$(date +%Y%m%d).log"
# 分隔线函数
print_separator() {
echo -e "${CYAN}==========================================================${NC}"
}
print_mini_separator() {
echo -e "${CYAN}--------------------------------------------------${NC}"
}
# 打印标题函数
print_title() {
echo -e "${BLUE}${BOLD}=== $1 ===${NC}"
}
# 记录日志函数
log_message() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE"
}
# 检查命令是否存在
check_command() {
if ! command -v $1 &> /dev/null; then
echo -e "${RED}错误: $1 命令未找到${NC}"
log_message "ERROR: $1 command not found"
exit 1
fi
}
# 检查权限
check_permissions() {
if [ "$EUID" -ne 0 ]; then
echo -e "${RED}错误: 请使用sudo运行此脚本${NC}"
exit 1
fi
}
# 显示主菜单
show_main_menu() {
clear
print_separator
echo -e "${PURPLE}${BOLD} $SCRIPT_NAME v$VERSION ${NC}"
echo -e "${PURPLE}${BOLD} $(date '+%Y-%m-%d %H:%M:%S') ${NC}"
print_separator
echo -e "${CYAN}${BOLD}主菜单:${NC}"
echo -e " ${GREEN}1)${NC} 系统状态监控"
echo -e " ${GREEN}2)${NC} 智能攻击分析"
echo -e " ${GREEN}3)${NC} 封禁管理"
echo -e " ${GREEN}4)${NC} 实时监控"
echo -e " ${GREEN}5)${NC} 配置管理"
echo -e " ${GREEN}6)${NC} 日志分析"
echo -e " ${GREEN}7)${NC} 系统维护"
echo -e " ${GREEN}8)${NC} 生成报告"
echo -e " ${YELLOW}h)${NC} 帮助信息"
echo -e " ${RED}0)${NC} 退出"
print_mini_separator
}
# 1. 系统状态监控
system_status_monitor() {
clear
print_title "系统状态监控"
log_message "Starting system status monitor"
# 检查必要命令
check_command "fail2ban-client"
check_command "iptables"
check_command "systemctl"
# Fail2Ban服务状态
print_title "Fail2Ban 服务状态"
if systemctl is-active --quiet fail2ban; then
echo -e "${GREEN}✓ Fail2Ban 服务正在运行${NC}"
uptime=$(systemctl show fail2ban --property=ActiveEnterTimestamp --value)
echo -e "启动时间: ${uptime}"
# 内存使用
memory=$(systemctl show fail2ban --property=MemoryCurrent --value)
if [ "$memory" != "[not set]" ] && [ ! -z "$memory" ]; then
memory_mb=$((memory / 1024 / 1024))
echo -e "内存使用: ${memory_mb}MB"
fi
else
echo -e "${RED}✗ Fail2Ban 服务未运行${NC}"
echo -e "${YELLOW}建议执行: sudo systemctl start fail2ban${NC}"
fi
echo
# 所有Jail总览
print_title "Jail 总览"
fail2ban_status=$(fail2ban-client status 2>/dev/null)
if [ $? -eq 0 ]; then
echo "$fail2ban_status"
else
echo -e "${RED}无法获取Fail2Ban状态${NC}"
fi
echo
# SSH Jail详细状态
print_title "SSH 防护详情"
sshd_status=$(fail2ban-client status sshd 2>/dev/null)
if [ $? -eq 0 ]; then
echo "$sshd_status"
# 提取关键信息
currently_failed=$(echo "$sshd_status" | grep "Currently failed:" | awk '{print $4}')
total_failed=$(echo "$sshd_status" | grep "Total failed:" | awk '{print $4}')
banned_count=$(echo "$sshd_status" | grep "Currently banned:" | awk '{print $4}')
total_banned=$(echo "$sshd_status" | grep "Total banned:" | awk '{print $4}')
echo
if [ "$banned_count" -gt 0 ]; then
echo -e "${RED}⚠ 当前有 $banned_count 个IP被封禁${NC}"
else
echo -e "${GREEN}✓ 当前没有IP被封禁${NC}"
fi
echo -e "统计信息: 当前失败 $currently_failed | 总计失败 $total_failed | 累计封禁 $total_banned"
else
echo -e "${YELLOW}SSH jail 未配置或未启用${NC}"
fi
echo
# 防火墙规则状态
print_title "防火墙规则检查"
# 检查f2b-sshd链
if iptables -L f2b-sshd -n -v &>/dev/null; then
echo -e "${GREEN}✓ f2b-sshd 链存在${NC}"
chain_stats=$(iptables -L f2b-sshd -n -v | grep -v "Chain\|target")
if [ ! -z "$chain_stats" ]; then
echo "链统计信息:"
echo "$chain_stats"
# 统计通过的数据包
total_packets=$(echo "$chain_stats" | awk '{sum += $1} END {print sum}')
total_bytes=$(echo "$chain_stats" | awk '{sum += $2} END {print sum}')
echo -e "总数据包: ${YELLOW}$total_packets${NC} 个, 总字节: ${YELLOW}$total_bytes${NC} 字节"
fi
else
echo -e "${RED}✗ f2b-sshd 链不存在${NC}"
fi
# 检查INPUT链中的fail2ban规则
f2b_rules=$(iptables -L INPUT -n --line-numbers | grep "f2b")
if [ ! -z "$f2b_rules" ]; then
echo -e "${GREEN}✓ INPUT链中的Fail2Ban规则:${NC}"
echo "$f2b_rules"
else
echo -e "${YELLOW}⚠ INPUT链中未找到Fail2Ban规则${NC}"
fi
echo
# 系统建议
print_title "系统建议"
# 检查配置
if [ -f "/etc/fail2ban/jail.local" ]; then
echo -e "${GREEN}✓ 自定义配置文件存在${NC}"
else
echo -e "${YELLOW}⚠ 建议创建 /etc/fail2ban/jail.local 配置文件${NC}"
fi
# 检查日志文件
if [ -f "/var/log/fail2ban.log" ]; then
log_size=$(du -h /var/log/fail2ban.log | cut -f1)
echo -e "Fail2Ban日志大小: ${log_size}"
fi
# 检查SSH端口
ssh_port=$(netstat -tlnp 2>/dev/null | grep sshd | awk '{print $4}' | cut -d: -f2 | head -1)
if [ ! -z "$ssh_port" ] && [ "$ssh_port" != "22" ]; then
echo -e "${GREEN}✓ SSH端口已修改为: $ssh_port${NC}"
else
echo -e "${YELLOW}⚠ 建议修改SSH默认端口22${NC}"
fi
log_message "System status monitor completed"
}
# 2. 智能攻击分析
intelligent_attack_analysis() {
clear
print_title "智能攻击分析"
log_message "Starting intelligent attack analysis"
# 检查Fail2Ban是否运行
if ! systemctl is-active --quiet fail2ban; then
echo -e "${RED}错误: Fail2Ban服务未运行${NC}"
return 1
fi
# 分析时间范围选择
echo -e "${CYAN}选择分析时间范围:${NC}"
echo "1) 最近1小时"
echo "2) 最近24小时"
echo "3) 最近7天"
echo "4) 自定义日期"
read -p "请选择 [1-4]: " time_choice
case $time_choice in
1)
time_filter="$(date +'%b %d %H')"
echo -e "${YELLOW}分析最近1小时的攻击...${NC}"
;;
2)
time_filter="$(date +'%b %d')"
echo -e "${YELLOW}分析最近24小时的攻击...${NC}"
;;
3)
echo -e "${YELLOW}分析最近7天的攻击...${NC}"
time_filter=""
;;
4)
read -p "请输入日期 (格式: Jun 27): " custom_date
time_filter="$custom_date"
echo -e "${YELLOW}分析 $custom_date 的攻击...${NC}"
;;
*)
time_filter="$(date +'%b %d')"
echo -e "${YELLOW}默认分析最近24小时的攻击...${NC}"
;;
esac
echo
# 分析攻击者
if [ -z "$time_filter" ]; then
# 分析所有日志
ATTACKERS=$(grep -E "Invalid user|Failed password" /var/log/auth.log | \
grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | \
sort | uniq -c | sort -nr)
else
# 分析指定时间的日志
ATTACKERS=$(grep "$time_filter" /var/log/auth.log | \
grep -E "Invalid user|Failed password" | \
grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | \
sort | uniq -c | sort -nr)
fi
if [ -z "$ATTACKERS" ]; then
echo -e "${GREEN}✓ 指定时间范围内无攻击记录${NC}"
return 0
fi
echo -e "${RED}发现以下攻击者IP (攻击次数):${NC}"
echo "$ATTACKERS" | head -20 # 显示前20个
total_attacks=$(echo "$ATTACKERS" | awk '{sum += $1} END {print sum}')
unique_ips=$(echo "$ATTACKERS" | wc -l)
echo
echo -e "${YELLOW}统计: 共 $unique_ips 个唯一IP,总计 $total_attacks 次攻击${NC}"
echo
# 检查封禁状态
print_title "封禁状态检查"
# 获取当前已封禁的IP列表
BANNED_IPS=$(fail2ban-client get sshd banip 2>/dev/null)
# 检查每个攻击者IP
NEW_ATTACKERS=""
BANNED_COUNT=0
UNBANNED_COUNT=0
while read -r count ip; do
if [ ! -z "$ip" ]; then
if echo "$BANNED_IPS" | grep -q "$ip"; then
echo -e "${GREEN}✓ $ip (已封禁, 攻击${count}次)${NC}"
((BANNED_COUNT++))
else
echo -e "${RED}✗ $ip (未封禁, 攻击${count}次)${NC}"
NEW_ATTACKERS="$NEW_ATTACKERS $ip"
((UNBANNED_COUNT++))
fi
fi
done <<< "$ATTACKERS"
echo
echo -e "${CYAN}封禁统计: 已封禁 $BANNED_COUNT 个, 未封禁 $UNBANNED_COUNT 个${NC}"
# 网段分析
print_title "网段分析"
NETWORKS=$(echo "$ATTACKERS" | awk '{print $2}' | \
sed 's/\.[0-9]*$/\.0\/24/' | sort | uniq -c | sort -nr)
if [ ! -z "$NETWORKS" ]; then
echo "可疑网段分布 (IP数量):"
echo "$NETWORKS" | head -10
echo
# 高危网段警告
echo -e "${YELLOW}高危网段 (超过5个攻击IP):${NC}"
echo "$NETWORKS" | while read count network; do
if [ "$count" -gt 5 ]; then
echo -e "${RED} $network - $count 个攻击IP${NC}"
fi
done
fi
# 地理位置分析(简单版本)
print_title "攻击源分析"
# 按IP段分析可能的地理位置
echo -e "${CYAN}主要攻击源IP段:${NC}"
echo "$ATTACKERS" | head -10 | while read count ip; do
first_octet=$(echo $ip | cut -d. -f1)
case $first_octet in
1|2|3|4|5|6|7|8|9|10|11|12|13|14|15)
region="美国/加拿大"
;;
46|47|49|58|59|60|61|103|106|111|112|113|114|115|116|117|118|119|120|121|122|123|124|125)
region="亚太地区"
;;
80|81|82|83|84|85|86|87|88|89|90|91|92|93|94|95)
region="欧洲"
;;
200|201|202|203)
region="亚太/南美"
;;
*)
region="其他地区"
;;
esac
echo -e " $ip (${count}次) - ${region}"
done
# 询问是否封禁新攻击者
if [ ! -z "$NEW_ATTACKERS" ]; then
echo
print_mini_separator
echo -e "${YELLOW}发现 $UNBANNED_COUNT 个未封禁的攻击者${NC}"
read -p "是否使用Fail2Ban封禁这些IP? [y/N]: " ban_choice
if [[ $ban_choice =~ ^[Yy]$ ]]; then
echo -e "${YELLOW}开始封禁新攻击者...${NC}"
banned_success=0
banned_failed=0
for ip in $NEW_ATTACKERS; do
echo -n "封禁 $ip ... "
if fail2ban-client set sshd banip "$ip" 2>/dev/null; then
echo -e "${GREEN}成功${NC}"
((banned_success++))
log_message "Successfully banned IP: $ip"
else
echo -e "${RED}失败${NC}"
((banned_failed++))
log_message "Failed to ban IP: $ip"
fi
done
echo
echo -e "${GREEN}封禁完成: 成功 $banned_success 个, 失败 $banned_failed 个${NC}"
fi
fi
log_message "Intelligent attack analysis completed"
}
# 3. 封禁管理
ban_management() {
clear
print_title "封禁管理"
while true; do
echo -e "${CYAN}封禁管理选项:${NC}"
echo "1) 查看封禁列表"
echo "2) 手动封禁IP"
echo "3) 解封IP"
echo "4) 批量封禁"
echo "5) 清空所有封禁"
echo "6) 封禁网段"
echo "0) 返回主菜单"
echo
read -p "请选择操作 [0-6]: " ban_choice
case $ban_choice in
1)
echo -e "${BLUE}=== 当前封禁列表 ===${NC}"
fail2ban-client status sshd
echo
banned_ips=$(fail2ban-client get sshd banip 2>/dev/null)
if [ ! -z "$banned_ips" ]; then
echo -e "${CYAN}详细封禁IP:${NC}"
echo "$banned_ips" | tr ' ' '\n' | sort
fi
;;
2)
read -p "请输入要封禁的IP地址: " ip
if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
if fail2ban-client set sshd banip "$ip" 2>/dev/null; then
echo -e "${GREEN}IP $ip 已被封禁${NC}"
log_message "Manually banned IP: $ip"
else
echo -e "${RED}封禁失败${NC}"
fi
else
echo -e "${RED}无效的IP地址格式${NC}"
fi
;;
3)
current_bans=$(fail2ban-client get sshd banip 2>/dev/null)
if [ -z "$current_bans" ]; then
echo -e "${YELLOW}当前没有被封禁的IP${NC}"
else
echo -e "${CYAN}当前被封禁的IP:${NC}"
echo "$current_bans" | tr ' ' '\n' | nl
echo
read -p "请输入要解封的IP地址: " ip
if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
if fail2ban-client set sshd unbanip "$ip" 2>/dev/null; then
echo -e "${GREEN}IP $ip 已被解封${NC}"
log_message "Manually unbanned IP: $ip"
else
echo -e "${RED}解封失败(IP可能未被封禁)${NC}"
fi
else
echo -e "${RED}无效的IP地址格式${NC}"
fi
fi
;;
4)
echo -e "${YELLOW}批量封禁模式${NC}"
echo "请输入IP地址,每行一个,输入空行结束:"
ips=()
while read -r line; do
if [ -z "$line" ]; then
break
fi
if [[ $line =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
ips+=("$line")
else
echo -e "${RED}跳过无效IP: $line${NC}"
fi
done
if [ ${#ips[@]} -gt 0 ]; then
echo -e "${YELLOW}准备封禁 ${#ips[@]} 个IP...${NC}"
for ip in "${ips[@]}"; do
if fail2ban-client set sshd banip "$ip" 2>/dev/null; then
echo -e "${GREEN}✓ $ip${NC}"
else
echo -e "${RED}✗ $ip${NC}"
fi
done
log_message "Batch banned ${#ips[@]} IPs"
fi
;;
5)
current_bans=$(fail2ban-client get sshd banip 2>/dev/null)
if [ -z "$current_bans" ]; then
echo -e "${YELLOW}当前没有被封禁的IP${NC}"
else
ban_count=$(echo "$current_bans" | wc -w)
echo -e "${RED}警告: 将解封所有 $ban_count 个IP${NC}"
read -p "确认清空所有封禁? [y/N]: " confirm
if [[ $confirm =~ ^[Yy]$ ]]; then
for ip in $current_bans; do
fail2ban-client set sshd unbanip "$ip" 2>/dev/null
done
echo -e "${GREEN}所有封禁已清空${NC}"
log_message "Cleared all bans"
fi
fi
;;
6)
read -p "请输入要封禁的网段 (如: 192.168.1.0/24): " network
if [[ $network =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/[0-9]{1,2}$ ]]; then
echo -e "${YELLOW}注意: 网段封禁将直接添加到iptables规则${NC}"
read -p "确认封禁网段 $network? [y/N]: " confirm
if [[ $confirm =~ ^[Yy]$ ]]; then
if iptables -I INPUT -s "$network" -j DROP 2>/dev/null; then
echo -e "${GREEN}网段 $network 已被封禁${NC}"
log_message "Banned network: $network"
else
echo -e "${RED}封禁网段失败${NC}"
fi
fi
else
echo -e "${RED}无效的网段格式${NC}"
fi
;;
0)
return
;;
*)
echo -e "${RED}无效选择${NC}"
;;
esac
echo
read -p "按回车键继续..."
echo
done
}
# 4. 实时监控
real_time_monitor() {
clear
print_title "实时监控"
echo -e "${CYAN}实时监控选项:${NC}"
echo "1) 监控SSH攻击"
echo "2) 监控Fail2Ban日志"
echo "3) 监控系统登录"
echo "4) 综合监控面板"
echo "0) 返回主菜单"
echo
read -p "请选择监控类型 [0-4]: " monitor_choice
case $monitor_choice in
1)
echo -e "${YELLOW}开始监控SSH攻击 (按Ctrl+C停止)${NC}"
echo -e "${CYAN}格式: 时间 | 攻击类型 | IP地址${NC}"
print_mini_separator
tail -f /var/log/auth.log | grep --line-buffered -E "Invalid user|Failed password" | \
while read line; do
echo -e "${RED}$line${NC}"
done
;;
2)
echo -e "${YELLOW}开始监控Fail2Ban日志 (按Ctrl+C停止)${NC}"
print_mini_separator
tail -f /var/log/fail2ban.log | \
while read line; do
if echo "$line" | grep -q "Ban"; then
echo -e "${RED}$line${NC}"
elif echo "$line" | grep -q "Unban"; then
echo -e "${GREEN}$line${NC}"
else
echo -e "${CYYAN}$line${NC}"
fi
done
;;
3)
echo -e "${YELLOW}开始监控系统登录 (按Ctrl+C停止)${NC}"
print_mini_separator
tail -f /var/log/auth.log | grep --line-buffered -E "Accepted|session opened" | \
while read line; do
echo -e "${GREEN}$line${NC}"
done
;;
4)
echo -e "${YELLOW}综合监控面板 (按Ctrl+C停止)${NC}"
print_mini_separator
# 创建临时文件用于监控数据
temp_dir="/tmp/f2b_monitor_$$"
mkdir -p "$temp_dir"
# 后台监控进程
tail -f /var/log/auth.log | grep --line-buffered "Invalid user" > "$temp_dir/attacks" &
attack_pid=$!
tail -f /var/log/fail2ban.log | grep --line-buffered "Ban" > "$temp_dir/bans" &
ban_pid=$!
# 监控循环
trap "kill $attack_pid $ban_pid 2>/dev/null; rm -rf $temp_dir; exit" INT
attack_count=0
ban_count=0
while true; do
clear
echo -e "${PURPLE}=== 综合监控面板 ($(date)) ===${NC}"
echo
# 当前状态
current_status=$(fail2ban-client status sshd 2>/dev/null)
if [ $? -eq 0 ]; then
echo "$current_status"
fi
echo
# 实时计数
if [ -f "$temp_dir/attacks" ]; then
new_attacks=$(wc -l < "$temp_dir/attacks" 2>/dev/null || echo 0)
if [ "$new_attacks" -gt "$attack_count" ]; then
echo -e "${RED}新攻击: $((new_attacks - attack_count)) 次${NC}"
attack_count=$new_attacks
fi
fi
if [ -f "$temp_dir/bans" ]; then
new_bans=$(wc -l < "$temp_dir/bans" 2>/dev/null || echo 0)
if [ "$new_bans" -gt "$ban_count" ]; then
echo -e "${GREEN}新封禁: $((new_bans - ban_count)) 个${NC}"
ban_count=$new_bans
fi
fi
echo -e "${CYAN}按Ctrl+C停止监控${NC}"
sleep 5
done
;;
0)
return
;;
*)
echo -e "${RED}无效选择${NC}"
;;
esac
}
# 5. 配置管理
config_management() {
clear
print_title "配置管理"
while true; do
echo -e "${CYAN}配置管理选项:${NC}"
echo "1) 查看当前配置"
echo "2) 编辑jail配置"
echo "3) 重载配置"
echo "4) 备份配置"
echo "5) 恢复配置"
echo "6) 配置向导"
echo "0) 返回主菜单"
echo
read -p "请选择操作 [0-6]: " config_choice
case $config_choice in
1)
echo -e "${BLUE}=== 当前配置 ===${NC}"
if [ -f "/etc/fail2ban/jail.local" ]; then
echo -e "${GREEN}jail.local 配置:${NC}"
cat /etc/fail2ban/jail.local
else
echo -e "${YELLOW}未找到 jail.local 配置文件${NC}"
fi
echo
echo -e "${CYAN}当前jail参数:${NC}"
fail2ban-client get sshd findtime 2>/dev/null && echo
fail2ban-client get sshd maxretry 2>/dev/null && echo
fail2ban-client get sshd bantime 2>/dev/null && echo
;;
2)
if [ -f "/etc/fail2ban/jail.local" ]; then
echo -e "${YELLOW}即将编辑 jail.local 配置文件${NC}"
read -p "按回车键继续编辑..."
nano /etc/fail2ban/jail.local
else
echo -e "${YELLOW}jail.local 不存在,是否创建? [y/N]: ${NC}"
read create_choice
if [[ $create_choice =~ ^[Yy]$ ]]; then
echo -e "${YELLOW}创建基础配置文件...${NC}"
cat > /etc/fail2ban/jail.local << 'EOF'
[DEFAULT]
bantime = -1
findtime = 600
maxretry = 1
backend = auto
banaction = iptables-multiport
banaction_allports = iptables-allports
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
backend = auto
bantime = -1
findtime = 600
maxretry = 1
action = iptables-multiport[name=SSH, port=ssh, protocol=tcp]
EOF
echo -e "${GREEN}基础配置文件已创建${NC}"
read -p "是否现在编辑? [y/N]: " edit_choice
if [[ $edit_choice =~ ^[Yy]$ ]]; then
nano /etc/fail2ban/jail.local
fi
fi
fi
;;
3)
echo -e "${YELLOW}重载Fail2Ban配置...${NC}"
if fail2ban-client reload 2>/dev/null; then
echo -e "${GREEN}配置重载成功${NC}"
log_message "Configuration reloaded"
else
echo -e "${RED}配置重载失败${NC}"
fi
;;
4)
backup_dir="/root/fail2ban_backups"
mkdir -p "$backup_dir"
backup_file="$backup_dir/fail2ban_backup_$(date +%Y%m%d_%H%M%S).tar.gz"
echo -e "${YELLOW}创建配置备份...${NC}"
tar -czf "$backup_file" /etc/fail2ban/ 2>/dev/null
if [ $? -eq 0 ]; then
echo -e "${GREEN}备份创建成功: $backup_file${NC}"
log_message "Configuration backup created: $backup_file"
else
echo -e "${RED}备份创建失败${NC}"
fi
# 显示现有备份
echo -e "${CYAN}现有备份文件:${NC}"
ls -lh "$backup_dir"/*.tar.gz 2>/dev/null || echo "无备份文件"
;;
5)
backup_dir="/root/fail2ban_backups"
if [ -d "$backup_dir" ]; then
backups=$(ls "$backup_dir"/*.tar.gz 2>/dev/null)
if [ ! -z "$backups" ]; then
echo -e "${CYAN}可用的备份文件:${NC}"
ls -1 "$backup_dir"/*.tar.gz | nl
echo
read -p "请输入要恢复的备份文件编号: " backup_num
backup_file=$(ls -1 "$backup_dir"/*.tar.gz | sed -n "${backup_num}p")
if [ ! -z "$backup_file" ]; then
echo -e "${RED}警告: 这将覆盖当前配置${NC}"
read -p "确认恢复备份? [y/N]: " confirm
if [[ $confirm =~ ^[Yy]$ ]]; then
echo -e "${YELLOW}恢复备份中...${NC}"
tar -xzf "$backup_file" -C / 2>/dev/null
if [ $? -eq 0 ]; then
echo -e "${GREEN}备份恢复成功${NC}"
echo -e "${YELLOW}重启Fail2Ban以应用恢复的配置...${NC}"
systemctl restart fail2ban
log_message "Configuration restored from: $backup_file"
else
echo -e "${RED}备份恢复失败${NC}"
fi
fi
else
echo -e "${RED}无效的备份文件编号${NC}"
fi
else
echo -e "${YELLOW}没有找到备份文件${NC}"
fi
else
echo -e "${YELLOW}备份目录不存在${NC}"
fi
;;
6)
echo -e "${BLUE}=== Fail2Ban 配置向导 ===${NC}"
echo
# SSH端口检测
ssh_port=$(netstat -tlnp 2>/dev/null | grep sshd | awk '{print $4}' | cut -d: -f2 | head -1)
if [ -z "$ssh_port" ]; then
read -p "请输入SSH端口 [默认: 22]: " ssh_port
ssh_port=${ssh_port:-22}
fi
echo -e "检测到SSH端口: ${GREEN}$ssh_port${NC}"
# 封禁时间配置
echo
echo -e "${CYAN}封禁时间配置:${NC}"
echo "1) 永久封禁 (推荐)"
echo "2) 1小时"
echo "3) 24小时"
echo "4) 7天"
echo "5) 自定义"
read -p "请选择封禁时间 [1-5]: " bantime_choice
case $bantime_choice in
1) bantime="-1" ;;
2) bantime="3600" ;;
3) bantime="86400" ;;
4) bantime="604800" ;;
5)
read -p "请输入封禁时间(秒): " bantime
if ! [[ "$bantime" =~ ^[0-9]+$ ]]; then
bantime="-1"
fi
;;
*) bantime="-1" ;;
esac
# 失败次数配置
echo
read -p "失败多少次后封禁 [默认: 1]: " maxretry
maxretry=${maxretry:-1}
# 时间窗口配置
echo
read -p "检测时间窗口(秒) [默认: 600]: " findtime
findtime=${findtime:-600}
# 生成配置
echo
echo -e "${YELLOW}生成配置文件...${NC}"
cat > /etc/fail2ban/jail.local << EOF
[DEFAULT]
bantime = $bantime
findtime = $findtime
maxretry = $maxretry
backend = auto
banaction = iptables-multiport
banaction_allports = iptables-allports
[sshd]
enabled = true
port = $ssh_port
filter = sshd
logpath = /var/log/auth.log
backend = auto
bantime = $bantime
findtime = $findtime
maxretry = $maxretry
action = iptables-multiport[name=SSH, port=$ssh_port, protocol=tcp]
EOF
echo -e "${GREEN}配置文件已生成${NC}"
echo
echo -e "${CYAN}配置摘要:${NC}"
echo "SSH端口: $ssh_port"
echo "封禁时间: $bantime 秒"
echo "失败次数: $maxretry 次"
echo "时间窗口: $findtime 秒"
echo
read -p "是否重启Fail2Ban应用新配置? [Y/n]: " restart_choice
if [[ ! $restart_choice =~ ^[Nn]$ ]]; then
echo -e "${YELLOW}重启Fail2Ban...${NC}"
systemctl restart fail2ban
echo -e "${GREEN}Fail2Ban已重启${NC}"
log_message "Applied new configuration via wizard"
fi
;;
0)
return
;;
*)
echo -e "${RED}无效选择${NC}"
;;
esac
echo
read -p "按回车键继续..."
echo
done
}
# 6. 日志分析
log_analysis() {
clear
print_title "日志分析"
while true; do
echo -e "${CYAN}日志分析选项:${NC}"
echo "1) 攻击趋势分析"
echo "2) 顶级攻击者"
echo "3) 攻击方式分析"
echo "4) 时间段分析"
echo "5) 地理分布分析"
echo "6) 导出分析报告"
echo "0) 返回主菜单"
echo
read -p "请选择分析类型 [0-6]: " analysis_choice
case $analysis_choice in
1)
echo -e "${BLUE}=== 攻击趋势分析 ===${NC}"
echo
# 按天统计攻击
echo -e "${CYAN}最近7天攻击统计:${NC}"
for i in {6..0}; do
date_str=$(date -d "$i days ago" +'%b %d')
attack_count=$(grep "$date_str" /var/log/auth.log 2>/dev/null | \
grep -c -E "Invalid user|Failed password")
echo "$date_str: $attack_count 次攻击"
done
echo
# 按小时统计今日攻击
echo -e "${CYAN}今日每小时攻击统计:${NC}"
today=$(date +'%b %d')
for hour in {00..23}; do
attack_count=$(grep "$today $hour:" /var/log/auth.log 2>/dev/null | \
grep -c -E "Invalid user|Failed password")
if [ $attack_count -gt 0 ]; then
printf "%s %s:00 - %d 次攻击\n" "$today" "$hour" "$attack_count"
fi
done
;;
2)
echo -e "${BLUE}=== 顶级攻击者分析 ===${NC}"
echo
# 最活跃的攻击IP
echo -e "${CYAN}攻击次数最多的IP (前20):${NC}"
grep -E "Invalid user|Failed password" /var/log/auth.log | \
grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | \
sort | uniq -c | sort -nr | head -20 | \
while read count ip; do
# 检查是否已被封禁
if fail2ban-client get sshd banip 2>/dev/null | grep -q "$ip"; then
status="${GREEN}(已封禁)${NC}"
else
status="${RED}(未封禁)${NC}"
fi
printf "%-6d %s %s\n" "$count" "$ip" "$status"
done
echo
# 最常被尝试的用户名
echo -e "${CYAN}最常被尝试的用户名 (前15):${NC}"
grep "Invalid user" /var/log/auth.log | \
sed 's/.*Invalid user \([^ ]*\) .*/\1/' | \
sort | uniq -c | sort -nr | head -15
;;
3)
echo -e "${BLUE}=== 攻击方式分析 ===${NC}"
echo
# 攻击类型统计
invalid_user_count=$(grep -c "Invalid user" /var/log/auth.log 2>/dev/null)
failed_password_count=$(grep -c "Failed password" /var/log/auth.log 2>/dev/null)
echo -e "${CYAN}攻击类型分布:${NC}"
echo "无效用户名攻击: $invalid_user_count 次"
echo "密码错误攻击: $failed_password_count 次"
total_attacks=$((invalid_user_count + failed_password_count))
if [ $total_attacks -gt 0 ]; then
invalid_percent=$((invalid_user_count * 100 / total_attacks))
failed_percent=$((failed_password_count * 100 / total_attacks))
echo "无效用户名占比: ${invalid_percent}%"
echo "密码错误占比: ${failed_percent}%"
fi
echo
# 常见攻击模式
echo -e "${CYAN}常见攻击用户名模式:${NC}"
grep "Invalid user" /var/log/auth.log | \
sed 's/.*Invalid user \([^ ]*\) .*/\1/' | \
grep -E '^(admin|root|user|test|guest|oracle|postgres|mysql|ftp|mail|www)' | \
sort | uniq -c | sort -nr | head -10
;;
4)
echo -e "${BLUE}=== 时间段分析 ===${NC}"
echo
read -p "请输入分析日期 (格式: Jun 27, 回车=今天): " analysis_date
if [ -z "$analysis_date" ]; then
analysis_date=$(date +'%b %d')
fi
echo -e "${CYAN}$analysis_date 的攻击时间分布:${NC}"
# 按2小时时段统计
for start_hour in 00 02 04 06 08 10 12 14 16 18 20 22; do
end_hour=$(printf "%02d" $((10#$start_hour + 2)))
if [ $end_hour -gt 23 ]; then
end_hour="23"
fi
attack_count=$(grep "$analysis_date" /var/log/auth.log 2>/dev/null | \
awk -v start="$start_hour" -v end="$end_hour" '
{
time_part = $3
split(time_part, time_array, ":")
hour = time_array[1]
if (hour >= start && hour < end) count++
}
END {print count+0}')
if [ $attack_count -gt 0 ]; then
printf "%s:00-%s:59: %d 次攻击\n" "$start_hour" "$end_hour" "$attack_count"
fi
done
;;
5)
echo -e "${BLUE}=== 地理分布分析 ===${NC}"
echo
# 简单的地理位置分析(基于IP段)
echo -e "${CYAN}攻击源地区分布 (基于IP段):${NC}"
grep -E "Invalid user|Failed password" /var/log/auth.log | \
grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | \
sort | uniq | \
while read ip; do
first_octet=$(echo $ip | cut -d. -f1)
case $first_octet in
1|2|3|4|5|6|7|8|9|10|11|12|13|14|15)
echo "北美"
;;
46|47|49|58|59|60|61|103|106|111|112|113|114|115|116|117|118|119|120|121|122|123|124|125)
echo "亚太"
;;
80|81|82|83|84|85|86|87|88|89|90|91|92|93|94|95)
echo "欧洲"
;;
200|201|202|203)
echo "南美/亚太"
;;
*)
echo "其他"
;;
esac
done | sort | uniq -c | sort -nr
echo
echo -e "${CYAN}主要攻击国家/地区 (IP段分析):${NC}"
grep -E "Invalid user|Failed password" /var/log/auth.log | \
grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | \
sort | uniq -c | sort -nr | head -10 | \
while read count ip; do
# 简单的国家判断
first_two=$(echo $ip | cut -d. -f1-2)
case $first_two in
"103.171"|"103.183"|"103.175")
country="可能来自东南亚"
;;
"206.123"|"134.122")
country="可能来自北美"
;;
"93.123"|"87.240"|"195.178")
country="可能来自欧洲"
;;
"115.246"|"119.209"|"123.59")
country="可能来自中国"
;;
*)
country="未知地区"
;;
esac
printf "%-6d %s (%s)\n" "$count" "$ip" "$country"
done
;;
6)
echo -e "${BLUE}=== 导出分析报告 ===${NC}"
report_file="/tmp/fail2ban_analysis_$(date +%Y%m%d_%H%M%S).txt"
echo -e "${YELLOW}正在生成详细分析报告...${NC}"
{
echo "Fail2Ban 安全分析报告"
echo "生成时间: $(date)"
echo "服务器: $(hostname)"
echo "========================================"
echo
echo "1. 系统状态"
echo "------------"
systemctl status fail2ban --no-pager -l
echo
fail2ban-client status sshd 2>/dev/null
echo
echo "2. 攻击统计"
echo "----------"
total_invalid=$(grep -c "Invalid user" /var/log/auth.log 2>/dev/null)
total_failed=$(grep -c "Failed password" /var/log/auth.log 2>/dev/null)
total_attacks=$((total_invalid + total_failed))
echo "总攻击次数: $total_attacks"
echo "无效用户名: $total_invalid"
echo "密码错误: $total_failed"
echo
echo "3. 顶级攻击者 (前20)"
echo "------------------"
grep -E "Invalid user|Failed password" /var/log/auth.log | \
grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | \
sort | uniq -c | sort -nr | head -20
echo
echo "4. 最近7天攻击趋势"
echo "----------------"
for i in {6..0}; do
date_str=$(date -d "$i days ago" +'%b %d')
attack_count=$(grep "$date_str" /var/log/auth.log 2>/dev/null | \
grep -c -E "Invalid user|Failed password")
echo "$date_str: $attack_count 次"
done
echo
echo "5. 常见攻击用户名"
echo "---------------"
grep "Invalid user" /var/log/auth.log | \
sed 's/.*Invalid user \([^ ]*\) .*/\1/' | \
sort | uniq -c | sort -nr | head -15
echo
echo "6. 当前封禁列表"
echo "-------------"
fail2ban-client get sshd banip 2>/dev/null | tr ' ' '\n' | sort
echo
echo "7. 防火墙规则"
echo "------------"
iptables -L INPUT -n --line-numbers | grep -E "f2b|fail2ban"
echo
} > "$report_file"
echo -e "${GREEN}报告已生成: $report_file${NC}"
echo -e "${CYAN}报告大小: $(du -h "$report_file" | cut -f1)${NC}"
read -p "是否查看报告? [y/N]: " view_choice
if [[ $view_choice =~ ^[Yy]$ ]]; then
less "$report_file"
fi
log_message "Analysis report generated: $report_file"
;;
0)
return
;;
*)
echo -e "${RED}无效选择${NC}"
;;
esac
echo
read -p "按回车键继续..."
echo
done
}
# 7. 系统维护
system_maintenance() {
clear
print_title "系统维护"
while true; do
echo -e "${CYAN}系统维护选项:${NC}"
echo "1) 服务管理"
echo "2) 日志清理"
echo "3) 规则优化"
echo "4) 性能检查"
echo "5) 安全加固"
echo "6) 系统健康检查"
echo "0) 返回主菜单"
echo
read -p "请选择维护操作 [0-6]: " maintenance_choice
case $maintenance_choice in
1)
echo -e "${BLUE}=== 服务管理 ===${NC}"
echo
echo "1) 启动Fail2Ban"
echo "2) 停止Fail2Ban"
echo "3) 重启Fail2Ban"
echo "4) 重载配置"
echo "5) 查看服务状态"
echo "6) 启用开机自启"
echo "7) 禁用开机自启"
read -p "请选择操作: " service_choice
case $service_choice in
1) systemctl start fail2ban; echo -e "${GREEN}Fail2Ban已启动${NC}" ;;
2) systemctl stop fail2ban; echo -e "${YELLOW}Fail2Ban已停止${NC}" ;;
3) systemctl restart fail2ban; echo -e "${GREEN}Fail2Ban已重启${NC}" ;;
4) fail2ban-client reload; echo -e "${GREEN}配置已重载${NC}" ;;
5) systemctl status fail2ban --no-pager -l ;;
6) systemctl enable fail2ban; echo -e "${GREEN}已启用开机自启${NC}" ;;
7) systemctl disable fail2ban; echo -e "${YELLOW}已禁用开机自启${NC}" ;;
*) echo -e "${RED}无效选择${NC}" ;;
esac
;;
2)
echo -e "${BLUE}=== 日志清理 ===${NC}"
echo
# 显示日志大小
if [ -f "/var/log/fail2ban.log" ]; then
f2b_size=$(du -h /var/log/fail2ban.log | cut -f1)
echo "Fail2Ban日志大小: $f2b_size"
fi
if [ -f "/var/log/auth.log" ]; then
auth_size=$(du -h /var/log/auth.log | cut -f1)
echo "认证日志大小: $auth_size"
fi
echo
echo "清理选项:"
echo "1) 清理Fail2Ban日志(保留最近1000行)"
echo "2) 压缩旧日志文件"
echo "3) 删除30天前的日志"
echo "4) 清理临时文件"
read -p "请选择清理操作: " clean_choice
case $clean_choice in
1)
if [ -f "/var/log/fail2ban.log" ]; then
tail -1000 /var/log/fail2ban.log > /tmp/fail2ban.log.tmp
mv /tmp/fail2ban.log.tmp /var/log/fail2ban.log
echo -e "${GREEN}Fail2Ban日志已清理${NC}"
fi
;;
2)
find /var/log -name "*.log.*" -not -name "*.gz" -exec gzip {} \;
echo -e "${GREEN}旧日志文件已压缩${NC}"
;;
3)
find /var/log -name "*.log.*" -mtime +30 -delete
echo -e "${GREEN}30天前的日志已删除${NC}"
;;
4)
rm -f /tmp/f2b_* /tmp/attack_report_* /tmp/fail2ban_analysis_*
echo -e "${GREEN}临时文件已清理${NC}"
;;
*)
echo -e "${RED}无效选择${NC}"
;;
esac
;;
3)
echo -e "${BLUE}=== 规则优化 ===${NC}"
echo
echo "1) 检查重复规则"
echo "2) 优化iptables规则顺序"
echo "3) 清理无效封禁"
echo "4) 合并相似网段"
read -p "请选择优化操作: " optimize_choice
case $optimize_choice in
1)
echo -e "${CYAN}检查iptables重复规则...${NC}"
iptables -L INPUT -n | sort | uniq -d
;;
2)
echo -e "${CYAN}当前INPUT链规则顺序:${NC}"
iptables -L INPUT -n --line-numbers | head -20
echo -e "${YELLOW}建议将Fail2Ban规则放在前面以提高效率${NC}"
;;
3)
echo -e "${CYAN}清理可能的无效封禁...${NC}"
# 这里可以添加检查IP是否仍然活跃的逻辑
banned_ips=$(fail2ban-client get sshd banip 2>/dev/null)
if [ ! -z "$banned_ips" ]; then
echo "当前封禁IP数量: $(echo $banned_ips | wc -w)"
echo "建议定期审查长期封禁的IP是否仍有必要"
fi
;;
4)
echo -e "${CYAN}分析可合并的网段...${NC}"
banned_ips=$(fail2ban-client get sshd banip 2>/dev/null)
if [ ! -z "$banned_ips" ]; then
echo "$banned_ips" | tr ' ' '\n' | \
sed 's/\.[0-9]*$/\.0\/24/' | \
sort | uniq -c | \
awk '$1 > 3 {print "可考虑封禁整个网段: " $2 " (包含 " $1 " 个IP)"}'
fi
;;
*)
echo -e "${RED}无效选择${NC}"
;;
esac
;;
4)
echo -e "${BLUE}=== 性能检查 ===${NC}"
echo
# CPU和内存使用
echo -e "${CYAN}系统资源使用:${NC}"
echo "CPU使用率: $(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)%"
echo "内存使用: $(free | grep Mem | awk '{printf "%.1f%%", $3/$2 * 100.0}')"
# Fail2Ban资源使用
if pgrep -f fail2ban-server > /dev/null; then
f2b_pid=$(pgrep -f fail2ban-server)
f2b_cpu=$(ps -p $f2b_pid -o %cpu --no-headers 2>/dev/null | tr -d ' ')
f2b_mem=$(ps -p $f2b_pid -o %mem --no-headers 2>/dev/null | tr -d ' ')
echo "Fail2Ban CPU: ${f2b_cpu}%"
echo "Fail2Ban 内存: ${f2b_mem}%"
fi
# 日志处理性能
echo
echo -e "${CYAN}日志处理性能:${NC}"
if [ -f "/var/log/auth.log" ]; then
auth_lines=$(wc -l < /var/log/auth.log)
echo "认证日志行数: $auth_lines"
# 检查日志增长速度
current_size=$(stat -c%s /var/log/auth.log 2>/dev/null || echo 0)
echo "当前日志大小: $(numfmt --to=iec $current_size)"
fi
# iptables规则数量
rule_count=$(iptables -L INPUT -n | wc -l)
echo "INPUT链规则数量: $rule_count"
if [ $rule_count -gt 100 ]; then
echo -e "${YELLOW}警告: 规则数量较多,可能影响性能${NC}"
fi
;;
5)
echo -e "${BLUE}=== 安全加固 ===${NC}"
echo
echo "1) 检查SSH配置安全性"
echo "2) 设置更严格的Fail2Ban规则"
echo "3) 启用额外的保护机制"
echo "4) 检查系统安全状态"
read -p "请选择加固操作: " security_choice
case $security_choice in
1)
echo -e "${CYAN}SSH配置安全检查:${NC}"
# 检查SSH配置
if [ -f "/etc/ssh/sshd_config" ]; then
echo "检查SSH配置文件..."
# 检查关键配置项
port_config=$(grep "^Port " /etc/ssh/sshd_config 2>/dev/null)
if [ ! -z "$port_config" ]; then
echo -e "${GREEN}✓ SSH端口已修改: $port_config${NC}"
else
echo -e "${YELLOW}⚠ 建议修改SSH默认端口${NC}"
fi
root_login=$(grep "^PermitRootLogin " /etc/ssh/sshd_config 2>/dev/null)
if echo "$root_login" | grep -q "no"; then
echo -e "${GREEN}✓ 已禁用root直接登录${NC}"
else
echo -e "${YELLOW}⚠ 建议禁用root直接登录${NC}"
fi
password_auth=$(grep "^PasswordAuthentication " /etc/ssh/sshd_config 2>/dev/null)
if echo "$password_auth" | grep -q "no"; then
echo -e "${GREEN}✓ 已禁用密码认证${NC}"
else
echo -e "${YELLOW}⚠ 建议禁用密码认证,使用密钥认证${NC}"
fi
fi
;;
2)
echo -e "${CYAN}设置更严格的Fail2Ban规则...${NC}"
cat > /etc/fail2ban/jail.local << 'EOF'
[DEFAULT]
# 更严格的配置
bantime = -1
findtime = 300
maxretry = 1
backend = auto
banaction = iptables-multiport
banaction_allports = iptables-allports
destemail = root@localhost
sendername = Fail2Ban
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
backend = auto
bantime = -1
findtime = 300
maxretry = 1
action = iptables-multiport[name=SSH, port=ssh, protocol=tcp]
sendmail-whois[name=SSH, dest=root, sender=fail2ban]
# 额外的保护
[sshd-ddos]
enabled = true
port = ssh
filter = sshd-ddos
logpath = /var/log/auth.log
bantime = 86400
findtime = 60
maxretry = 2
[apache-auth]
enabled = false
filter = apache-auth
action = iptables-multiport[name=apache-auth, port="http,https"]
logpath = /var/log/apache*/*error.log
maxretry = 6
[nginx-http-auth]
enabled = false
filter = nginx-http-auth
action = iptables-multiport[name=nginx-http-auth, port="http,https"]
logpath = /var/log/nginx/error.log
maxretry = 6
EOF
echo -e "${GREEN}严格配置已应用${NC}"
read -p "是否重启Fail2Ban应用新配置? [Y/n]: " restart_choice
if [[ ! $restart_choice =~ ^[Nn]$ ]]; then
systemctl restart fail2ban
echo -e "${GREEN}Fail2Ban已重启${NC}"
fi
;;
3)
echo -e "${CYAN}启用额外保护机制...${NC}"
# 检查并安装psad (端口扫描检测)
if ! command -v psad &> /dev/null; then
echo "psad (端口扫描检测) 未安装"
read -p "是否安装psad? [y/N]: " install_psad
if [[ $install_psad =~ ^[Yy]$ ]]; then
apt update && apt install -y psad
fi
else
echo -e "${GREEN}✓ psad 已安装${NC}"
fi
# 设置更多的iptables规则
echo "添加额外的防护规则..."
# 限制连接频率
if ! iptables -L INPUT | grep -q "recent:"; then
iptables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --set
iptables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 4 -j DROP
echo -e "${GREEN}✓ SSH连接频率限制已设置${NC}"
fi
# 保存规则
iptables-save > /etc/iptables/rules.v4 2>/dev/null
;;
4)
echo -e "${CYAN}系统安全状态检查:${NC}"
# 检查开放端口
echo "开放的网络端口:"
netstat -tlnp | grep LISTEN | head -10
# 检查最近登录
echo -e "\n最近的登录记录:"
last | head -10
# 检查sudo使用
echo -e "\n最近的sudo使用:"
grep sudo /var/log/auth.log | tail -5 2>/dev/null || echo "无sudo记录"
# 检查系统用户
echo -e "\n系统用户账户:"
awk -F: '$3 >= 1000 {print $1 " (UID:" $3 ")"}' /etc/passwd
# 检查定时任务
echo -e "\n活跃的定时任务:"
crontab -l 2>/dev/null | grep -v "^#" | head -5 || echo "无定时任务"
;;
*)
echo -e "${RED}无效选择${NC}"
;;
esac
;;
6)
echo -e "${BLUE}=== 系统健康检查 ===${NC}"
echo
health_score=0
max_score=10
# 1. Fail2Ban服务状态
if systemctl is-active --quiet fail2ban; then
echo -e "${GREEN}✓ Fail2Ban服务运行正常${NC}"
((health_score++))
else
echo -e "${RED}✗ Fail2Ban服务未运行${NC}"
fi
# 2. 配置文件存在
if [ -f "/etc/fail2ban/jail.local" ]; then
echo -e "${GREEN}✓ 自定义配置文件存在${NC}"
((health_score++))
else
echo -e "${YELLOW}⚠ 缺少自定义配置文件${NC}"
fi
# 3. SSH jail启用
if fail2ban-client status sshd &>/dev/null; then
echo -e "${GREEN}✓ SSH jail正常工作${NC}"
((health_score++))
else
echo -e "${RED}✗ SSH jail未启用${NC}"
fi
# 4. 防火墙规则
if iptables -L f2b-sshd &>/dev/null; then
echo -e "${GREEN}✓ 防火墙规则正常${NC}"
((health_score++))
else
echo -e "${YELLOW}⚠ 防火墙规则可能有问题${NC}"
fi
# 5. 日志文件可读
if [ -r "/var/log/auth.log" ]; then
echo -e "${GREEN}✓ 日志文件可正常读取${NC}"
((health_score++))
else
echo -e "${RED}✗ 无法读取日志文件${NC}"
fi
# 6. 最近有防护活动
recent_activity=$(grep "$(date +'%Y-%m-%d')" /var/log/fail2ban.log 2>/dev/null | wc -l)
if [ $recent_activity -gt 0 ]; then
echo -e "${GREEN}✓ 今日有防护活动记录${NC}"
((health_score++))
else
echo -e "${YELLOW}⚠ 今日无防护活动${NC}"
fi
# 7. 内存使用正常
mem_usage=$(free | grep Mem | awk '{printf "%.1f", $3/$2 * 100.0}')
if [ "${mem_usage%.*}" -lt 90 ]; then
echo -e "${GREEN}✓ 内存使用正常 (${mem_usage}%)${NC}"
((health_score++))
else
echo -e "${YELLOW}⚠ 内存使用偏高 (${mem_usage}%)${NC}"
fi
# 8. 磁盘空间充足
disk_usage=$(df / | tail -1 | awk '{print $5}' | sed 's/%//')
if [ $disk_usage -lt 90 ]; then
echo -e "${GREEN}✓ 磁盘空间充足 (已使用${disk_usage}%)${NC}"
((health_score++))
else
echo -e "${YELLOW}⚠ 磁盘空间不足 (已使用${disk_usage}%)${NC}"
fi
# 9. SSH端口非默认
ssh_port=$(netstat -tlnp 2>/dev/null | grep sshd | awk '{print $4}' | cut -d: -f2 | head -1)
if [ "$ssh_port" != "22" ]; then
echo -e "${GREEN}✓ SSH端口已修改为非默认端口${NC}"
((health_score++))
else
echo -e "${YELLOW}⚠ 仍使用默认SSH端口22${NC}"
fi
# 10. 最近有封禁活动
recent_bans=$(fail2ban-client status sshd 2>/dev/null | grep "Currently banned:" | awk '{print $4}')
if [ "$recent_bans" -gt 0 ]; then
echo -e "${GREEN}✓ 系统正在积极防护 (${recent_bans}个IP被封禁)${NC}"
((health_score++))
else
echo -e "${YELLOW}⚠ 当前无IP被封禁${NC}"
fi
# 健康评分
echo
echo -e "${CYAN}=== 健康评分 ===${NC}"
health_percent=$((health_score * 100 / max_score))
if [ $health_percent -ge 80 ]; then
echo -e "${GREEN}系统健康状况: 优秀 (${health_score}/${max_score}, ${health_percent}%)${NC}"
elif [ $health_percent -ge 60 ]; then
echo -e "${YELLOW}系统健康状况: 良好 (${health_score}/${max_score}, ${health_percent}%)${NC}"
else
echo -e "${RED}系统健康状况: 需要改善 (${health_score}/${max_score}, ${health_percent}%)${NC}"
fi
# 建议改进措施
if [ $health_score -lt $max_score ]; then
echo
echo -e "${CYAN}改进建议:${NC}"
if [ ! -f "/etc/fail2ban/jail.local" ]; then
echo "- 创建自定义配置文件"
fi
if [ "$ssh_port" = "22" ]; then
echo "- 修改SSH默认端口"
fi
if [ $recent_bans -eq 0 ]; then
echo "- 检查是否有攻击活动,系统可能过于安静"
fi
fi
;;
0)
return
;;
*)
echo -e "${RED}无效选择${NC}"
;;
esac
echo
read -p "按回车键继续..."
echo
done
}
# 8. 生成报告
generate_report() {
clear
print_title "生成报告"
echo -e "${CYAN}报告类型选择:${NC}"
echo "1) 快速状态报告"
echo "2) 详细安全报告"
echo "3) 攻击分析报告"
echo "4) 性能报告"
echo "5) 完整系统报告"
echo "0) 返回主菜单"
echo
read -p "请选择报告类型 [0-5]: " report_choice
case $report_choice in
1)
report_file="/tmp/f2b_quick_report_$(date +%Y%m%d_%H%M%S).txt"
echo -e "${YELLOW}生成快速状态报告...${NC}"
{
echo "Fail2Ban 快速状态报告"
echo "======================"
echo "生成时间: $(date)"
echo
systemctl status fail2ban --no-pager -l
echo
fail2ban-client status sshd 2>/dev/null
echo
echo "防火墙规则:"
iptables -L f2b-sshd -n -v 2>/dev/null
} > "$report_file"
;;
2)
report_file="/tmp/f2b_security_report_$(date +%Y%m%d_%H%M%S).txt"
echo -e "${YELLOW}生成详细安全报告...${NC}"
{
echo "Fail2Ban 详细安全报告"
echo "===================="
echo "生成时间: $(date)"
echo "服务器: $(hostname)"
echo "操作系统: $(uname -a)"
echo
echo "1. 服务状态"
echo "----------"
systemctl status fail2ban --no-pager -l
echo
echo "2. 配置信息"
echo "----------"
if [ -f "/etc/fail2ban/jail.local" ]; then
cat /etc/fail2ban/jail.local
else
echo "未找到自定义配置文件"
fi
echo
echo "3. 当前封禁状态"
echo "-------------"
fail2ban-client status sshd 2>/dev/null
echo
echo "4. 防火墙规则"
echo "------------"
iptables -L INPUT -n --line-numbers | grep -E "f2b|fail2ban"
echo
echo "5. SSH配置检查"
echo "-------------"
if [ -f "/etc/ssh/sshd_config" ]; then
grep -E "^(Port|PermitRootLogin|PasswordAuthentication)" /etc/ssh/sshd_config
else
echo "SSH配置文件未找到"
fi
echo
echo "6. 最近攻击活动"
echo "-------------"
grep "$(date +'%b %d')" /var/log/auth.log 2>/dev/null | \
grep -E "Invalid user|Failed password" | tail -10
} > "$report_file"
;;
3)
report_file="/tmp/f2b_attack_analysis_$(date +%Y%m%d_%H%M%S).txt"
echo -e "${YELLOW}生成攻击分析报告...${NC}"
{
echo "Fail2Ban 攻击分析报告"
echo "===================="
echo "生成时间: $(date)"
echo
echo "1. 攻击统计"
echo "----------"
total_invalid=$(grep -c "Invalid user" /var/log/auth.log 2>/dev/null)
total_failed=$(grep -c "Failed password" /var/log/auth.log 2>/dev/null)
total_attacks=$((total_invalid + total_failed))
echo "总攻击次数: $total_attacks"
echo "无效用户名攻击: $total_invalid"
echo "密码错误攻击: $total_failed"
echo
echo "2. 顶级攻击者"
echo "------------"
grep -E "Invalid user|Failed password" /var/log/auth.log | \
grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | \
sort | uniq -c | sort -nr | head -20
echo
echo "3. 攻击趋势(最近7天)"
echo "------------------"
for i in {6..0}; do
date_str=$(date -d "$i days ago" +'%b %d')
attack_count=$(grep "$date_str" /var/log/auth.log 2>/dev/null | \
grep -c -E "Invalid user|Failed password")
echo "$date_str: $attack_count 次攻击"
done
echo
echo "4. 常见攻击用户名"
echo "---------------"
grep "Invalid user" /var/log/auth.log | \
sed 's/.*Invalid user \([^ ]*\) .*/\1/' | \
sort | uniq -c | sort -nr | head -15
echo
echo "5. 网段分析"
echo "----------"
grep -E "Invalid user|Failed password" /var/log/auth.log | \
grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | \
sed 's/\.[0-9]*$/\.0\/24/' | sort | uniq -c | sort -nr | head -10
} > "$report_file"
;;
4)
report_file="/tmp/f2b_performance_report_$(date +%Y%m%d_%H%M%S).txt"
echo -e "${YELLOW}生成性能报告...${NC}"
{
echo "Fail2Ban 性能报告"
echo "================="
echo "生成时间: $(date)"
echo
echo "1. 系统资源使用"
echo "-------------"
echo "CPU使用率: $(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)%"
echo "内存使用: $(free | grep Mem | awk '{printf "%.1f%%", $3/$2 * 100.0}')"
echo "磁盘使用: $(df / | tail -1 | awk '{print $5}')"
echo
echo "2. Fail2Ban进程信息"
echo "-----------------"
if pgrep -f fail2ban-server > /dev/null; then
f2b_pid=$(pgrep -f fail2ban-server)
ps -p $f2b_pid -o pid,ppid,cmd,%cpu,%mem,time
else
echo "Fail2Ban进程未运行"
fi
echo
echo "3. 日志文件大小"
echo "-------------"
if [ -f "/var/log/fail2ban.log" ]; then
ls -lh /var/log/fail2ban.log
fi
if [ -f "/var/log/auth.log" ]; then
ls -lh /var/log/auth.log
fi
echo
echo "4. iptables规则统计"
echo "------------------"
total_rules=$(iptables -L INPUT -n | wc -l)
f2b_rules=$(iptables -L INPUT -n | grep -c "f2b")
echo "总规则数: $total_rules"
echo "Fail2Ban规则: $f2b_rules"
echo
echo "5. 网络连接统计"
echo "-------------"
netstat -an | awk '/^tcp/ {print $6}' | sort | uniq -c
} > "$report_file"
;;
5)
report_file="/tmp/f2b_complete_report_$(date +%Y%m%d_%H%M%S).txt"
echo -e "${YELLOW}生成完整系统报告...${NC}"
{
echo "Fail2Ban 完整系统报告"
echo "===================="
echo "生成时间: $(date)"
echo "报告版本: $VERSION"
echo "服务器信息: $(hostname) - $(uname -a)"
echo
# 包含所有其他报告的内容
echo "================================"
echo "第一部分: 系统状态"
echo "================================"
systemctl status fail2ban --no-pager -l
echo
fail2ban-client status
echo
echo "================================"
echo "第二部分: 配置信息"
echo "================================"
if [ -f "/etc/fail2ban/jail.local" ]; then
cat /etc/fail2ban/jail.local
else
echo "未找到自定义配置文件"
fi
echo
echo "================================"
echo "第三部分: 攻击分析"
echo "================================"
total_invalid=$(grep -c "Invalid user" /var/log/auth.log 2>/dev/null)
total_failed=$(grep -c "Failed password" /var/log/auth.log 2>/dev/null)
echo "攻击统计: 无效用户名 $total_invalid, 密码错误 $total_failed"
echo
echo "顶级攻击者:"
grep -E "Invalid user|Failed password" /var/log/auth.log | \
grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | \
sort | uniq -c | sort -nr | head -15
echo
echo "================================"
echo "第四部分: 防火墙状态"
echo "================================"
iptables -L INPUT -n --line-numbers
echo
echo "================================"
echo "第五部分: 系统安全"
echo "================================"
if [ -f "/etc/ssh/sshd_config" ]; then
echo "SSH配置:"
grep -E "^(Port|PermitRootLogin|PasswordAuthentication)" /etc/ssh/sshd_config
fi
echo
echo "开放端口:"
netstat -tlnp | grep LISTEN
echo
echo "================================"
echo "第六部分: 性能指标"
echo "================================"
echo "CPU: $(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)%"
echo "内存: $(free | grep Mem | awk '{printf "%.1f%%", $3/$2 * 100.0}')"
echo "磁盘: $(df / | tail -1 | awk '{print $5}')"
echo
echo "================================"
echo "第七部分: 日志摘要"
echo "================================"
echo "最近的Fail2Ban活动:"
tail -20 /var/log/fail2ban.log 2>/dev/null || echo "无Fail2Ban日志"
echo
echo "最近的攻击:"
tail -10 /var/log/auth.log 2>/dev/null | grep -E "Invalid user|Failed password" || echo "无攻击记录"
} > "$report_file"
;;
0)
return
;;
*)
echo -e "${RED}无效选择${NC}"
return
;;
esac
if [ -f "$report_file" ]; then
echo -e "${GREEN}报告生成成功: $report_file${NC}"
echo -e "${CYAN}报告大小: $(du -h "$report_file" | cut -f1)${NC}"
read -p "是否查看报告? [y/N]: " view_choice
if [[ $view_choice =~ ^[Yy]$ ]]; then
less "$report_file"
fi
read -p "是否发送报告到邮箱? [y/N]: " email_choice
if [[ $email_choice =~ ^[Yy]$ ]]; then
read -p "请输入邮箱地址: " email_addr
if command -v mail &> /dev/null; then
mail -s "Fail2Ban Report $(date)" "$email_addr" < "$report_file"
echo -e "${GREEN}报告已发送到 $email_addr${NC}"
else
echo -e "${YELLOW}mail命令未安装,无法发送邮件${NC}"
fi
fi
log_message "Report generated: $report_file"
fi
}
# 显示帮助信息
show_help() {
clear
print_title "帮助信息"
cat << EOF
${BOLD}Fail2Ban统一管理工具${NC} - 版本 $VERSION
${CYAN}功能模块说明:${NC}
${GREEN}1. 系统状态监控${NC}
- 实时查看Fail2Ban服务状态
- 监控SSH防护效果
- 检查防火墙规则
- 系统健康评估
${GREEN}2. 智能攻击分析${NC}
- 自动分析攻击日志
- 识别未封禁的攻击者
- 网段攻击模式分析
- 一键封禁新发现的攻击者
${GREEN}3. 封禁管理${NC}
- 查看当前封禁列表
- 手动封禁/解封IP
- 批量操作支持
- 网段封禁功能
${GREEN}4. 实时监控${NC}
- SSH攻击实时监控
- Fail2Ban日志监控
- 系统登录监控
- 综合监控面板
${GREEN}5. 配置管理${NC}
- 配置文件编辑
- 配置备份恢复
- 配置向导
- 参数优化建议
${GREEN}6. 日志分析${NC}
- 攻击趋势分析
- 攻击者排行
- 时间段分析
- 地理分布分析
${GREEN}7. 系统维护${NC}
- 服务管理
- 日志清理
- 性能优化
- 安全加固
${GREEN}8. 报告生成${NC}
- 多种格式报告
- 邮件发送支持
- 自动化分析
- 历史记录保存
${CYAN}使用建议:${NC}
1. 首次使用建议运行"配置向导"
2. 定期查看"系统健康检查"
3. 使用"智能攻击分析"主动发现威胁
4. 通过"实时监控"观察防护效果
${CYAN}常用快捷操作:${NC}
- 快速状态检查: 选择选项1
- 分析新攻击: 选择选项2
- 实时监控: 选择选项4
- 生成报告: 选择选项8
${YELLOW}注意事项:${NC}
- 所有操作都会记录在日志文件中
- 建议定期备份配置文件
- 修改配置后记得重启服务
- 重要操作前建议先生成报告
${CYAN}技术支持:${NC}
如有问题,请检查以下日志文件:
- Fail2Ban日志: /var/log/fail2ban.log
- 认证日志: /var/log/auth.log
- 工具日志: $LOG_FILE
EOF
read -p "按回车键返回主菜单..."
}
# 主程序循环
main_loop() {
# 检查权限
check_permissions
# 初始化日志
log_message "Fail2Ban unified management tool started"
while true; do
show_main_menu
read -p "请选择操作 [0-8,h]: " choice
case $choice in
1)
system_status_monitor
;;
2)
intelligent_attack_analysis
;;
3)
ban_management
;;
4)
real_time_monitor # Now defined above main_loop
;;
5)
config_management # Now defined above main_loop
;;
6)
log_analysis # Now defined above main_loop
;;
7)
system_maintenance # Now defined above main_loop
;;
8)
generate_report
;;
h|H)
show_help
;;
0)
echo
print_separator
echo -e "${PURPLE}感谢使用 Fail2Ban 统一管理工具!${NC}"
echo -e "${CYAN}工具日志已保存到: $LOG_FILE${NC}"
print_separator
log_message "Fail2Ban unified management tool exited"
exit 0
;;
*)
echo -e "${RED}无效选择,请重新输入${NC}"
;;
esac
# 操作完成后暂停
if [[ ! $choice =~ ^[0h]$ ]]; then
echo
read -p "按回车键返回主菜单..."
fi
done
}
# 脚本入口点
if [ "${BASH_SOURCE[0]}" == "${0}" ]; then
main_loop
fi
2 介绍 iptables-chain ( iptables 链) 概念
链是iptables中的规则集合,数据包进入系统时会按顺序通过不同的链,每个链包含多条规则,会按顺序检查进入的数据包。
工作流程:
SSH连接请求到达服务器
--> 进入INPUT链,按顺序交给 f2b-ssh-chain (rule 1)
--> 在 f2b-sshd-chain (rule 5)中做:检查IP是否在封禁列表 (是:丢弃连接)
否 --> 返回主链继续
--> 经过其它规则检查
--> 允许/拒绝
检测规则如配置文件中:
注:
- 30 分钟内,失败 3 次就触发, 永久封禁。
- 对于SSH 密钥+密码,如果密码输入错误,也会永久封禁。
- f2b 是读取 /var/log/auth.log 内容
3 验证
正在修改 maxretry 时,IP 190.80.247.133 触发规则,被禁。
4 建议(可选)
在用户登录的启动文件加入“fail2ban-client status sshd” 方便没次登录可以看到 f2b 结果,如:
主机 USW:防火墙 UFW
这个主机与 JPT 不同,运营商的防火墙服务是收费的,所以自己使用 ufw 来保护主机
查看日志:(主机在本 16 号重装过)
上图,来自 92.118.39.56 在穷举登录
下图,来自203.91.184.180 与 103.163.21.28,短时间内大量连接尝,使用特殊断开消,在“预认证阶段断开”,使用不同端口号连接(说明它正在扫描这台主机)
1. 解决方法:
1)安装 fail2ban (f2b)
sudo apt update && sudo apt install fail2ban -y
2)创建 UFW 适配的配置文件
sudo tee /etc/fail2ban/jail.local << 'EOF'
[DEFAULT]
bantime = -1
findtime = 1800
maxretry = 3
backend = auto
banaction = ufw
banaction_allports = ufw
ignoreip = 127.0.0.1/8 ::1
[sshd]
enabled = true
port = 9922
filter = sshd
logpath = /var/log/auth.log
backend = auto
bantime = -1
findtime = 1800
maxretry = 3
action = ufw[name=SSH, port=9922, protocol=tcp]
[ssh-scanner]
enabled = true
port = 9922
filter = ssh-scanner
logpath = /var/log/auth.log
maxretry = 2
bantime = -1
findtime = 600
action = ufw[name=SSH-SCANNER, port=9922, protocol=tcp]
EOF
3)创建 UFW 动作配置文件
sudo tee /etc/fail2ban/action.d/ufw.conf << 'EOF'
[Definition]
actionstart =
actionstop =
actioncheck =
actionban = ufw insert 1 deny from <ip> to any port <port>
actionunban = ufw delete deny from <ip> to any port <port>
[Init]
name = default
port = ssh
protocol = tcp
EOF
4)创建扫描检测过滤器
专为 "Normal Shutdown, Thank you for playing" 这种扫描行为, 加入又遇到的字串
[INCLUDES]
before = common.conf
[Definition]
_daemon = sshd
failregex = ^%(__prefix_line)sConnection from <HOST> port \d+ on \S+ port \d+$
^%(__prefix_line)sConnection closed by <HOST> port \d+ \[preauth\]$
^%(__prefix_line)sConnection closed by authenticating user .* <HOST> port \d+ \[preauth\]$
^%(__prefix_line)sDisconnected from .* <HOST> port \d+ \[preauth\]$
^%(__prefix_line)sReceived disconnect from <HOST> port \d+:\d+: .* \[preauth\]$
^%(__prefix_line)sbanner exchange: Connection from <HOST> port \d+: invalid format$
ignoreregex =
5)启动和测试配置
# 测试配置文件语法
sudo fail2ban-client -t
# 重启 fail2ban 服务
sudo systemctl restart fail2ban
# 检查服务状态
sudo systemctl status fail2ban
# 查看 fail2ban 状态
sudo fail2ban-client status
# 查看 SSH 监狱状态
sudo fail2ban-client status sshd
# 查看 SSH Scanner 监狱状态
sudo fail2ban-client status ssh-scanner
6)测试:模拟扫描攻击行为
第一次攻击:(规则要2次才触发封禁)
sleep 5
sudo bash -c 'echo "$(date --iso-8601=seconds) usw sshd[9999]: Received disconnect from 1.2.3.4 port 12345:11: Normal Shutdown, Thank you for playing [preauth]" >> /var/log/auth.log'
sleep 5
查看 f2b 状态
sudo fail2ban-client status ssh-scanner
sudo ufw status | grep "1.2.3.4"
第二次攻击:(将出发封禁)
sleep 5
sudo bash -c 'echo "$(date --iso-8601=seconds) usw sshd[9998]: Received disconnect from 1.2.3.4 port 54321:11: Normal Shutdown, Thank you for playing [preauth]" >> /var/log/auth.log'
sleep 10
查看 f2b 状态
sudo fail2ban-client status ssh-scanner
sudo ufw status | grep "1.2.3.4"
查看 ufw 是否添加了规则
sudo ufw status numbered | grep -A2 -B2 "1.2.3.4"
删除测试用的“封禁记录”
sudo fail2ban-client set ssh-scanner unbanip 1.2.3.4
6) 查看生效(状态查看)
i. 服务状态
sudo systemctl status fail2ban
ii. 查看 ssh scaner 状态
sudo fail2ban-client status sshd
sudo fail2ban-client status ssh-scanner
iii. 查看所有已封禁的 IP
sudo fail2ban-client banned
iv. 查看 F2J 的配置信息
sudo fail2ban-client get sshd findtime
sudo fail2ban-client get sshd maxretry
sudo fail2ban-client get sshd bantime
v. 实时监控 SSH 攻击
sudo tail -f /var/log/auth.log | grep "Invalid user"
7)fail2ban-status.sh 报告脚本
#!/bin/bash
# Fail2ban Status Display Script
# Shows banned IPs and attack statistics
# by Dave and Claude on 26Jun25
echo "================================================"
echo "🛡️ FAIL2BAN SECURITY STATUS REPORT"
echo "================================================"
# Check if fail2ban is running
if ! systemctl is-active --quiet fail2ban; then
echo "❌ Fail2ban service is not running"
exit 1
fi
# Get current time
echo "📅 Report Time: $(date '+%Y-%m-%d %H:%M:%S')"
echo ""
# Show overall status
echo "📊 Jail Overview:"
fail2ban-client status 2>/dev/null | sed 's/^/ /'
echo ""
# Get all jail list
jails=$(fail2ban-client status 2>/dev/null | grep "Jail list:" | cut -d: -f2 | tr ',' '\n' | xargs)
total_banned=0
total_failed=0
# Loop through each jail
for jail in $jails; do
if [[ -n "$jail" ]]; then
echo "🏢 Jail: $jail"
echo " ----------------------------------------"
# Get jail status
status_output=$(fail2ban-client status "$jail" 2>/dev/null)
# Extract data
currently_failed=$(echo "$status_output" | grep "Currently failed:" | awk '{print $NF}')
total_failed_jail=$(echo "$status_output" | grep "Total failed:" | awk '{print $NF}')
currently_banned=$(echo "$status_output" | grep "Currently banned:" | awk '{print $NF}')
total_banned_jail=$(echo "$status_output" | grep "Total banned:" | awk '{print $NF}')
banned_ips=$(echo "$status_output" | grep "Banned IP list:" | cut -d: -f2 | xargs)
# Display statistics
echo " 📈 Current Failed: $currently_failed"
echo " 📊 Total Failed: $total_failed_jail"
echo " 🚫 Currently Banned: $currently_banned"
echo " 📋 Total Banned: $total_banned_jail"
# Display banned IPs
if [[ -n "$banned_ips" && "$banned_ips" != "" ]]; then
echo " 🔴 Banned IPs:"
for ip in $banned_ips; do
# Try to get IP geolocation info (if whois command is available)
if command -v whois >/dev/null 2>&1; then
country=$(whois "$ip" 2>/dev/null | grep -i country | head -1 | awk '{print $2}' 2>/dev/null)
if [[ -n "$country" ]]; then
echo " 🌍 $ip ($country)"
else
echo " 🌍 $ip"
fi
else
echo " 🌍 $ip"
fi
done
else
echo " ✅ No banned IPs currently"
fi
# Accumulate statistics
total_banned=$((total_banned + currently_banned))
total_failed=$((total_failed + total_failed_jail))
echo ""
fi
done
# Display totals
echo "================================================"
echo "📊 Overall Statistics:"
echo " 🚫 Total Banned IPs: $total_banned"
echo " 📈 Total Attack Attempts: $total_failed"
echo "================================================"
# Show recent attacks (if log file exists)
if [[ -f /var/log/fail2ban.log ]]; then
echo ""
echo "🕒 Recent Ban Activity:"
echo " ----------------------------------------"
recent_bans=$(tail -50 /var/log/fail2ban.log 2>/dev/null | grep "Ban " | tail -5)
if [[ -n "$recent_bans" ]]; then
echo "$recent_bans" | while read line; do
echo " 📅 $line"
done
else
echo " ✅ No recent ban activity"
fi
fi
echo ""
echo "🛡️ Server security protection is running normally"
echo "================================================"
推荐加到 ~/.bashrc
主机 BJN BJT: 运营商防火墙+ UFW + F2B
完全照上面的 USW 配置,即可实现 UFW会自动添加deny规则
附件:记录攻击的 IP 地址
主机 BJT:
主机 BJN
主机 JPT
主机 USW
Claude 分析:
提示:
脚本需要 fail2ban-status.sh 如果不展示国家名,需要安展 whois 包