部署 20 小时,911 条 Web 请求,7 类 PHP 漏洞探测,6 个扫描源 IP 同步作业——这是 PHP 关键安全更新发布窗口期,公网扫描器的真实生态快照。
0. 缘起:一封营销邮件又让我熬大夜
昨天早上收到 @wordfence 的邮件告警,标题大意是「Upcoming Critical PHP Security Release」。
说实话第一反应是:又是营销软文。Wordfence 家的邮件一贯如此——把别人家的漏洞包装成自己的情报来推。扫了一眼准备归档,突然看到 CVE 级别是 Critical,而且影响范围写的是「All PHP versions」。
一个激灵:我那 WordPress 站点跑的就是 PHP 啊。
按照行业惯例,PoC 会在补丁发布后的几小时到几天内陆续公开,紧接着就是全网扫描器的狂欢。
晚上 10 点 PHP 发补丁,我突发奇想:不如搭个蜜罐,蹲第一波 PoC 利用?
说起来这不是我第一次干这事——去年的 Log4Shell 风波我也搭过蜜罐,那时候纯粹是看戏吃瓜。没想到今年轮到我熬大夜了。
感谢 @blogclub 群友帮忙”拼好机”,凌晨 4 点终于把双节点蜜罐(A 机 Web 蜜罐 + B 机多端口蜜罐)拉起来了。本文是部署首日(D1)的真实捕获记录。
1. 蜜罐整体捕获概览
-1024x454.png)
先上一张总览图,对规模有个概念:
两个节点的分工:
- A 机:部署在香港轻量云,跑 WordPress + Apache(:80/:443),外加 :2222 端口的 SSH 蜜罐。这是本文的主战场——专门用来钓 PHP 相关漏洞利用。
- B 机节点:六端口汇聚(SSH/TELNET/HTTP/MySQL 等),主要抓 IoT 蠕虫和暴力破解,作为背景噪音参考。
D1 合计捕获近 1.1 万条事件。但真正有干货的,是 A 机 Web 面的 911 条请求——里面藏着 PHP 漏洞扫描器的完整画像。
2. 核心发现:PHP 扫描器生态全景
2.1 头条:新 CVE 披露不到 24 小时,武器化探测已上线
在所有捕获里,信号价值最高的是这一条:
POST /lib/phpunit/phpunit/Util/PHP/eval-stdin.php
User-Agent: php2shell-109618
Content-Type: multipart/form-data; boundary=----poc618
UA 直接自报 php2shell-109618,其中 109618 正是这次 PHP 安全更新对应的 CVE 编号(CVE-2026-109618,PHP cgi OOM RCE,官方 10 月 21 日发布)。蜜罐抓到这条请求的时间是 10 月 22 日 14:08 UTC——距离漏洞披露还不到 24 小时。
更有意思的是攻击手法:它不走 php-cgi 注入的正路,而是借道 PHPUnit eval-stdin.php(CVE-2017-9841)这个经典 POST-body-eval 入口,把针对新 CVE 的 PoC 装载进去打——新旧 CVE 组合装载是当前武器化的典型套路,老洞当”枪”、新洞当”弹”。
⚠️ 这条请求最终 404 没触达可利用面(复刻靶没有这个路径,error.log 也无 PHP 异常)。UA 直接点名内部代号,归因还在核对中,目前措辞为”疑似定向武器化探测”。
结论很直白:补丁窗口期的假设已经失效了。 以前是披露→ PoC → 扫描,中间有几天到几周的缓冲;现在披露和被扫描几乎是同一件事的前后脚。“披露即假定已被扫描”应该成为默认的运营假设。
2.2 攻击类型分布
先看 A 机 Web 面 911 条请求里,各种攻击类型的占比:
-1024x709.png)
几个值得注意的点:
- PHPUnit RCE 探测高居榜首(127 次)——这是 CVE-2017-9841 的老洞,但因为 PHPUnit 在 Composer 项目里几乎是标配,且大量生产环境误带
vendor/目录上线,至今仍是扫描器的必打项。 - PHP-CGI 参数注入(30 次)——这是本次最值得关注的信号。扫描器使用了 5 种编码变体,包括双 URL 编码绕过,明显是有备而来。
- WordPress 登录探测(120 次)——属于常规背景噪音,但值得注意的是 41 次 POST 请求都是针对
wp-login.php的暴力破解。 - TBK IoT 注入(23 次)——来自
device.rsp接口的 IoT 僵尸网络,和 PHP 漏洞无关,但侧面说明公网任何 IP 都会被多类扫描器同时光顾。
2.3 扫描器 UA 指纹
扫描器的 User-Agent 是最直接的身份标识。来看看 Top 8:
-1024x730.png)
头号嫌疑人:libredtail-http(178 次)
这是本次 PHP 漏洞专项扫描的主力。特征非常鲜明:
- 6 个不同源 IP,行为模式完全一致——同一套 payload、同一顺序、相近时间窗
- 每轮扫描约 43 条请求,波次间隔约 7 小时
- 覆盖攻击面:PHP-CGI 注入 + PHPUnit 遍历 + ThinkPHP RCE + Pearcmd LFI + 路径穿越
- UA 无版本号、无多余信息,典型的武器化商用扫描器特征
libredtail-http 这个 UA 在公开资料中不多见,但从其扫描策略的系统性和完整性来看,绝非业余脚本。后续会持续追踪其指纹变化。
二号:Go Web Pentest Tool(128 次)
- 全部来自同一 IP
122.51.93.217(腾讯云) - 集中在 21 日 23:00 时段爆发式扫描
- 通用 Web 漏洞扫描,覆盖面广但深度一般
三号:l9explore/1.2.2(87 次)
- 秘密文件/目录扫描器,专门探测
.git/config、readme.html、备份文件等 - 在 22 日 11:00 时段出现,与 PHP 扫描波次错开
2.4 扫描波次时间线:脉冲 + 持续背景的双层结构
-1024x682.png)
扫描不是匀速的,而是“脉冲 + 持续背景”的双层结构:
- libredtail 与 PHP 攻击高度重合——几乎每一波 libredtail 的出现,都对应着 PHP 漏洞攻击的峰值。这进一步确认了 libredtail 就是 PHP 专项扫描器。
- Go Web Pentest Tool 集中在深夜——23:00 一波流,128 条请求打完就走,疑似自动定时任务。
- l9explore 在午间出现——独立波次,与 PHP 扫描无关,属常规互联网测绘。
- PHP 更新发布后扫描频率上升——22 日 14:00 那波(51 次 PHP 攻击)是全天峰值,正好在 PHP 补丁发布约 16 小时后。
脉冲的强度很惊人:libredtail-http 曾在 1 分钟内连发 47 条请求(来自 165.154.218.226),且同一工具族在 5~6 个不同 IP 间轮换作业——按 IP 封几乎没意义,按特征封才有效。其余攻击则以每小时 7~67 行的背景噪声 21 小时不断。
2.5 攻击链三段式:侦察 → 探针 → 武器化
D1 的数据能拼出完整的阶段化作业流。时间线上看得很清楚:
- 资产收割(侦察)——
l9explore先到,专门找.git/config、.env、备份文件、配置泄露(78 次配置探测)。这一步是在摸”值不值得深入打”。 - 宽覆盖探针——
Go Web Pentest Tool和libredtail的 PHPUnit/ThinkPHP/TBK/穿越族轮番上场,127 次 PHPUnit 探测、30 次 CGI 注入、2 次 ThinkPHP,404 居多但覆盖面极广。 - 武器化装载——
php2shell-109618携 PoC 直击特定入口,出现在 l9explore 与 PHPUnit 扫描之后。
扫描是武器化的前置侦察。对防御方来说,能在第 1、2 段拦住,成本远低于第 3 段得手后再处置。
2.6 老 CVE 永不死:一个工具箱里的十五年
同一批扫描请求里,共存着跨越 14 年的利用代码:
- CVE-2012-1823(PHP-CGI 参数注入,2012)
- CVE-2017-9841(PHPUnit eval-stdin,2017)
- CVE-2021-41773(Apache 路径穿越,含
%%32%65双编码变体,2021) - CVE-2024-4577(PHP-CGI 编码绕过,2024)
- CVE-2026-109618(PHP cgi OOM RCE,2026)
十四年跨度的利用代码在同一次扫描会话里轮番出现。 不是因为攻击者怀旧,而是自动化工具箱”全量过一遍”的作业模式——只要目标面上还残留任何一个未修补组件,宽覆盖扫描就有收益。
防御侧的”已修补”是逐组件的,攻击侧的”全打一遍”是批量的——长尾旧漏洞的暴露面清理价值被系统性低估了。
2.7 行为细节里的攻防不对称
假 200 迷惑了攻击者,也提醒了防御者。 php-cgi 注入族有 18 次拿到 200 状态码、ThinkPHP 探针 3 次 200——但全部是 WordPress 把探测路径当搜索词渲染出来的假 200(error.log 无 PHP 异常可佐证)。攻击者靠状态码很难分辨真假;防守方只要比对一下响应字节数(69KB 与首页一致)就能识别——“默认应用行为即蜜罐”是零成本防御。
载荷自托管源 = 攻击源。 TBK 族 23 次 device.rsp 注入,载荷 URL 的主机 160.119.66.206 与请求源 IP 完全相同——攻击者用同一台主机既投载荷又发攻击,是高价值 IOC 与溯源锚点。
3. 干货:PHP 漏洞利用载荷全解析
这一节是给 WAF 工程师和运维同学看的——所有 payload 都是蜜罐里实打实抓的,可以直接拿去写规则或自查。
3.1 PHP-CGI 参数注入:5 种编码变体
这是本次捕获中技术含量最高的攻击。利用的是 PHP-CGI 模式下的 query string 参数注入(CVE-2012-1823 类型的漏洞族),通过 URL 注入 -d 参数来修改 PHP 配置,最终结合 php://input 实现远程代码执行。

核心原理: 当 PHP 以 CGI 模式运行时,query string 中形如 -d key=value 的参数会被当作 PHP 命令行参数处理,从而修改 php.ini 配置。扫描器利用这一点注入:
allow_url_include=1—— 开启 URL 包含auto_prepend_file=php://input—— 将 POST body 作为 PHP 代码自动前置执行
5 种编码变体一览:
| # | 路径 | 编码方式 | 状态码 |
|---|---|---|---|
| 1 | /?%ADd+allow_url_include%3d1+%ADd+auto_prepend_file%3dphp://input | 单编码 -d | 200 |
| 2 | /index.php?%25ADd+allow_url_include%3D1+%25ADd+auto_prepend_file%3Dphp://input | 双编码(%→%25) | 200 |
| 3 | /index.php?-d+allow_url_include%3don+-d+auto_prepend_file%3dphp%3a//input | 明文 -d | 200 |
| 4 | /hello.world?%ADd+allow_url_include=... | 单编码 + 伪路径 | 404 |
| 5 | /test.hello?%25ADd+allow_url_include=... | 双编码 + 伪路径 | 404 |
为什么用
%ADd代替-d?%AD是 URL 编码的软连字符(,U+00AD),某些 WAF 不会把它识别为-号,但 PHP 在解析时会将其等同于减号。这是一个典型的 WAF 绕过手法。而
%25AD则是双重 URL 编码——%本身被编码成%25,目的是绕过那些只做一次解码的 WAF。
3.2 PHPUnit eval-stdin.php:37 种路径穷举
CVE-2017-9841 是 PHPUnit 中的一个远程代码执行漏洞——eval-stdin.php 文件会直接执行标准输入中的 PHP 代码。这个文件本应只在测试环境中存在,但大量项目误将 vendor/ 目录部署到了生产环境的 Web 根目录下。
扫描器的策略非常粗暴:穷举所有可能的路径组合。
基础路径变体(4 种):
/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php/vendor/phpunit/phpunit/Util/PHP/eval-stdin.php/phpunit/phpunit/src/Util/PHP/eval-stdin.php/phpunit/phpunit/Util/PHP/eval-stdin.php
子目录前缀(27 种,覆盖主流框架):
| 类别 | 前缀 |
|---|---|
| 通用部署 | public/, api/, app/, lib/, cms/, crm/, blog/, admin/, panel/, apps/, backup/, V2/ |
| 框架名 | laravel/, yii/, zend/, workspace/drupal/ |
| 测试目录 | test/, tests/, testing/ |
| 其他 | ws/, www/, demo/, ws/ec/, vendor/vendor/ |
每个子目录前缀 × 每种基础路径 = 37 种组合,一次性打完。
3.3 ThinkPHP RCE 与 Pearcmd LFI
除了上面两类主力攻击,扫描器还顺手探测了另外两个 PHP 相关漏洞:
- ThinkPHP RCE:
/index.php?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=md5&vars[1][]=Hello—— 经典的 ThinkPHP 5.x 远程代码执行利用链,用md5("Hello")作为验证回显。 - Pearcmd LFI/RCE:
/index.php?lang=../../../../../../../../usr/local/lib/php/pearcmd&+config-create+/&/<?echo(md5("hi"));?>+/tmp/index1.php—— 利用 Pear 命令行工具的config-create参数实现文件写入,进而 getshell。
4. WAF 规则速查 & 自查指南
所有上面提到的 payload,都可以直接用于配置 WAF 规则,或者用来检查自己的服务器有没有被扫描过。

自查命令
如果你想快速检查自己的 access log 里有没有这些攻击痕迹,可以直接跑:
# 检查 PHP-CGI 参数注入
grep -E "allow_url_include|auto_prepend_file" access.log
# 检查 PHPUnit RCE 探测
grep -E "phpunit.*eval-stdin" access.log
# 检查 ThinkPHP RCE
grep -E "think\\\\app|invokefunction" access.log
# 检查路径穿越(双编码)
grep -E "%%32%65|%2e%2e.*bin/sh" access.log
# 检查 Pearcmd 利用
grep -E "pearcmd|config-create" access.log
关键拦截特征(WAF 规则优先级建议)
| 优先级 | 规则 | 匹配位置 |
|---|---|---|
| P0 | allow_url_include.*auto_prepend_file | URI query |
| P0 | php://input | URI query + body |
| P1 | phpunit.*eval-stdin\.php | URI path |
| P1 | think\\app.*invokefunction | URI query |
| P1 | pearcmd.*config-create | URI query |
| P2 | %%32%65(双编码 ..) | URI path |
| P2 | %ADd\+(软连字符 -d) | URI query |
注意:以上规则建议在测试环境验证后再上线,避免误拦截正常业务。尤其是
php://input可能会影响使用 JSON body 的 API。
5. 蜜罐其他情报简报
前面说过,B 机节点主要抓 IoT 蠕虫和暴力破解,这里简要带过(详细数据留到周报里再说):
- 9635 条事件,其中 SSH 2297 条、TELNET 2013 条、TCP 5292 条、HTTP 33 条
- 3140 次真实登录尝试(SSH 2295 + TELNET 845),Top1 是
admin/admin(86 次),字典攻击是常态背景 - IoT 蠕虫三个变种指纹齐活:
/bin/busybox HISILICON×67(海思芯片定向蠕虫,老熟人)/bin/busybox DUWa9d4D×17(本轮新见指纹,首次捕获到)ping; sh×93(利用 shell 解析缺陷直接 spawn,先拿 shell 再投喂)
- 落盘工程化:dropper 模板
>/tmp/.x && cd /tmp出现 10 个目录变体(/tmp/、/var/run/、/mnt/、/dev/、/etc/、/usr/等),Mirai stage-1 同款多目录触碰——目录随机化是对抗查杀的常规动作,检测必须按行为模式而非固定路径 - 跨协议侦察:MySQL 握手层探测
mysql_old_password/caching_sha2_password认证协商(×108)、FTP 层AUTH TLS/SSL安全探测(×13)、HTTP 层 CONNECT 代理滥用——蠕虫的协议覆盖面远超单端口假设 - RULE + LLM 双层标注管线:RULE 命中 614 条(零成本规则前置,可卸载 LLM ~90% 已知命中),LLM 标注 711 条(异常命令/异常 MySQL/疑似密码泄露等,留给未知变异)
6. 结语:蜜罐只是开始
部署蜜罐的初衷,是想亲眼看看「PHP 关键安全补丁发布后,公网扫描器有多快跟上」。20 小时的捕获结果确实有点超出预期了(我还以为我能够几小时内就捕获到呢)。
后续计划:
- 持续捕获,观察 PoC 公开后的攻击演变
- 部署态势感知大屏,实时可视化攻击数据
- 整理 IP 黑名单,开放给社区使用
敬请期待。
数据来源:蜜罐部署 D1 捕获记录(2026-10-21 ~ 2026-10-22 UTC),已脱敏处理,所有 IP 均经 RFC5737 占位映射。





发表回复