结论: 服务器被挂马(WebShell 网页后门)的处置顺序是:先隔离止损,再定位后门(按修改时间找新增脚本、grep 危险函数、比对官方源码),清除后门文件与计划任务,最后堵入口(PHP 禁用危险函数、上传目录禁止执行、权限 644/755)并改密换钥打补丁。只删文件不堵入口,通常 72 小时内会被二次植入。
"网站被搜索引擎标红""浏览器提示危险站点""云厂商发来违规外联告警"——这些信号的背后,绝大多数是服务器被挂了马。挂马和服务器中病毒不是一回事:病毒的战场在系统进程里,挂马的战场在你的网站目录里。它藏得极深,可能只是一个 47 字节的 .php 文件,却能让攻击者拿到你整台机器的命令执行权。
更麻烦的是,很多人处理挂马的方式是"找到文件、删掉、收工"。三天后马又回来,而且换了个更难找的名字。原因很简单:入口没堵。本文给出一条从隔离 → 定位 → 清除 → 堵入口 → 加固的完整链路,命令基于 Ubuntu 24.04 LTS + Nginx 1.26 + PHP 8.3,可直接复制执行。
先分清:WebShell 网页后门 ≠ 服务器中病毒
结论:WebShell 是寄生在 Web 目录里、靠 HTTP 请求触发的脚本后门;主机层恶意程序(挖矿木马、rootkit、勒索软件)是常驻系统的独立进程。 两者排查工具和处理侧重完全不同,先判断类型能少走 80% 的弯路。
| 对比维度 | WebShell 网页后门(本文) | 主机层恶意程序(挖矿 / rootkit / 蠕虫) |
|---|---|---|
| 落点位置 | Web 目录,如 /var/www/html,和源码混在一起 | /tmp、/dev/shm、系统目录、crontab、systemd、内核模块 |
| 运行方式 | 被 HTTP 请求触发,由 PHP / JSP / ASP 解释执行 | 独立进程常驻,有 PID,可长期占用 CPU |
| 运行权限 | 等于 Web 服务用户(www-data / nginx) | 多为 root,或提权后拿到 root |
| 典型特征 | 网站目录出现陌生 .php,访问日志有 POST 到罕见路径 | CPU 长期 100%、异常外连、命令被 hook、文件被锁 |
| 排查工具 | find -mtime、grep 危险函数、diff 官方源码、ClamAV | ps/top、chkrootkit、rkhunter、auditd |
| 处理侧重 | 清 Web 目录 + 堵上传与解析入口 | 清进程 + 清持久化 + 系统级加固 |
一句话区分:如果 CPU 没异常、进程看不出问题,但网站目录多了文件、访问日志里有诡异请求,那基本就是挂马。 主机层恶意程序的处置方法见本站点另一篇《服务器中病毒了怎么处理》,本文只讲 Web 层。
第一步:隔离止损,保留现场
结论:发现挂马后前 10 分钟不要急着删文件,先做两件事——限制访问(止损)和打包留证(保留现场)。 直接删除会毁掉判断入侵时间和入口的关键证据,也会让攻击者察觉后换更隐蔽的手法。
隔离的三个动作,按优先级:
- 切维护页或临时下线:让站点停止对外服务,阻断后门被继续调用。
- 对后门文件单独 deny:如果业务不能停,用 Nginx 精确封掉已确认的后门路径。
- 打包现场:把 Web 目录和 Nginx 日志先复制到
/root下的隔离目录,供后续取证。
# 1. 建立取证目录并保留现场(不要直接删任何文件)
INC=/root/incident-$(date +%F)
mkdir -p $INC
tar czf $INC/www.tar.gz /var/www/html 2>/dev/null
cp -a /var/log/nginx $INC/nginx-log
cp -a /etc/php/8.3/fpm $INC/php-fpm-conf
# 2. 记录当前所有可疑进程与监听端口(供后续对比)
ps auxf > $INC/ps.txt
ss -lntp > $INC/ss.txt# /etc/nginx/sites-available/example.com(Nginx 1.26)
# 方式 A:全站维护页,最快止损
server {
listen 80;
server_name example.com;
root /usr/share/nginx/html;
index maintenance.html;
location / { try_files /maintenance.html =503; }
}
# 方式 B:业务不能停时,精确封掉已确认的后门文件
location = /wp-content/uploads/2026/06/x.php { deny all; }改完记得 nginx -t && systemctl reload nginx。
第二步:定位后门文件——四种查法叠加使用
结论:不要只依赖一种查法。 时间法能找到"新来的",特征法能找到"伪装的",比对法能找到"被动过手脚的官方文件",杀软能兜底。四种叠加,漏网概率才降到最低。
方法一:按修改时间找新增文件
挂马文件的修改时间通常非常集中,往往和入侵发生在同一天甚至同一分钟。
# 找最近 3 天内被修改过的 php 文件,按时间排序
find /var/www -type f -name "*.php" -mtime -3 \
-printf '%TY-%Tm-%Td %TH:%TM %s %p\n' | sort
# 精确到分钟:找入侵当天(例如 2026-06-18)变动的所有文件
find /var/www -type f -newermt "2026-06-18 00:00" ! -newermt "2026-06-19 00:00" \
-printf '%TH:%TM %p\n' | sort
# 找体积异常小的 php 文件(一句话木马常小于 200 字节)
find /var/www -type f -name "*.php" -size -200c -printf '%s %p\n'方法二:按内容特征 grep 危险函数
# 推荐写法:正则一次覆盖常见后门函数
grep -rnE "(eval|assert|system|passthru|shell_exec|proc_open|popen|base64_decode|gzinflate|str_rot13|create_function|preg_replace\s*\(\s*['\"].*['\"]\s*/\s*[es]*\s*\))[[:space:]]*\(" \
/var/www --include="*.php" | head -60
# 兼容老系统的简化写法
grep -r "eval(\|base64_decode\|assert(\|system(\|passthru" /var/www
# 只看文件名,先看规模再逐个打开
grep -rlE "eval\(|base64_decode\(|assert\(" /var/www --include="*.php" | head -30注意:CMS 自身的模板引擎、缓存插件也可能命中 eval(,命中不等于后门,需要打开文件人工确认——真正的后门通常只有几行、变量名为 $_POST['x'] 这类单字母、有大量 base64 乱码字符串。
方法三:与官方源码比对(最可靠)
# A. 站点在 git 管理下(最省事)
cd /var/www/html
git status --porcelain | head -50 # Untracked 的 .php 高度可疑
git diff --stat | head -20 # 被修改的文件逐个看
# B. 无版本控制:下载官方干净包逐文件 diff
wget -q https://wordpress.org/wordpress-6.7.2.zip -O /tmp/wp.zip
unzip -q /tmp/wp.zip -d /tmp/clean
diff -rq /tmp/clean/wordpress /var/www/html \
| grep -v "wp-content/uploads" | head -40比对法的核心价值是:它能发现"藏进官方文件里"的后门——攻击者往 wp-includes/functions.php 里插三行代码,时间和特征法都可能漏掉,但 diff 一比就露馅。
方法四:ClamAV 全盘扫描兜底
apt update && apt install -y clamav clamav-daemon # Ubuntu 24.04 LTS
freshclam # 更新病毒库,首次较慢
clamscan -r --infected --log=/root/clamav-$(date +%F).log /var/www
# 确认后再决定是否 --remove,误删正常文件的代价很高第三步:认清常见 WebShell 形态与识别特征
结论:一句话木马已经很少以原样出现,现在主流是"变形免杀 + 图片马 + 合法文件寄生"。 认识它们的伪装手法,才不会被"看着像正常文件"骗过去。
| 形态 | 典型代码特征 | 识别要点 |
|---|---|---|
| 一句话木马 | | 体积极小(几十字节),文件名常伪装成 index1.php、logo.php |
| 变形免杀 | 函数名字符串拼接、变量函数、strrev 反转 | 变量名全是无意义单字母,含大量 . 拼接 |
| 图片马 | 正常图片尾部追加 PHP 代码 | 需配合解析漏洞或文件包含才生效,重点查上传目录 |
| 合法文件寄生 | 往官方 PHP 文件开头/结尾插入几行 | 只能靠 diff 或 git status 发现 |
| 加密混淆马 | 整段 base64 + gzinflate + eval | 文件几乎全是乱码,看不到任何正常业务逻辑 |
图片马的检测命令(查图片文件里是否混入了 PHP 标签):
grep -rl "/dev/null
# PHP 侧也应校验真实 MIME,而不是只看后缀第四步:清除后门——不只是删文件
结论:删除后门文件只完成了一半。 攻击者几乎一定留了持久化手段(计划任务、systemd 服务、SSH 公钥),不清掉这些,删多少文件都没用。
# 1. 确认后先隔离,不直接 rm(方便后续复盘)
mkdir -p /root/quarantine
mv /var/www/html/wp-content/uploads/x.php /root/quarantine/
# 2. 查计划任务(重点看 Web 用户 www-data 的任务)
crontab -l -u www-data 2>/dev/null; crontab -l -u root
ls -la /etc/cron.d/ /var/spool/cron/crontabs/ /etc/cron.hourly/
# 3. 查 systemd 服务与开机启动项
systemctl list-unit-files --state=enabled | grep -viE "systemd|dbus|ssh|cron|nginx|php|ufw|getty"
ls -la /etc/systemd/system/ | grep -viE "multi-user|default|@\."
# 4. 查 SSH 公钥是否被写入
cat /root/.ssh/authorized_keys /home/*/.ssh/authorized_keys 2>/dev/null
# 5. 查 Web 用户是否被赋予了可登录 shell
grep -E "www-data|nginx|apache" /etc/passwd
# 正常应为 /usr/sbin/nologin 或 /bin/false清理清单,逐条打勾:
- 已删除/隔离全部后门文件(含图片马、寄生代码)
- 已清除 Web 用户与 root 的可疑计划任务
- 已删除可疑 systemd 服务单元并
systemctl daemon-reload - 已清理未授权的
authorized_keys条目 - 已确认
www-data的 shell 为nologin
第五步:堵住入口——Web 层加固配置
结论:入口不堵,72 小时内必然二次挂马。 三个必做项:PHP 禁用危险函数、上传目录禁止执行脚本、文件权限与属主规范化。
PHP 8.3 禁用危险函数
; /etc/php/8.3/fpm/php.ini (Ubuntu 24.04 LTS + PHP 8.3)
disable_functions = exec,passthru,shell_exec,system,proc_open,popen,
pcntl_exec,putenv,dl,show_source,parse_ini_file,curl_multi_exec注意两点:eval 是 PHP 语言结构而非函数,无法通过 disable_functions 禁用,只能靠代码审计与 WAF;禁用前要确认业务不依赖这些函数(部分备份插件、Composer 部署脚本会用到 exec,需单独评估)。改完执行:
php-fpm8.3 -t && systemctl restart php8.3-fpm
php -i | grep -i disable_functions # 验证是否生效上传目录禁止执行脚本
# /etc/nginx/sites-available/example.com(Nginx 1.26)
# 上传目录:只允许静态文件,任何 php 直接拒绝
location ^~ /wp-content/uploads/ {
location ~* \.(php|php5|phtml|phar|pht)$ { deny all; }
expires 30d;
log_not_found off;
}
# 站点正常 PHP 解析
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}PHP-FPM 侧再加一道锁,限制只解析 .php 后缀:
; /etc/php/8.3/fpm/pool.d/www.conf
security.limit_extensions = .php
php_admin_value[open_basedir] = /var/www/html:/tmp
user = www-data
group = www-data
listen.owner = www-data
listen.mode = 0660文件权限与属主:644 / 755
# 目录 755,文件 644
find /var/www/html -type d -exec chmod 755 {} \;
find /var/www/html -type f -exec chmod 644 {} \;
# 属主 root、属组 www-data:Web 进程只读,无法改写源码
chown -R root:www-data /var/www/html
# 只有必须写入的目录才给组写权限
chown -R www-data:www-data /var/www/html/wp-content/uploads
find /var/www/html/wp-content/uploads -type d -exec chmod 755 {} \;
# 排查世界可写文件
find /var/www -type f -perm -o+w -printf '%M %p\n'绝对禁止:chmod -R 777、用 root 用户运行 PHP-FPM、把 Web 目录属主设成 www-data。这三条是挂马最常见的温床。
第六步:清理后的三步加固与入口审计
结论:收尾只有三件事——改密码换密钥、打补丁、审计入口。 第三件最容易被跳过,而它恰恰决定了"会不会再来一次"。
- 改密码换密钥:SSH 密钥对、数据库账号、CMS 后台管理员、FTP/SFTP、宝塔等面板账号,全部轮换;数据库账号不要再用 root。
- 打补丁:CMS 核心、插件、主题升级到官方最新版;系统侧
apt update && apt upgrade;PHP 与 Nginx 保持小版本更新(截至 2026 年,PHP 8.3 为 Ubuntu 24.04 LTS 默认版本)。 - 审计入口:从日志反推攻击者是怎么进来的。
# 找出被 POST 最多的路径(后门调用通常高频且路径罕见)
awk '$6 ~ /POST/ {print $7}' /var/log/nginx/access.log \
| sort | uniq -c | sort -rn | head -20
# 查某个后门文件第一次被访问的时间,即入侵起始点
grep -n "x.php" /var/log/nginx/access.log | head -3
# 查同一时段还有哪些文件被创建(与第一次访问时间交叉比对)
find /var/www -type f -newermt "2026-06-18 14:00" ! -newermt "2026-06-18 15:00"常见入口只有五类:弱口令后台、CMS 插件/主题漏洞、上传功能未校验、暴露的数据库或 Redis 未授权访问、泄露的源码与备份文件。定位到具体那一类,才算真正闭环。
企业QQ咨询




