某天早上打开自家站,用户反馈一点击就跳到一个陌生页面,后台自己登录正常、前台却乱跳——这多半不是浏览器问题,是站点被挂马了。挂马的本质是攻击者往你的程序里塞了后门或跳转代码,借你的域名和权重去引流、做 SEO 作弊甚至钓鱼。越早处理损失越小,拖久了会被搜索引擎标记“此站点可能遭到黑客攻击”,正常流量直接腰斩。
处理挂马最忌讳“凭感觉乱删”。正确顺序是先确认、再隔离清理、然后加固、最后复检。下面这套流程照着走,既能清干净,也能把重复被挂的概率压下去。
一、先确认是不是真被挂马
现象通常有这几类:访问首页或内页被强制跳转到别的域名;百度快照里你的标题和描述变成了乱七八糟的赌博、医药内容;站点根目录或上传目录里冒出你从没建过的文件,比如 x.php、t.php、名字随机的 .phtml;服务器 CPU 和出网流量突然异常偏高;访问日志里出现大量对某一个陌生脚本的请求。先别急着下结论,用两个动作验证:在搜索引擎里用 site:你的域名看快照标题是否正常;用命令行 curl -I 你的首页,看响应头里有没有 Location 跳转。两条里只要中一条,基本可以认定被挂马。
二、清除:先备份隔离,再逐层清理
第一步是立刻做一次全量备份,万一清错还能回滚,很多站长一慌就直接删文件,结果把正常程序也删了。第二步把站点临时下线或挂维护页,避免继续对外投毒、也避免清理时攻击者又写入。第三步扫描 webshell 特征,把藏在后门里的恶意代码揪出来。下面这段脚本专门干这件事:把站点根目录填进 ROOT,它遍历所有脚本文件,用一组常见后门特征逐一比对,跑完把命中文件列出来供你逐个复核。
# 扫描站点目录里的 webshell 特征,列出可疑文件供人工复核
import os, re
ROOT = "/www/example.com" # 改成你的站点根目录
RULES = [
rb"eval\s*\(",
rb"base64_decode\s*\(",
rb"gzinflate\s*\(",
rb"assert\s*\(",
rb"preg_replace\s*\([^)]*/e",
rb"create_function\s*\(",
rb"shell_exec\s*\(",
rb"system\s*\(",
rb"passthru\s*\(",
rb"phpinfo\s*\(",
]
def scan(path):
hits = []
for root, _, files in os.walk(path):
for f in files:
if not f.endswith((".php", ".phtml", ".php3", ".inc")):
continue
fp = os.path.join(root, f)
try:
data = open(fp, "rb").read()
except OSError:
continue
for r in RULES:
if re.search(r, data):
hits.append((fp, r.decode()))
break
return hits
for fp, rule in scan(ROOT):
print("可疑文件:", fp, "命中特征:", rule)
跑完看到的可疑文件,先对照业务判断它到底是后门还是正常用到这些函数的程序(比如某些老框架会用到 eval)。确认是后门就删除;拿不准的先移到隔离目录,观察几天再处理。第四步清数据库里的注入内容,很多挂马会把跳转写进文章表、配置表,用后台或命令行把异常记录删掉;被改的模板还原成干净版本。第五步改掉所有密码:FTP、数据库、后台管理员、服务器登录,任何一处没改,攻击者都能再进来。
三、加固:堵住再被挂的口子
清完只是止血,不加固很快会被同一批自动化工具再打一遍。第一,把程序、插件、主题全部升级到最新版,绝大多数挂马利用的是已知漏洞,官方补丁早就出了。第二,收敛文件权限:目录设 755、文件设 644,上传目录禁止执行脚本(Nginx 里对该目录加 location ~ \.php$ { return 403; })。第三,关闭危险函数,在 php.ini 的 disable_functions 里禁用 exec、system、passthru、shell_exec、popen 等非必要函数,按业务保留最小集。第四,给后台加一道防线:改掉默认路径、开启两步验证、限制登录 IP。第五,在 CDN 或防火墙层加规则,拦截包含常见注入特征的请求。
加固之后建议再扫一遍“最近被改动过的文件”,因为后门常常藏在看起来正常的文件里、只是修改时间很新。下面这段把最近 N 天内被改过的文件列出来,你重点看这些时间点反常的文件是不是你本人改的。
# 列出最近 N 天内被改动过的文件,快速看出挂马后新增或篡改的文件
import os, time
ROOT = "/www/example.com" # 改成你的站点根目录
DAYS = 7 # 排查最近 7 天
cut = time.time() - DAYS * 86400
for root, _, files in os.walk(ROOT):
for f in files:
fp = os.path.join(root, f)
try:
m = os.path.getmtime(fp)
except OSError:
continue
if m >= cut:
print(time.strftime("%Y-%m-%d %H:%M", time.localtime(m)), fp)
四、复检:确认清干净并恢复信誉
清理和加固做完,还要验证真的干净了。第一,把当前目录和一份确认干净的备份逐文件对比,确认没有漏网的后门。第二,再用 curl -I 和 site: 命令复查,跳转和异常快照应当都消失。第三,去搜索引擎的站长平台提交“被黑站点已修复”的反馈,能加速解除安全警示、让正常快照回来。第四,把监控变成例行:定时跑上面的两个脚本,看访问日志里有没有针对陌生脚本的异常请求,一旦发现苗头马上处理。挂马处置不是一次性活儿,清完不监控,等于门没关。
相关阅读:
申请创业报道,分享创业好点子。点击此处,共同探讨创业新机遇!
