记录一次木马入侵及修复
记录一次木马入侵及修复
结论
2026-11-10 11:21(北京时间),hxgeomaterial.com 再次被同一条 PbootCMS 缓存注入链路打中:攻击者在查询参数 s 里带上变形后的 PHP 短标签,页面中的 {pboot:pageurl} 把完整 URL 原样写进将被 include 的 HTML 缓存,View::cache() 里用来“剥离 PHP 标签”的正则反而把 <<??= 拼回 <?=,后续请求执行 payload,在 runtime/ 写下投放器 tempp3.php,再生成冰蝎式后门 bd459bcae6.php。
这不是后台密码泄露。当天同一波扫描也打了 www.tdxadapter.com,但该站 .htaccess 里已经有查询串拦截,请求全部返回 403。hxgeomaterial.com 在 11 月 9 日升级到 PbootCMS 3.2.32 后,根目录 .htaccess 只剩下伪静态,没有这组拦截规则,所以这次被写进去了。
升级后的 3.2.32 源码里,View::cache() 仍然使用 ! query_string('p,s'):这个函数会先丢掉 p 和 s 再判断查询串是否为空,因此“只带 p、s 的恶意请求”照样写缓存;{pboot:pageurl} 也仍未做 HTML 转义。上一篇《记一次pbootcms系统修复》里的代码层 P0,并不在这次升级后的文件里。
这次先清掉网站目录里的后门,再给两个 PbootCMS 站点统一补上 Apache 拦截,并禁止通过 HTTP 访问 runtime/、config/、data/。runtime/archive/session_ticket.php 是系统自己写的正常文件,不是木马。
告警与时间线
主机安全(腾讯云,服务器标识 usa_web / lhins-ghu278rh)连续告警:
- 11:21:31 检测到恶意文件
/www/wwwroot/hxgeomaterial.com/runtime/tempp3.php - 11:21:41 检测到恶意文件
/www/wwwroot/hxgeomaterial.com/runtime/bd459bcae6.php - 11:24:39 检测到
/root/incident-20261110-hx/bd459bcae6.php——这是隔离样本被扫描器再次命中,不是网站又被写入。取证不要把可执行.php样本留在磁盘上,只保留哈希和说明即可。
访问日志 /www/wwwlogs/hxgeomaterial.com-access_log 的对应关系:
- 11:21:19 起,UA 为
pbootcms-multiroute-poc的 GET 请求经 Cloudflare 回源,URL 形如/?p=/aboutus/&s=<<??=file_put_contents('runtime/tempp3.php', base64_decode('...'))??>>,多数返回 200(页面正常渲染,同时缓存被种下)。 - 11:21:40
GET /runtime/tempp3.php返回 200、34 字节——投放器已执行:写出随机文件名后门并自删。 - 11:21:41 再请求同一地址已是 404(文件已被主机安全或投放器自己删除)。
- 11:21:51
GET /runtime/bd459bcae6.php返回 200。
www.tdxadapter.com 当天同类带 file_put_contents 的查询请求全部 403。
入口与原因
和《记一次pbootcms系统修复》是同一条链,只是这次落点改成了 runtime/tempp3.php:
- 模板输出
{pboot:pageurl}时调用get_current_url(),不转义,完整查询串进入即将缓存的 HTML(常见位置是og:url)。 s参数并不被业务代码读取,query_string('p,s')先剔除p、s再判断,结果为空,于是View::cache()仍然写缓存。- 写缓存前的剥离正则会删除
<?、<?=、?>等,<<??=删掉中间的<?后变成<?=,??>>删掉?>后变成?>。这段内容被写进runtime/cache/<md5>.html,内核随后include该文件,payload 执行。
站点当时跑在 Apache(80/443 由 httpd 监听,.htaccess 生效)。hxgeomaterial.com 的 .htaccess 升级后只剩伪静态,以及拒绝访问 data|static/backup 的规则,没有拦截 {pboot:if}、PHP 短标签和 file_put_contents 等危险函数。已经落到磁盘上的 runtime/*.php 会由 Apache 直接执行,不会走到伪静态。
清理
runtime/tempp3.php检查时已被主机安全删除。runtime/bd459bcae6.php(680 字节,属主 www,mtime 11:21:40)是冰蝎风格的加密通信后门,已从网站目录移除。- 全站扫描未发现其它同类随机名 PHP、历史上的
ea7987b3目录,或上传目录里的 PHP。 - 不要把后门原文拷到
/root下留作“取证”,主机安全会再次告警。
这次具体改了什么
两个 PbootCMS 站点都改了,路径分别是:
/www/wwwroot/hxgeomaterial.com/www/wwwroot/www.tdxadapter.com
原 .htaccess 备份为 .htaccess.bak-sec-20261110112658。
1. 站点根目录 .htaccess
在伪静态 catch-all 之前增加两类规则:敏感目录直接拒绝;查询串里出现模板注入或危险函数时返回 403。
1 | <IfModule mod_rewrite.c> |
2. runtime/.htaccess
即使有人再次在 runtime/ 写下 PHP,也不能通过网页执行。应用内部 include 编译模板不受影响。
1 | Require all denied |
验证
在服务器本机用 HTTPS 检查(用无害特征即可,不必重放攻击):
- 两个站点首页返回 200
/?s=file_put_contents返回 403/runtime/、/runtime/archive/session_ticket.php返回 403
还没做完的代码层修复
Web 层拦截只能挡住已知特征。升级 CMS 后要重新核对上一篇里的 P0 是否还在,目前这两处仍然是升级前的逻辑,需要再补一次:
core/view/View.php的cache():把条件改成存在任意查询串就不写 HTML 缓存,例如empty($_SERVER['QUERY_STRING']);剥离标签之后如果还能匹配到<?/<?=/<%,放弃写缓存。apps/home/controller/ParserController.php:{pboot:pageurl}改为htmlspecialchars(get_current_url(), ENT_QUOTES, 'UTF-8')后再替换。
topchinafactory.com、www.hneco.com 不是 PbootCMS,日志里没有这波 UA。主机安全控制台里这几条可以按已处理关闭。
.jpg)
