网站被挂黑页、暗链和黑链的植入是常见的网络安全事件。暗链与黑链是指攻击者在页面或站点中隐蔽植入指向目标站点的链接或 iframe,通常指向自身流量池、广告、SEO 劫持或欺诈落地页。攻击者的目的包括操纵搜索引擎排名、增加目标站点流量,或为后续恶意跳转铺路。
异常 302 跳转与重定向链是更具隐蔽性的攻击手段。攻击者通过服务器端或前端 JS注入,触发一系列 302/301 重定向将访问者最终导向诈骗页面、恶意广告、恶意软件下载或挂马页面。常见的技术包括在 PHP、JavaScript 或 .htaccess 中植入动态判断逻辑,根据用户代理(UA)、Referer、Cookie、IP 地址或语言地域进行"选择性跳转"(cloaking)。这种技术的优势在于它可以对不同访客返回不同内容——例如,向搜索引擎爬虫返回正常页面,但向真实用户返回恶意跳转——从而大幅增加检测难度并隐匿真实来源。
攻击者获取网站控制权的主要渠道包括以下几类。
CMS 与插件漏洞是最常见的入侵口。WordPress、Joomla 等 CMS 的核心程序、插件或主题中的未修复漏洞被广泛利用。攻击者可以通过这些漏洞直接写入后门、篡改模板文件或数据库内容。
身份认证失效包括 FTP、SSH、控制面板(cPanel、宝塔等)的弱口令或泄露的登录凭据,攻击者可以直接上传 webshell 或修改网站文件。
第三方资源被劫持是一种被动注入攻击。如果网站依赖第三方广告脚本、分析脚本或其他外联 JavaScript,这些脚本的源站被入侵或被中间人劫持后,就可以向网站访客注入恶意跳转逻辑。
数据库注入通过 SQL 注入或其他数据库漏洞,攻击者可以直接向 CMS 的 options、posts、postmeta 表等关键表中写入跳转逻辑或生成隐藏的垃圾页面。这通常导致 SEO 垃圾页或关键词劫持。
应急响应需要遵循严格的流程,确保既能快速控制局面,又能完整保全证据用于事后溯源。完整的流程包括:
初步确认与隔离,判断攻击的范围和影响,快速阻止进一步的损害。证据保全,在任何修改前备份日志、文件和数据库,为后续分析和执法提供证据。靶向排查,深入查找后门、异常文件、数据库篡改和恶意定时任务。清理恢复,删除后门文件、修补漏洞、恢复干净代码。加固防御,改变所有密钥、应用补丁、部署 WAF 和持续监控。最后是回溯与报告,进行根因分析、收集 IOC(Indicators of Compromise)并制定改进建议。
首先需要验证是否真的存在异常跳转,以及这种跳转是否为选择性 cloaking(只对特定访客触发)。使用 curl 模拟不同的用户代理和请求头进行测试:
curl -I -L -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" https://example.com/
用普通浏览器的 UA 访问,看看是否返回正常内容。
curl -I -L -A "Googlebot/2.1 (+http://www.google.com/bot.html)" https://example.com/
用谷歌爬虫的 UA 访问,对比返回的内容和重定向。
curl -I -L -e "https://www.baidu.com" https://example.com/
模拟来自百度搜索的访问,看看 Referer 是否会影响返回结果。
curl -I -L -A "Baiduspider/2.0" https://example.com/
curl -I -L -A "Mozilla/5.0 (compatible; Bingbot/2.0)" https://example.com/
试试其他常见爬虫的 UA。
如果观察到不同 UA 返回不同的重定向目标或状态码,特别是正常浏览器被重定向而爬虫返回 200 正常页面,这明确表示存在选择性 cloaking。攻击者使用这种技术规避搜索引擎和安全检测工具的发现。
为了并行测试多种 UA 并快速得出结论,可以使用以下脚本:
#!/bin/bash
URL="$1"
echo "=== Cloaking Detection for $URL ==="
for ua in \
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" \
"Googlebot/2.1; +http://www.google.com/bot.html" \
"Baiduspider" \
"facebookexternalhit/1.1" \
"Mozilla/5.0 (compatible; Bingbot/2.0; +http://www.bing.com/bingbot.htm)"; do
loc=$(curl -sSLk -A "$ua" -I "$URL" 2>/dev/null | grep -i ^location: | head -1 | awk '{print $2}' | tr -d '\r')
code=$(curl -sSLk -A "$ua" -o /dev/null -w "%{http_code}" "$URL" 2>/dev/null)
echo "UA: $(echo $ua | cut -c1-50) | HTTP $code | Location: ${loc:0:60}"
done
脚本会逐个测试不同的 UA,输出每个 UA 的 HTTP 状态码和重定向地址。如果发现不同 UA 的返回结果差异很大,基本能确认存在 cloaking。
确认被攻击后,需要立即隔离,防止更多访客遭受伤害。
如果网站托管在公有云(阿里云、腾讯云、AWS 等),优先将流量切换到维护页面,或启用云 WAF 的"网站防护模式"和"Under Attack Mode"。
对于自建服务器,可以临时在 Nginx/Apache 配置中仅允许特定 IP(如自己的办公网段)或内网访问,其他访问者看到维护提示。通过 basic auth(HTTP 基本认证)阻断外部访问也是快速方案。
server {
listen 80;
server_name example.com;
allow 10.0.0.0/8;
allow 203.0.113.10;
deny all;
auth_basic "Under Maintenance";
auth_basic_user_file /etc/nginx/.htpasswd;
}
临时在 Nginx 中添加上面这个配置块。allow指令只允许特定 IP,其他流量直接返回 403。同时可以加上 basic auth,让有权限的人输入密码访问。
此时应将首页或 404 页面指向简单的维护提示页面,例如"网站正在进行安全维护,请稍后访问"。
在任何清理行为之前,必须完整保全现场证据,这对后续溯源、执法和审计至关重要。
访问日志(Nginx/Apache 的 access.log)、错误日志(error.log)、CDN 日志(Cloudflare、阿里云 CDN 等)以及 WAF 日志都需要被完整备份。建议将涉及事件时间窗口(如过去 7-30 天)的原始日志打包并上传到只读存档(例如对象存储)或离线媒体。
grep "$(date -d '24 hours ago' +'%d/%b/%Y:%H')" /var/log/nginx/access.log > /tmp/incident_access_24h.log
用 grep 按时间提取过去 24 小时的日志,基于 Nginx 默认的日期格式[day/month/year:hour:...]。
awk '$4 >= "[26/Nov/2025:00:" && $4 <= "[26/Nov/2025:23:"' /var/log/nginx/access.log > /tmp/incident_access_20251126.log
或者用 awk 的比较操作符按日期范围提取,这个方法更灵活。
tar czf /tmp/logs_backup_20251126.tgz /var/log/nginx/ /var/log/apache2/ 2>/dev/null || true
打包备份日志到压缩文件中,2>/dev/null忽略不存在的目录错误。
使用 curl 保存当前网站返回的完整响应头和页面内容,包括所有跳转链:
curl -v -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" https://example.com/ 2>&1 | tee /tmp/response_full.txt
-v打印详细信息,2>&1把 stderr 合并到 stdout,tee同时输出到屏幕和文件。
curl -D /tmp/headers.txt -o /tmp/body.html -L https://example.com/
-D保存响应头,-o保存响应体,-L自动跟随重定向。执行后得到的 headers.txt 和 body.html 分别记录了完整的 HTTP 头和页面内容。
curl -L -v https://example.com/ 2>&1 | grep -E "^(>|<|Location:)"
跟踪完整的重定向链,只输出请求行、响应行和 Location 头,便于快速查看跳转目标。
导出当前数据库状态,保留完整的数据备份和二进制日志(binlog),用于日后溯源:
mysqldump -u root -p --single-transaction --routines --triggers --events example_db > /tmp/example_db_snapshot_$(date +%s).sql
--single-transaction保证备份的一致性(InnoDB 会获取快照)。--routines --triggers --events导出存储过程、触发器和定时事件。文件名后面加时间戳便于版本管理。
mysqldump -u root -p --single-transaction --all-databases > /tmp/all_databases_backup_$(date +%s).sql
如果需要备份整个 MySQL 实例,用--all-databases。
mysql -u root -p -e "SHOW BINARY LOGS; SHOW MASTER STATUS\G"
查看 binlog 位置,这个信息可以帮助恢复时间线或进行增量恢复。
对 web 根目录、配置文件、定时任务进行完整备份:
tar czf /tmp/webroot_backup_$(date +%s).tgz /var/www/ --exclude="node_modules" --exclude=".git"
备份整个 web 根目录,排除 node_modules 和 .git 等大文件夹以节省空间和时间。
find /var/www -type f -printf '%TY-%Tm-%Td %TH:%TM:%TS %p\n' | sort -r | head -200 > /tmp/recent_files.txt
列出最近修改的 200 个文件,按修改时间倒序排列。这能快速看出哪些文件在攻击期间被篡改。
tar czf /tmp/configs_backup.tgz /etc/nginx /etc/apache2 /etc/php /etc/mysql 2>/dev/null || true
备份关键的系统配置目录。有些目录可能不存在,所以用2>/dev/null忽略错误。
crontab -l > /tmp/crontab_current.txt
for user in /home/*/; do
sudo crontab -l -u $(basename "$user") > /tmp/crontab_$(basename "$user").txt 2>/dev/null || true
done
导出当前用户和所有系统用户的 crontab,看看是否有被植入的恶意定时任务。
如果怀疑存在内存驻留的恶意代码或 rootkit,需要在关闭服务前进行内存取证:
ps auxf > /tmp/processes.txt
lsof -i > /tmp/network_connections.txt
导出当前的进程树和网络连接,便于事后分析。
ps aux | grep -E "php|apache|nginx"
快速查看 web 相关进程是否异常。
php -r 'if(extension_loaded("Zend OPcache")){$status=opcache_get_status();if($status){echo "=== Cached Scripts ===\n";foreach($status["scripts"] as $k=>$v){echo "$k | mtime:" . $v["timestamp"] . "\n";}}}' > /tmp/opcache_status.txt 2>/dev/null || true
如果 PHP 安装了 opcache,这个命令能导出所有缓存的脚本及其修改时间。重启 PHP-FPM 前一定要检查这个,因为 opcache 会缓存恶意代码在内存中。
定位恶意代码是应急的关键环节。需要从多个角度——日志、页面源码、服务器文件、数据库——进行交叉验证。
访问日志是最直接的证据来源。查找返回 3xx 重定向状态码的访问记录,并分析其特征:
awk '$9 ~ /^30[127]$/' /var/log/nginx/access.log | tail -n 500 > /tmp/redirects.log
cat /tmp/redirects.log | head -20
提取所有返回 302/301/307 的请求,Nginx 日志中第 9 列是 HTTP 状态码。
awk '$9 ~ /^30[127]$/ {print}' /var/log/nginx/access.log | grep Location | awk -F'Location: ' '{print $2}' | sort | uniq -c | sort -rn | head -20
统计重定向最频繁的目标 URL,看看有没有几个明确的恶意站点。
awk '$9 ~ /^30[127]$/ {print $4, $1, $12}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -30
按时间、IP、UA 统计,快速识别攻击模式。这样能看出是哪个 IP、哪个时间段、哪个 UA 产生了大量重定向。
关键观察点包括:
Referer 和 UA 模式:如果重定向请求的 Referer 来自谷歌、百度等搜索引擎,但访客 IP 不属于这些搜索引擎的 IP 段,这是 cloaking 的典型信号。
重定向链:通过 curl -v 跟踪完整的重定向链,记录每一步的 URL 和响应码。
时间聚集:短时间内大量 302 响应可能表示攻击刚发生或仍在进行中。
下载受影响的页面源码,搜索可疑脚本和特征:
curl -s https://example.com/ > /tmp/homepage.html
curl -s https://example.com/about > /tmp/about.html
下载首页和几个关键页面,保存为本地文件方便分析。
grep -E "(eval\(|atob\(|fromCharCode|document\.location|window\.location|location\.href|base64_decode|base64_encode|setTimeout.*location)" /tmp/homepage.html
查找常见的恶意 JavaScript 函数和关键词。这些是动态跳转的常用手段。
grep -r --include="*.php" --include="*.js" --include="*.html" \
-E "(eval\(|atob\(|document\.location|window\.location|location\.href)" /var/www/html | head -50
在整个 web 根目录递归查找这些危险字符串。
特别需要关注:
隐藏在页脚或 header 的脚本:很多注入脚本被放在 footer.php、header.php 或通过 wp_head 钩子注入。攻击者知道开发者通常不会仔细检查这些文件。
Base64 编码内容:<script>eval(atob('...'))</script>这样的模式是常见的混淆手段。如果看到奇怪的 Base64 字符串,可以用在线工具或命令行解码看看。
第三方脚本加载:检查所有<script src="...">和<iframe>标签,验证这些外链源是否可信。
查找可疑的 PHP 或其他脚本文件,特别是包含 eval、base64_decode、gzinflate 等危险函数的文件:
find /var/www -type f -name "*.php" -exec grep -l \
-E "(base64_decode|eval|gzinflate|gzuncompress|str_rot13|preg_replace.*\/e|create_function|assert|system|passthru|shell_exec|exec|popen)" {} \; | head -50
逐个扫描所有 PHP 文件,看哪些包含了危险函数。输出包含这些函数的文件列表。
find /var/www -type f -name "*.php" -mtime -7 | sort
列出最近 7 天内修改或新建的 PHP 文件。如果看到奇怪的新文件,很可能就是 webshell。
find /var/www -type f ! -user www-data ! -user nginx ! -user root 2>/dev/null
查找文件拥有者不符的文件。web 文件应该属于 www-data、nginx 或 root,其他用户所有的文件很可疑。
ls -la /var/www/html/index.php
ls -la /var/www/html/.htaccess
ls -la /var/www/html/wp-config.php
cat /var/www/html/.htaccess | head -30
检查常被篡改的关键文件,看看修改时间、文件大小和内容是否异常。
常见隐匿特征:
文件名伪装:webshell 可能被命名为图片(1.php.jpg)、文本(config.php.txt)或普通字符串。
编码混淆:使用\x十六进制编码(\x65\x76\x61\x6C代表eval)或 rot13 等变换来躲避文本搜索。
时间戳篡改:攻击者可能使用touch改变文件修改时间以躲避日期排序。
这是近些年最常见的隐藏方式。攻击者直接在 web 服务器配置中植入重定向规则,这样不需要修改 PHP 文件,也更难被发现:
grep -rn "RewriteRule\|RedirectMatch\|Redirect 302\|SetEnvIfNoCase" /var/www --include=".htaccess"
查找 Apache .htaccess 中的恶意重定向规则。
grep -rn "return 30[127]\|rewrite.*http\|location.*proxy_pass" /etc/nginx/
查找 Nginx 配置文件中的异常重定向。
grep -rn "google\|bot\|spider\|baidu\|yandex\|bing" /var/www --include=".htaccess" -A 2 -B 2
grep -rn "google\|bot\|spider\|baidu" /etc/nginx/ -A 2 -B 2
查找针对特定 UA 或搜索引擎的条件重定向,通常这是 cloaking 的核心逻辑。
典型的恶意 .htaccess 看起来像这样:
RewriteCond %{HTTP_USER_AGENT} .*google.* [NC]
RewriteRule ^(.*)$ https://evil.example.com/casino.php [R=302,L]
这条规则说的是:如果 UA 包含 "google"(不区分大小写),就把所有请求重定向到https://evil.example.com/casino.php。
许多 CMS 被破坏后,恶意代码被植入数据库而非文件系统,使得文件层检查无法发现。特别是 WordPress 容易被注入到 options 表和 posts 表:
SELECT ID, post_title, post_content FROM wp_posts
WHERE post_content LIKE '%<script%'
OR post_content LIKE '%iframe%'
OR post_content LIKE '%base64%'
LIMIT 50;
搜索 posts 表中包含可疑内容的文章。如果是被劫持的网站,通常会看到大量的文章内容被插入了脚本或 iframe。
SELECT option_name, option_value FROM wp_options
WHERE option_value LIKE '%<script%'
OR option_value LIKE '%eval%'
OR option_value LIKE '%location%'
LIMIT 50;
搜索 wp_options 表中的异常选项。攻击者有时会在这里植入重定向逻辑或修改关键配置。
SELECT ID, post_title, post_status FROM wp_posts
WHERE (post_status='draft' OR post_status='private' OR post_status='trash')
AND (post_content LIKE '%redirect%' OR post_content LIKE '%<script%')
LIMIT 100;
查找被隐藏的垃圾页面。攻击者为了逃避肉眼检查,通常会把恶意文章设置为 draft(草稿)或 private(私密),甚至放进 trash(垃圾箱)。
SELECT post_id, meta_key, meta_value FROM wp_postmeta
WHERE meta_value LIKE '%http%eval%'
OR meta_value LIKE '%location.href%'
LIMIT 50;
检查 postmeta 中是否有异常数据。postmeta 存储文章的元数据,有时也会被注入恶意内容。
现代 webshell 使用变量拼接、回调函数(call_user_func)、lambda 表达式等方式绕过简单的关键词匹配。推荐以下更强大的检测:
find /var/www -type f -name "*.php" -exec grep -EHn \
'(::|->|\\x|\\0|\\147|gz(inflate|decode)|str_rot13|file_get_contents.*\$_|curl_exec|system|passthru|shell_exec|popen|assert|preg_replace.*e|create_function|array_map|usort|call_user_func|array_filter|\\x65\\x76\\x61\\x6C)' {} \; | grep -v "^Binary" | head -50
这是个超级加强版的检测命令。它不仅查找 eval,还查找call_user_func、array_map这样的回调函数。这些函数经常被用来执行恶意代码,但不被普通关键词搜索捕获。
grep -rn "call_user_func\|array_map\|array_filter\|usort" /var/www --include="*.php" | grep -v "/vendor/" | head -20
专门查找 PHP 回调型 webshell。这些函数允许动态执行代码,危险系数很高。
strings /var/www/html/*.php | grep -E "eval|base64_decode|gzinflate" | head -20
用strings命令提取二进制文件中的可打印字符串,有时能发现被隐藏在注释或数据中的恶意代码。
清理必须遵循以下顺序和原则:先保全证据,再进行清理;确保完全清除恶意代码,同时修补漏洞防止复现;在清理过程中保持服务的可控状态。
在进行任何清理前,保持网站处于隔离或只读状态,防止恶意代码继续传播或自我修复:
systemctl stop php-fpm
systemctl stop apache2
先把应用服务停掉,这样就没有任何代码在执行了。
location ~ \.php$ {
deny all;
}
或者在 Nginx 中临时禁止 PHP 执行。
从官方或备份恢复干净的 CMS 文件、主题、插件:
wp core download --allow-root --force
wp plugin install --all --allow-root
对于 WordPress,用 WP-CLI 重新下载核心文件和官方插件。--force表示覆盖现有文件。
diff -r /backup/www_clean /var/www/html | head -50
比对干净备份和现有文件,看看有多少差异。这能帮你确认备份是否真的干净。
cp /backup/www_clean/index.php /var/www/html/
cp /backup/www_clean/wp-config.php /var/www/html/
cp /backup/www_clean/.htaccess /var/www/html/ 2>/dev/null || true
逐文件恢复关键文件。这比全盘复制更安全,因为你能控制哪些文件被覆盖。
基于前面的排查结果,删除所有确认的恶意文件,并验证权限:
rm /var/www/html/shell.php
rm /var/www/html/admin/upload/shell.php
删除确认的 webshell。
find /var/www/html/uploads -type f -name "*.php" -delete
find /var/www/html/wp-content -type f -name "*.php" ! -path "*/plugins/*" ! -path "*/themes/*" -delete
清理上传目录中的可疑 PHP 文件。这里要注意别误删插件和主题目录下的合法 PHP 文件。
chmod -R 644 /var/www/html/*.html
chmod -R 644 /var/www/html/*.php
chmod -R 755 /var/www/html
检查文件权限。web 文件通常应该是 644(拥有者可读写,其他人只读),目录是 755(拥有者可读写执行,其他人可读执行)。
备份后,执行以下数据库清理。这个必须很小心,先在测试环境验证,然后在生产环境执行:
DELETE FROM wp_posts
WHERE post_content REGEXP '<script.*eval|iframe.*casino|base64_decode'
LIMIT 100;
删除 posts 表中明显包含恶意脚本的文章。用 LIMIT 限制一次删除数量,防止一次性删掉太多。
UPDATE wp_options
SET option_value = 'https://yourdomain.com'
WHERE option_name IN ('siteurl','home');
恢复被篡改的 siteurl 和 home 选项。如果这两个被修改,WordPress 会被重定向到恶意站点。
DELETE FROM wp_postmeta
WHERE meta_value REGEXP 'casino|viagra|porn|eval'
LIMIT 100;
删除包含异常关键词的 postmeta。这些通常是 SEO 垃圾内容。
攻击者获得了网站访问权限,必须立即更换所有密码和密钥,启用多因素认证:
wp user update 1 --prompt=user_pass --allow-root
用 WP-CLI 交互式地更改 WordPress 管理员密码。
mysql -u root -p -e "ALTER USER 'wp_user'@'localhost' IDENTIFIED BY 'new_strong_password';"
更改数据库用户密码。注意数据库密码必须在 wp-config.php 中同时更新。
passwd webuser
更改 FTP/SFTP 用户密码。
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N "passphrase"
生成新的 SSH 密钥对。ed25519 是目前最安全的算法。
wp core update --allow-root
wp theme update --all --allow-root
wp plugin update --all --allow-root
更新 WordPress 核心、主题、插件。这会修复已知的安全漏洞。
apt-get update && apt-get upgrade -y
更新系统包。这很关键,很多漏洞是操作系统级的。
apt-get install --only-upgrade php-fpm php-mysql php-curl
更新 PHP 等应用包。
WAF 与 CDN 配置
启用云 WAF或开源 WAF,配置针对异常重定向的规则。例如在 Cloudflare 中设置:
创建 WAF 规则:当请求返回 302 且频率异常高时触发告警或拦截。启用 Under Attack Mode,对所有访客进行 JavaScript 挑战。针对 UA 异常(Referer 来自搜索引擎但 IP 不符)的请求进行标记。
SecRule RESPONSE_STATUS "@rx 30[127]" "id:1001,phase:3,block,msg:'Suspicious redirect detected'"
SecRule REQUEST_HEADERS:User-Agent "@rx Googlebot" "chain,id:1002"
SecRule GEOIP:COUNTRY_CODE "!@rx US|CN" "block,msg:'Googlebot from unexpected country'"
这是 Nginx + ModSecurity 的规则示例。第一条规则检查响应码是否为 302/301/307,如果是则阻止。第二条规则检查是否有 Googlebot,并且 IP 地址不在预期的国家范围内,如果是则阻止。
文件完整性监控(FIM)
部署文件完整性检测工具,定期扫描关键文件的哈希值,及时发现篡改:
aide --init
mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db
初始化 AIDE(Advanced Intrusion Detection Environment)数据库。
0 2 * * * aide --check | mail -s "AIDE Report" [email protected]
加入 crontab,每天凌晨 2 点检查文件完整性,如果发现改动就发邮件通知。
日志监控与告警
在 SIEM(如 ELK、Splunk)中配置告警规则。关键告警包括:短时间内同一 URL 出现大量 302;特异的 UA 与 Referer 组合;同一 IP 发出大量不同 UA 的请求;文件或数据库异常更改。
对于使用阿里云、腾讯云、Cloudflare 等云服务的用户,有快速加固方案。
Cloudflare 一键防护
启用 "Under Attack Mode"。创建页面规则:优先级最高,设置"挑战"或"阻止"。添加 WAF 规则:拦截所有来自国外的 Googlebot,拦截 302 高频发生。
阿里云 WAF 配置
开启"网站防篡改"功能。创建 CC 防护规则:限制单 IP 单时间窗口的请求数。精准访问控制:添加规则"UA 包含 Googlebot 且来源 IP 非谷歌网段"→拒绝。
Nginx + Lua 脚本(开源方案,防选择性跳转)
local ua = ngx.var.http_user_agent or ""
local ref = ngx.var.http_referer or ""
local remote_ip = ngx.var.remote_addr
local google_ips = {
"66.249.64.0/19",
"64.233.160.0/19",
"2001:4860:4000::/36"
}
if string.find(ua, "Googlebot") then
if not (string.find(remote_ip, "66.249") or string.find(remote_ip, "64.233")) then
ngx.exit(403)
end
end
这个 Lua 脚本检查访问者是否声称是 Googlebot,但 IP 地址不在谷歌的网段内。如果检测到这样的矛盾,就返回 403 拒绝访问。
access_by_lua_file /etc/nginx/lua/anti_cloaking.lua;
在 Nginx 配置中引入这个脚本。
结合多个日志源重建攻击时间线,找出关键的入侵时刻:
cat /var/log/nginx/access.log /var/log/secure /var/log/vsftpd.log | \
grep -E "2025-11-2[0-5]" | sort | uniq > /tmp/timeline.log
把多个日志文件合并,按时间排序,便于查看整个事件链。
ls -la /var/www/html --sort=time | head -20
stat /var/www/html/shell.php
查看文件的修改时间。stat能显示更详细的时间戳信息。
grep "Failed\|Accepted" /var/log/secure | tail -100
查看 SSH 登录失败与成功记录。大量的失败可能说明有人在暴力破解。
查找恶意的外联连接和通信:
netstat -plant | grep ESTABLISHED
查看当前建立的网络连接。如果有奇怪的长连接,可能是 C2(命令与控制服务器)。
tcpdump -i any -nn 'tcp port 443' -w /tmp/capture.pcap
如果需要更详细的网络分析,可以用 tcpdump 抓包。
收集可作为告警规则的指标。这些信息对企业安全团队非常有价值,可以用来检测和阻止类似的攻击。
URL Indicators:
- https://evil.example.com/casino.php
- https://malicious.com/redirect_gate
- 所有重定向链中的中间 URL
File Indicators:
- shell.php (MD5: abc123...)
- 隐藏的 webshell 文件名模式
IP/Domain Indicators:
- 攻击者 C2 服务器 IP
- 恶意重定向目标域名
权限最小化:Web 应用用户不应有系统管理权限;数据库用户权限按最小必要原则分配。
禁止不必要的执行:在上传目录(uploads)禁用 PHP/Script 执行。
定期更新:建立补丁管理流程,及时更新 CMS、插件、操作系统。
备份与恢复:定期备份,定期演练恢复流程确保可用性。
echo "PHP.Webshell.EvalBase64:0:*:6576616C286261736536345F6465636F646528" >> /etc/clamav/local.ndb
在 ClamAV 中添加自定义 webshell 签名。这个签名检查eval(base64_decode的十六进制模式。
freshclam && clamscan -r /var/www/ --infected --exclude-dir="^/var/www/wp-content/cache" --log=/tmp/clamscan.log
运行 ClamAV 扫描,输出检测结果到日志文件。
仅删除可见被篡改文件而不更换凭据
攻击者总会留下隐藏的后门入口。如果不更换密码和密钥,网站会被反复入侵。所以不管发现了多少恶意文件,一定要把所有凭据都重新生成。
仅清理页面而不检查数据库
大量 SEO 垃圾页面或隐藏的恶意重定向被存储在数据库中,文件层清理无法发现它们。这也是为什么我们要同时检查 posts、postmeta 和 wp_options 表。
过度依赖自动化工具
虽然自动化扫描工具有用,但人工核查和理解攻击链仍然至关重要。误报和漏报都可能影响恢复效果。有时一个异常的正常文件也会被工具标记,需要你手工判断。
忽视 PHP 缓存
PHP Opcache 和 APCu 会缓存代码到内存中,重启 PHP-FPM 前需要手动清除缓存,否则恶意代码仍然驻留。
php -r "opcache_reset();" 2>/dev/null || true
systemctl restart php-fpm
CDN 缓存污染
恶意内容被 CDN 缓存后,源站修复也无效。必须主动清除 CDN 缓存。
curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/purge_cache" \
-H "X-Auth-Email: EMAIL" \
-H "X-Auth-Key: API_KEY" \
-d '{"purge_everything":true}'
通过 Cloudflare API 清除所有缓存。
发生可疑异常 302 或黑链事件时,应按以下顺序快速处置:
保存日志与快照(2 分钟)
curl -v https://example.com/ > /tmp/response.txt
grep "302\|301\|307" /var/log/nginx/access.log | head -50 > /tmp/redirects.log
mysqldump -u root -p --all-databases > /tmp/db_backup.sql
快速保存现场证据。
隔离网站
systemctl stop php-fpm
或者启用 basic auth、IP 限制。
导出数据
tar czf /tmp/backup_$(date +%s).tgz /var/www/ /etc/nginx /var/log/
打包关键目录。
定位恶意代码
grep -r "eval\|base64_decode\|location.href" /var/www/ --include="*.php" --include="*.js"
快速搜索危险函数。
快速删除
find /var/www -name "shell.php" -o -name "*webshell*" | xargs rm -f
删除明显的恶意文件。
更换凭据
wp user update 1 --prompt=user_pass --allow-root
mysql -u root -p -e "ALTER USER 'wp_user'@'localhost' IDENTIFIED BY 'newpass';"
更换关键密码。
修补与监控
wp core update --allow-root
aide --init
应用更新和部署监控。
应急响应一旦启动,关键是快速、有序、完整——既要迅速控制局面,又要保全证据,并从根本上清除威胁。持续的监控和定期的安全演练是防止类似事件再次发生的长期之道。记住,防御永远比应急更重要,所以在平时就要做好备份、更新、监控这些基础工作。