ShopXO v6.3.0 恶意文件安全事件排查与修复全记录
ShopXO v6.3.0 导致 服务器 Webshell 恶意文件安全事件排查与修复全记录
告警时间:2026-08-16 下午(GMT+8)
服务器环境:腾讯云轻量服务器 | OpenCloudOS | 宝塔面板 | Nginx + PHP 8.2.x + ThinkPHP 8.0.x + ShopXO v6.3.0(已应用本次安全修复)说明:本文已脱敏,域名、公网 IP、服务器实例 ID 等均以占位符或泛化描述代替。
一、事件背景
收到腾讯云主机安全告警通知:
| 项目 | 详情 |
|---|---|
| 告警时间 | 2026-08-16 下午 |
| 文件路径 | /tmp/php9pDNFw |
| 病毒名 | Php.Backdoor.Webshell.Rwhl |
| 威胁等级 | 严重 |
| 标签特征 | Webshell |
本文完整记录了从发现告警到定位攻击源、分析攻击路径、完成修复加固的全过程。
二、排查过程
2.1 第一步:检查恶意文件
首先检查告警中的恶意文件是否仍然存在:
ls -la /tmp/php9pDNFw结果:文件已不存在,可能已被主机安全自动隔离或删除,或被 PHP 进程自动清理。
2.2 第二步:确认服务器 Web 服务环境
检查服务器上运行的 Web 服务和 PHP 相关进程:
ps aux | grep -E 'nginx|apache|httpd|php-fpm|php' | grep -v grep
ss -tlnp | grep -E '80|443|8080|8443'
php -v结果:
- Nginx + PHP-FPM(宝塔面板环境)
- Web 服务监听 80、443 端口
- PHP 版本:8.2.x
- PHP-FPM 通过 Unix Socket
/tmp/php-cgi-82.sock监听,仅允许 127.0.0.1 连接
2.3 第三步:确认站点配置与日志路径
查看 Nginx 配置和站点日志:
find /www/server/panel/vhost/nginx -name '*.conf'
ls -la /www/wwwlogs/发现多个站点(域名均已脱敏):
- 主站(ShopXO 电商系统)
- 业务站 B
- 业务站 C(会员站)
- 业务站 D(FastAPI 服务)
2.4 第四步:搜索告警时段的 Web 日志
在所有站点日志中搜索告警时段前后的请求记录:
grep '16/Aug/2026:13:3[345]' /www/wwwlogs/*.log发现攻击源:来自境外 IDC 的来源 IP(已脱敏)在 13:34 前后进行了大规模自动化漏洞扫描,发送了上百个请求,探测敏感文件、目录遍历、框架漏洞等。
2.5 第五步:分析攻击请求
攻击者的 POST 请求中有两个返回了 200 状态码:
| 时间 | 请求 | 状态码 | 响应大小 |
|---|---|---|---|
| 13:34 | POST /index.php?option=com_jce&task=plugin.display&plugin=image&file=imgmanager | 200 | 208字节 |
| 13:34 | POST /index.php?option=com_jce&view=editor&plugin=imgmanager&cmd=file_upload | 200 | 208字节 |
这两个请求是 JCE(Joomla Content Editor)文件上传漏洞利用尝试,攻击者在 POST 请求体中包含了 multipart/form-data 上传数据。
2.6 第六步:主机安全日志分析
检查腾讯云主机安全(YunJing)日志,获取关键证据:
grep 'php9pDNFw\|phpJfqkRc\|/tmp/php' /usr/local/qcloud/YunJing/log/*.log关键发现:
13:34 Malware report path:/tmp/php9pDNFw
13:34 Malware open_fail path:/tmp/phpJfqkRc/tmp/php9pDNFw在 13:34 被检测为恶意文件(文件已被 PHP 释放)/tmp/phpJfqkRc在 13:34 检测时 open_fail(文件已被 PHP 删除)- 两个临时文件的时间点与两个 POST 请求完美对应
2.7 第七步:攻击路径还原
综合所有证据,攻击路径如下:
攻击者(来源 IP 已脱敏)
│
├── 13:34 POST /index.php?option=com_jce&task=plugin.display... (含 multipart 上传数据)
│ │
│ └── PHP-FPM 接收请求
│ │
│ └── PHP 在 /tmp 创建临时文件 php9pDNFw (Webshell)
│ │
│ └── YunJing 13:34 检测到恶意文件并告警
│
├── 13:34 POST /index.php?option=com_jce&view=editor&cmd=file_upload (含 multipart 上传数据)
│ │
│ └── PHP-FPM 接收请求
│ │
│ └── PHP 在 /tmp 创建临时文件 phpJfqkRc
│ │
│ └── YunJing 13:34 检测时文件已被 PHP 自动删除
│
└── ShopXO (ThinkPHP) 路由未匹配 JCE 组件,返回默认首页 (208字节)
└── 上传文件未被实际处理和保存,未造成持久化入侵关键结论:
- 攻击者利用 JCE 文件上传漏洞扫描器,向
/index.php发送了包含恶意 PHP 文件的 multipart 上传请求 - PHP 按标准机制将上传文件暂存到
/tmp目录,生成临时文件php9pDNFw和phpJfqkRc - 由于 ShopXO 并非 Joomla,ThinkPHP 路由未匹配到 JCE 组件,返回了默认首页
- 上传的恶意文件未被实际处理和保存,PHP 脚本结束后自动删除了临时文件
- 未造成实际入侵,但暴露了安全隐患
2.8 第八步:安全隐患排查
检查 /tmp 残留文件
find /tmp -name 'php*' -type f结果:无残留恶意文件 ✅
检查 Web 根目录
find /www/wwwroot -name '*.php' -mtime -1 | grep -v runtime结果:无异常 PHP 文件 ✅
检查异常进程
ps aux | grep -E 'nc |ncat|socat|python -m|perl -e|bash -i' | grep -v grep结果:无异常进程 ✅
检查 SSH 授权密钥
cat /root/.ssh/authorized_keys结果:无异常授权密钥 ✅
2.9 第九步:发现 UEditor 未授权访问漏洞
在排查过程中,发现 ShopXO 的 UEditor 百度编辑器存在安全隐患:
代码审计:
app/admin/controller/Ueditor.php→ 有IsLogin()认证 ✅app/api/controller/Ueditor.php→ 有IsLogin()认证 ✅app/index/controller/Ueditor.php→ 无登录认证 ❌
index 端(前台)的 Index() 方法直接调用 UeditorService::Run(input()),未授权用户可访问文件上传和 catchimage(远程图片抓取)功能。
虽然本次攻击未利用此漏洞,但这是一个严重的安全隐患,需要修复。
三、修复操作
3.1 封禁攻击来源 IP
# 封禁 Webshell 上传攻击来源 IP
iptables -I INPUT -s <来源IP-1> -j DROP
# 封禁 SSH 爆破来源 IP
iptables -I INPUT -s <来源IP-2> -j DROP
iptables -I INPUT -s <来源IP-3> -j DROP
# 保存规则,重启后持久化
iptables-save > /etc/sysconfig/iptables验证:
iptables -L INPUT -n --line-numbers | head 10| 来源(已脱敏) | 封禁原因 |
|---|---|
| 来源IP-1 | Webshell 上传攻击 + 大规模漏洞扫描 |
| 来源IP-2 | 长期 SSH 爆破攻击 |
| 来源IP-3 | 长期 SSH 爆破攻击 |
3.2 修复 UEditor 未授权访问漏洞
修改文件:站点根目录/app/index/controller/Ueditor.php
修改前:
public function Index()
{
return ApiService::ApiDataReturn(UeditorService::Run(input()));
}修改后:
public function Index()
{
// 安全加固:禁止前台未授权访问 UEditor 上传功能(2026-08-16)
// 如需恢复,注释掉下方 return 并取消注释原逻辑
return ApiService::ApiDataReturn(['code' => -1, 'msg' => '禁止访问']);
// return ApiService::ApiDataReturn(UeditorService::Run(input()));
}修复效果:
Index()方法直接返回禁止访问,不再调用UeditorService::Run()- 攻击者无法再通过 index 端未授权访问 UEditor 上传和 catchimage 功能
ScanUpload()方法不受影响,仍正常工作- 原始代码已注释保留,如日后需要恢复只需取消注释
四、安全加固建议
立即处理
| 序号 | 加固项 | 状态 |
|---|---|---|
| 1 | 封禁攻击来源 IP | ✅ 已完成 |
| 2 | 修复 UEditor 未授权访问 | ✅ 已完成 |
短期加固
| 序号 | 加固项 | 说明 |
|---|---|---|
| 3 | 配置 PHP 上传临时目录 | 设置 upload_tmp_dir 为非 /tmp 目录,防止临时文件被直接访问 |
| 4 | 加强 SSH 安全 | 禁用 root 密码登录,仅允许密钥认证 |
| 5 | 安装 fail2ban | 自动封禁暴力破解 IP |
| 6 | 确认系统二进制完整性 | 使用 rpm -V 验证系统命令是否被篡改 |
长期加固
| 序号 | 加固项 | 说明 |
|---|---|---|
| 7 | 升级 ShopXO | 关注官方安全更新,确认官方版本已包含本修复,及时升级到最新版本 |
| 8 | 部署 WAF | 在 Nginx 层部署 Web 应用防火墙,拦截恶意扫描请求 |
| 9 | 定期安全审计 | 定期检查 Web 日志、系统日志和主机安全告警 |
五、总结
事件定性
本次安全事件为未成功的 Webshell 上传攻击。攻击者通过自动化漏洞扫描器,利用 JCE 文件上传漏洞尝试向服务器上传 PHP Webshell。由于服务器运行的是 ShopXO(基于 ThinkPHP)而非 Joomla,攻击载荷未匹配到有效路由,上传的恶意文件仅作为 PHP 临时文件存在于 /tmp 目录,未被实际执行或持久化保存。
经验教训
- PHP 临时文件机制:PHP 处理 multipart 上传时会在
/tmp目录创建临时文件(命名格式php + 6位随机字符),即使业务逻辑不处理上传文件,临时文件仍会被创建,可能被主机安全检测到 - 日志分析的重要性:Nginx 访问日志 + 主机安全日志的关联分析是定位攻击路径的关键
- 最小权限原则:前台用户不应有未授权的文件上传权限,所有上传接口都应有认证机制
- 主机安全的价值:腾讯云主机安全(YunJing)在本次事件中发挥了关键作用,及时检测并告警了恶意临时文件
排查方法论
告警通知 → 检查恶意文件 → 确认 Web 环境 → 搜索日志记录
→ 分析攻击请求 → 关联主机安全日志 → 还原攻击路径
→ 排查安全隐患 → 执行修复加固 → 验证修复效果文档记录时间:2026-08-16 14:11