宝子放假,转眼假期已经过了一半,想着找个周末带宝子回老家住几天,大姐家的孩子周日要办升学宴,既然都回来了,不去也不合适,刚好就可以周六回老家,周日去淄博。
对象说,周日青岛会下大暴雨,还是下班之后直接回吧,不然第二天很可能走不了。
就这样,马不停蹄,下班买点东西就直接接上孩子往回走。天气预报零点的雨,在九点多到潍坊的时候就开始逐渐大了。
对象开车的时候,自己打开手机想回复下评论,但是却发现一个问题,那就是页面非常卡。刚开始还以为是网络问题,但是切到短视频却异常流畅。
瞬间有种不祥的预感,那就是服务器的 cpu 肯定又跑满了。
之前看到威言威语发的《暂时停用腾讯EdgeOne了》 ,感觉自己的系统貌似没什么太大的问题。但是,实际上是在这之前,切换到 eo 之后,也出现过一次 cpu 跑满的情况,当时重启 php 之后一切正常了,以为是偶发事件。所以也没再关注,但是这次尝试远程重启服务之后,只是瞬间缓解。几分钟之后就又卡死了,所以昨天能发评论的宝子真的都是真爱,么么哒(๑•́₃•̀๑),因为我自己都打不开我的后台。😂
这种感觉还有一个前兆,那就是后台资源库突然多了个文件。
不过这个文件看起来是某个插件的压缩包,但是描述是另外一个域名,猜测是另外一个域名传上来的。但是。搜了下这个用户不存在,所以最后直接把插件和文件一起删除了。
但是这个 cpu 跑满的感觉还是感觉是 cc,不然不至于 php 能直接占满了全部资源。
到家之后,看了下 eo 的后台没什么能配置地方。但是,通过服务器的访问记录却发现,有几个地址在频繁请求登录页面:
当然,更诡异的是这里面好几个 ip 竟然都是腾讯的海外节点。这就有点奇怪了。
尤其是 163 这个,按照常理来说,如果是 cdn 节点回源,应该不会摁着这一个地址回源,并且这个请求频率大概率会被 cdn 拦截,然而,现在的现象是不单没被拦截,还高频访问,一个地址在一秒内发起了几十个请求。这尼玛就离谱了,查了一下加速域名的节点,发现这些都不在 eo 的节点列表内。
那么,此时会合理的猜的就是 eo 的机房内或者是在某些地方的节点回源会泄露原始服务器地址,这样这一系列的请求就说的通了。这些请求本身并没有结果 cdn,所以直接是从机房发起的请求。
在回源地址泄露之后,有人通过 bot 控制了大量机房内的机器,尝试对 wp 的登录地址进行暴力破解,而这告诉 cc 也导致了家里的 mac mini 的服务器资源瞬间被耗尽了。
所以这个问题不是 eo 本身导致的,但是确实是套了 eo 的国外节点之后,有 eo 的某些请求泄露回源地址导致出现了直接针对服务器的 cc 攻击。这个攻击目标很明确,就是破解登录密码。本来想直接封锁那几个 ip,但是封锁之后发现还是不断的有新的开始尝试,于是,最新版本的工具就出现了,直接写个脚本,通过检测 nginx 访问日志,实现对 ip 动态风控。
代码如下:
#!/bin/bash # 实时监控日志文件并自动封锁恶意IP # 使用方法: sudo ./realtime_block.sh LOG_FILE="/home/wwwlogs/h4ck.org.cn.log" BLOCKED_IPS_FILE="/tmp/blocked_ips.txt" MAX_REQUESTS_PER_MINUTE=10 BLOCK_DURATION=3600 # 封锁时间(秒) DEBUG_MODE=false # 设置为true启用调试模式 QUIET_MODE=false # 设置为true启用静默模式(只显示新增封锁) ATTACK_HISTORY_FILE="/tmp/attack_history.txt" # 攻击历史记录文件 # 检查是否以root权限运行 if [ "$EUID" -ne 0 ]; then echo "请使用sudo运行此脚本" exit 1 fi # 检查inotify-tools是否安装 if ! command -v inotifywait &> /dev/null; then echo "请先安装inotify-tools:" echo "Ubuntu/Debian: sudo apt-get install inotify-tools" echo "CentOS/RHEL: sudo yum install inotify-tools" exit 1 fi # 检查日志文件是否存在 if [ ! -f "$LOG_FILE" ]; then echo "错误: 日志文件 $LOG_FILE 不存在" exit 1 fi # 创建iptables链(如果不存在) iptables -N BLOCK_MALICIOUS_IPS 2>/dev/null # 确保BLOCK_MALICIOUS_IPS链在INPUT链的最前面 iptables -C INPUT -j BLOCK_MALICIOUS_IPS 2>/dev/null || iptables -I INPUT 1 -j BLOCK_MALICIOUS_IPS # 初始化文件 touch "$BLOCKED_IPS_FILE" touch "$ATTACK_HISTORY_FILE" # 函数:检查并修复iptables配置 check_iptables_config() { echo "检查iptables配置..." # 检查BLOCK_MALICIOUS_IPS链是否存在 if ! iptables -L BLOCK_MALICIOUS_IPS >/dev/null 2>&1; then echo "创建BLOCK_MALICIOUS_IPS链..." iptables -N BLOCK_MALICIOUS_IPS fi # 检查INPUT链中是否包含BLOCK_MALICIOUS_IPS if ! iptables -C INPUT -j BLOCK_MALICIOUS_IPS 2>/dev/null; then echo "将BLOCK_MALICIOUS_IPS链插入到INPUT链的最前面..." iptables -I INPUT 1 -j BLOCK_MALICIOUS_IPS fi # 显示当前配置 echo "当前iptables配置:" iptables -L INPUT -n --line-numbers | head -10 echo "BLOCK_MALICIOUS_IPS链规则:" iptables -L BLOCK_MALICIOUS_IPS -n } # 函数:重新加载已封锁的IP到iptables reload_blocked_ips() { echo "重新加载已封锁的IP到iptables..." if [ -f "$BLOCKED_IPS_FILE" ]; then local count=0 while read -r ip; do if [ -n "$ip" ]; then # 检查iptables中是否已有此规则 if ! iptables -C BLOCK_MALICIOUS_IPS -s "$ip" -j DROP 2>/dev/null; then iptables -A BLOCK_MALICIOUS_IPS -s "$ip" -j DROP count=$((count + 1)) fi fi done < "$BLOCKED_IPS_FILE" echo "重新加载了 $count 个IP到iptables" fi } # 检查并修复iptables配置 check_iptables_config # 重新加载已封锁的IP reload_blocked_ips echo "开始实时监控日志文件: $LOG_FILE" echo "最大请求频率: $MAX_REQUESTS_PER_MINUTE 次/分钟" echo "封锁时间: $BLOCK_DURATION 秒" # 函数:封锁IP block_ip() { local ip=$1 local reason=$2 # 检查IP是否已经被封锁 if ! grep -q "^$ip$" "$BLOCKED_IPS_FILE"; then echo "$(date '+%Y-%m-%d %H:%M:%S') - 封锁IP: $ip (原因: $reason)" # 添加到iptables(确保规则正确添加) iptables -A BLOCK_MALICIOUS_IPS -s "$ip" -j DROP # 验证规则是否添加成功 if iptables -C BLOCK_MALICIOUS_IPS -s "$ip" -j DROP 2>/dev/null; then echo "$(date '+%Y-%m-%d %H:%M:%S') - 成功添加iptables规则: $ip" else echo "$(date '+%Y-%m-%d %H:%M:%S') - 警告: iptables规则添加失败: $ip" fi # 记录到文件 echo "$ip" >> "$BLOCKED_IPS_FILE" # 记录日志 echo "$(date '+%Y-%m-%d %H:%M:%S') - 封锁IP: $ip (原因: $reason)" >> /var/log/realtime_block.log else echo "$(date '+%Y-%m-%d %H:%M:%S') - IP $ip 已经被封锁" fi } # 函数:记录攻击历史 record_attack() { local ip=$1 local attack_type=$2 local timestamp=$(date +%s) echo "$ip|$attack_type|$timestamp" >> "$ATTACK_HISTORY_FILE" } # 函数:检查攻击历史 check_attack_history() { local ip=$1 local attack_type=$2 local current_time=$(date +%s) local time_window=300 # 5分钟时间窗口 # 清理过期的攻击记录 local temp_file="/tmp/temp_attack_history.txt" while IFS='|' read -r record_ip record_type record_time; do if [ $((current_time - record_time)) -lt $time_window ]; then echo "$record_ip|$record_type|$record_time" >> "$temp_file" fi done < "$ATTACK_HISTORY_FILE" mv "$temp_file" "$ATTACK_HISTORY_FILE" 2>/dev/null # 统计该IP在时间窗口内的攻击次数 local attack_count=$(grep "^$ip|" "$ATTACK_HISTORY_FILE" | wc -l) echo "$attack_count" } # 函数:分析新日志条目 analyze_new_logs() { local new_lines="$1" if [ -n "$new_lines" ]; then if [ "$DEBUG_MODE" = true ]; then echo "DEBUG: 分析新日志行数: $(echo "$new_lines" | wc -l)" fi # 统计IP请求频率 local ip_counts=$(echo "$new_lines" | awk '{print $1}' | sort | uniq -c | sort -nr) if [ "$DEBUG_MODE" = true ] && [ -n "$ip_counts" ]; then echo "DEBUG: IP统计结果:" echo "$ip_counts" fi # 检查每个IP的请求频率 while read -r count ip; do if [ -n "$ip" ] && [ "$count" -gt "$MAX_REQUESTS_PER_MINUTE" ]; then record_attack "$ip" "high_frequency" local total_attacks=$(check_attack_history "$ip" "high_frequency") if [ "$total_attacks" -gt 2 ]; then block_ip "$ip" "请求频率过高: ${count}次/分钟 (累计${total_attacks}次)" fi fi done <<< "$ip_counts" # 检查WordPress登录尝试 local wp_login_attempts=$(echo "$new_lines" | grep "POST /wp-login.php" | awk '{print $1}' | sort | uniq -c | sort -nr) if [ "$DEBUG_MODE" = true ] && [ -n "$wp_login_attempts" ]; then echo "DEBUG: WordPress登录尝试统计:" echo "$wp_login_attempts" fi if [ -n "$wp_login_attempts" ]; then while read -r count ip; do if [ -n "$ip" ]; then record_attack "$ip" "wp_login" local total_attacks=$(check_attack_history "$ip" "wp_login") if [ "$total_attacks" -gt 1 ]; then # 只要超过1次WordPress登录尝试就封锁 block_ip "$ip" "WordPress暴力破解: ${count}次尝试 (累计${total_attacks}次)" fi fi done <<< "$wp_login_attempts" fi # 检查404错误(可能的扫描行为) local error_404_attempts=$(echo "$new_lines" | grep " 404 " | awk '{print $1}' | sort | uniq -c | sort -nr) if [ -n "$error_404_attempts" ]; then while read -r count ip; do if [ -n "$ip" ] && [ "$count" -gt 5 ]; then # 降低阈值到5次404错误 record_attack "$ip" "error_404" local total_attacks=$(check_attack_history "$ip" "error_404") if [ "$total_attacks" -gt 2 ]; then block_ip "$ip" "扫描行为: ${count}次404错误 (累计${total_attacks}次)" fi fi done <<< "$error_404_attempts" fi # 检查可疑的扫描行为(访问不存在的文件) local suspicious_requests=$(echo "$new_lines" | grep -E "(\.php|\.asp|\.jsp|\.exe|\.bat|\.cmd)" | awk '{print $1}' | sort | uniq -c | sort -nr) if [ -n "$suspicious_requests" ]; then while read -r count ip; do if [ -n "$ip" ] && [ "$count" -gt 3 ]; then # 降低阈值到3次可疑请求 record_attack "$ip" "suspicious" local total_attacks=$(check_attack_history "$ip" "suspicious") if [ "$total_attacks" -gt 1 ]; then block_ip "$ip" "可疑扫描: ${count}次可疑请求 (累计${total_attacks}次)" fi fi done <<< "$suspicious_requests" fi fi } # 函数:监控日志文件变化 monitor_log_file() { echo "开始实时监控..." # 记录当前文件行数 local last_line_count=$(wc -l < "$LOG_FILE" 2>/dev/null || echo 0) # 使用inotifywait监控文件变化 inotifywait -m -e modify "$LOG_FILE" | while read -r directory events filename; do # 获取当前文件行数 local current_line_count=$(wc -l < "$LOG_FILE" 2>/dev/null || echo 0) if [ "$current_line_count" -gt "$last_line_count" ]; then if [ "$DEBUG_MODE" = true ]; then echo "DEBUG: 检测到新日志行,从第 $((last_line_count + 1)) 行开始" fi # 获取新增的日志行 local new_lines=$(tail -n +$((last_line_count + 1)) "$LOG_FILE" 2>/dev/null) if [ -n "$new_lines" ]; then # 记录分析前的封锁数量 local old_blocked_count=$(wc -l < "$BLOCKED_IPS_FILE" 2>/dev/null || echo 0) # 分析新日志 analyze_new_logs "$new_lines" # 获取分析后的封锁数量 local new_blocked_count=$(wc -l < "$BLOCKED_IPS_FILE" 2>/dev/null || echo 0) # 根据模式输出不同的信息 if [ "$new_blocked_count" -gt "$old_blocked_count" ]; then # 有新增封锁 if [ "$QUIET_MODE" = true ]; then # 静默模式:只显示新增数量 echo "$(date '+%Y-%m-%d %H:%M:%S') - 新增封锁 $(($new_blocked_count - $old_blocked_count)) 个IP" else # 正常模式:显示详细信息 echo "$(date '+%Y-%m-%d %H:%M:%S') - 新增封锁 $(($new_blocked_count - $old_blocked_count)) 个IP,总计 $new_blocked_count 个" fi elif [ "$QUIET_MODE" = false ] && [ "$DEBUG_MODE" = false ]; then # 非静默且非调试模式:显示处理状态(可选) echo "$(date '+%Y-%m-%d %H:%M:%S') - 处理日志,当前封锁 $new_blocked_count 个IP" fi fi # 更新行数 last_line_count=$current_line_count fi done } # 函数:定期清理过期封锁 cleanup_expired_blocks() { while true; do sleep 3600 # 每小时执行一次 local current_time=$(date +%s) local temp_file="/tmp/temp_blocked_ips.txt" # 重新创建封锁文件(简化处理) if [ -f "$BLOCKED_IPS_FILE" ]; then # 这里可以根据需要实现更精确的时间管理 # 目前简化处理,每小时清理一次 echo "$(date '+%Y-%m-%d %H:%M:%S') - 清理过期封锁" >> /var/log/realtime_block.log fi done } # 函数:测试模式 test_mode() { echo "测试模式: 模拟恶意请求..." # 创建测试日志条目 local test_log_entries=( "192.168.1.100 - - [$(date '+%d/%b/%Y:%H:%M:%S')] \"GET / HTTP/1.1\" 200 1234" "192.168.1.100 - - [$(date '+%d/%b/%Y:%H:%M:%S')] \"GET / HTTP/1.1\" 200 1234" "192.168.1.100 - - [$(date '+%d/%b/%Y:%H:%M:%S')] \"GET / HTTP/1.1\" 200 1234" "192.168.1.100 - - [$(date '+%d/%b/%Y:%H:%M:%S')] \"GET / HTTP/1.1\" 200 1234" "192.168.1.100 - - [$(date '+%d/%b/%Y:%H:%M:%S')] \"GET / HTTP/1.1\" 200 1234" "192.168.1.100 - - [$(date '+%d/%b/%Y:%H:%M:%S')] \"GET / HTTP/1.1\" 200 1234" "192.168.1.100 - - [$(date '+%d/%b/%Y:%H:%M:%S')] \"GET / HTTP/1.1\" 200 1234" "192.168.1.100 - - [$(date '+%d/%b/%Y:%H:%M:%S')] \"GET / HTTP/1.1\" 200 1234" "192.168.1.100 - - [$(date '+%d/%b/%Y:%H:%M:%S')] \"GET / HTTP/1.1\" 200 1234" "192.168.1.100 - - [$(date '+%d/%b/%Y:%H:%M:%S')] \"GET / HTTP/1.1\" 200 1234" "192.168.1.100 - - [$(date '+%d/%b/%Y:%H:%M:%S')] \"GET / HTTP/1.1\" 200 1234" "192.168.1.100 - - [$(date '+%d/%b/%Y:%H:%M:%S')] \"GET / HTTP/1.1\" 200 1234" ) # 将测试数据写入日志文件 for entry in "${test_log_entries[@]}"; do echo "$entry" >> "$LOG_FILE" sleep 0.1 done echo "测试完成,请检查是否封锁了IP 192.168.1.100" } # 检查命令行参数 if [ "$1" = "--test" ]; then test_mode exit 0 elif [ "$1" = "--status" ]; then echo "当前封锁状态:" if [ -f "$BLOCKED_IPS_FILE" ]; then local blocked_count=$(wc -l < "$BLOCKED_IPS_FILE" 2>/dev/null || echo 0) echo "已封锁IP数量: $blocked_count" if [ "$blocked_count" -gt 0 ]; then echo "封锁的IP列表:" cat "$BLOCKED_IPS_FILE" fi else echo "暂无封锁的IP" fi exit 0 elif [ "$1" = "--debug" ]; then DEBUG_MODE=true echo "调试模式已启用" elif [ "$1" = "--quiet" ]; then QUIET_MODE=true echo "静默模式已启用(只显示新增封锁)" elif [ "$1" = "--minimal" ]; then QUIET_MODE=true DEBUG_MODE=false echo "最小输出模式已启用(只显示新增封锁)" elif [ "$1" = "--check-iptables" ]; then echo "检查iptables配置..." check_iptables_config echo "" echo "当前封锁的IP列表:" if [ -f "$BLOCKED_IPS_FILE" ]; then cat "$BLOCKED_IPS_FILE" else echo "暂无封锁的IP" fi exit 0 elif [ "$1" = "--attack-history" ]; then echo "攻击历史记录:" if [ -f "$ATTACK_HISTORY_FILE" ]; then echo "IP地址 | 攻击类型 | 时间戳" echo "------------------------" while IFS='|' read -r ip type timestamp; do time_str=$(date -d "@$timestamp" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || echo "未知时间") echo "$ip | $type | $time_str" done < "$ATTACK_HISTORY_FILE" else echo "暂无攻击历史记录" fi exit 0 fi # 启动清理进程 cleanup_expired_blocks & CLEANUP_PID=$! # 启动监控 monitor_log_file # 清理进程 kill $CLEANUP_PID 2>/dev/null
使用说明:
### 基本使用 ```bash sudo ./realtime_block.sh ``` ### 调试模式 ```bash sudo ./realtime_block.sh --debug ``` ### 静默模式(只显示新增封锁) ```bash sudo ./realtime_block.sh --quiet ``` ### 最小输出模式(最简洁的输出) ```bash sudo ./realtime_block.sh --minimal ``` ### 查看当前状态 ```bash sudo ./realtime_block.sh --status ``` ### 测试模式 ```bash sudo ./realtime_block.sh --test ``` ## 配置参数 在脚本开头可以修改以下参数: ```bash LOG_FILE="/home/wwwlogs/h4ck.org.cn.log" # 日志文件路径 BLOCKED_IPS_FILE="/tmp/blocked_ips.txt" # 封锁IP记录文件 MAX_REQUESTS_PER_MINUTE=10 # 每分钟最大请求数 BLOCK_DURATION=3600 # 封锁时间(秒) DEBUG_MODE=false # 调试模式 QUIET_MODE=false # 静默模式 ```
最终效果:
这,文正写完了,雨也停了。

7 comments
不是偶然,也不是必然,是高产
我域名解析,迄今为止屏蔽了国外的访问,国外ip太乱了。
第一张照片好帅,最后一张照片也很帅,可是车是要撞到了树上吗
厉害。我直接放弃用了。哈哈,
我也在渐进地暂停境外及福建全境IP访问。
看来动态的站点使用 EO 都或多或少会有点问题?
看起来都是用免费的套餐加速动态站点的问题,静态站点还没有这个问题