导语:2026年5月22日,一个平平无奇的周四深夜,Laravel开发者们还不知道,他们依赖了多年的翻译包已经悄然变天。一名攻击者在两个小时内,重写了Laravel-Lang组织下4个包的全部历史Git标签,将它们全部指向了一个攻击者可控的恶意fork。这次攻击不发布任何新版本号,不修改任何”正式”提交记录——而是直接对历史动手脚。等开发者反应过来时,云凭证、CI/CD密钥、GitHub Token可能已经躺在了攻击者的服务器上。
一、攻击手法:不是改代码,是改”指针”
在聊这次攻击之前,先科普一个小背景:Git的标签(tag)和GitHub的版本发布(release)是两回事。标签只是一个指向某个特定提交的指针,理论上可以随时被force push到另一个完全不同的提交。这是Git设计层面的”漏洞”,官方其实早就知道,但这次真的被人玩出了花。
攻击者没有在代码库里添加任何可疑的新文件,没有修改composer.json的版本号,也没有上传任何带恶意后缀的新版本。他只是拿到了一枚组织级的推送凭证,然后在夜里22:32 UTC开始,一个标签接一个标签地,把它们全部force push到自己的恶意fork里的新提交上。

到次日凌晨00:00 UTC,laravel-lang/lang的502个标签、laravel-lang/http-statuses的233个标签、laravel-lang/attributes的86个标签,以及laravel-lang/actions的46个标签——全部阵亡。换句话说,只要开发者的composer.lock里没有锁定具体的旧提交SHA,任何一次composer update都会自动resolve到这批”被污染”的标签。
为什么说这个手法很妙? 正常思维下,供应链攻击是”发布一个恶意新版本”,等着别人来踩坑。但攻击者反其道而行:不动新版本,动旧版本——而且改了所有人以为最可靠的历史记录。红队这边只能说:这波操作,我给满分。
二、恶意代码怎么跑起来的:Composer的”自动执行”陷阱
光改了标签还不够,代码得被执行才有意义。攻击者的切入点非常精准——利用了Composer的三种autoload模式中的”files”模式。
Composer支持三种自动加载方式:psr-4(懒加载)、classmap(懒加载)、以及files(饿加载)。前两种只在代码实际使用某个类时才加载对应文件,而files模式的厉害之处在于:只要require vendor/autoload.php,文件里列出的每个PHP文件都会立即被执行。
熟悉Laravel项目结构的读者应该知道,基本上每一个Laravel应用、Symfony应用,甚至是PHPUnit测试框架,都会在入口文件里写上require __DIR__.'/vendor/autoload.php'。这行代码本来只是加载依赖,但加上files autoload之后,就变成了一个”启动即执行”的触发器。
攻击者正是看准了这一点。他在每个被污染的提交里,只修改两个文件:composer.json和新增一个src/helpers.php。前者在autoload.files里加入helpers.php的引用,后者就是这个恶意payload的载体。
helpers.php里只写了很少的代码:去flipboxstudio.info(注意这个域名,和正经的flipboxstudio.com差了一个字母,是典型的typosquat)拉取第二阶段payload,写入/tmp下的一个随机隐藏文件名,然后用后台进程的方式执行。整个过程从加载到自删除不超过3秒。
妙在哪儿? 自删除。3秒之内,/tmp下的恶意文件就已经被rm掉了,但内存里的进程还在跑。 forensic团队事后去翻文件系统?什么都没有。这就是典型的”来无影去无踪”。
三、窃取目标:云凭证、CI/CD密钥,一个都不能少
StepSecurity在GitHub Actions隔离环境中实际 detonate(触发运行)了被污染的laravel-lang/http-statuses v3.4.5包,抓到了完整的攻击链路。
恶意loader运行后会向C2服务器POST它收集到的所有环境变量数据,受害者主机上但凡有点价值的东西,全被一网打尽:

结合BleepingComputer对第二阶段payload的分析,这个跨平台木马胃口相当大:
Linux/macOS载荷(由PHP loader动态获取):针对AWS密钥、GitHub Token、Kubernetes Secrets、Vault Token、SSH私钥、CI/CD环境变量(GitHub Actions的RUNNER_TEMP下的runner文件命令)、.env配置文件、云服务商(AWS/GCP/Azure)凭证、Slack Token、Stripe密钥、数据库连接信息、JWT令牌等。能正则匹配提取的,全部匹配。
Windows载荷(内嵌在PHP文件中的base64编码可执行文件):专门针对Chrome、Brave、Edge浏览器,提取App-Bound Encryption密钥以解密本地存储的凭证。此外还有一个PDB路径特征:C:UsersMeroOneDriveDesktopstuffclaudeChromium-DebugElevator——里面赫然写着”claude”,疑似攻击者借助AI工具辅助编写了这款Windows木马。
数据窃取完成后,加密回传到flipboxstudio.info,完成收网。
四、IOC指标:这几个特征请记下来
网络指标:
-
C2域名: flipboxstudio.info(与合法域名flipboxstudio.com对比,仅多了一个字母i→l的typosquat) -
GET请求: https://flipboxstudio.info/payload(Stage 1,下载载荷) -
POST请求: https://flipboxstudio.info/exfil(数据外传)
文件系统指标(攻击者自删除,但若能在运行后短时间内抓现场仍可见):
-
/tmp/.laravel_locale/(隐藏目录) -
/tmp/.laravel_locale/[随机6位hex].php(PHP loader) -
/tmp/.[随机12位hex](ELF二进制,无后缀) -
Windows: %TEMP%[随机.exe]
进程指标:
-
孤立的PHP进程,ppid=1(被init领养) -
孤立的未命名ELF进程,ppid=1 -
这类进程在 ps auxf里看不到父级关系,属于”断子绝孙”型进程存活方式
Git特征:
-
所有被污染标签的提交,作者名为”Your Name”,邮箱为 you@example.com——正常的开发者不会用这个 -
提交时间集中在2026-05-22 22:32 UTC到2026-05-23 00:00 UTC之间
五、影响规模:700+版本覆没,国内开发者影响几何?
Laravel-Lang系列包是Laravel生态中做多语言本地化的标配,其中laravel-lang/lang作为核心翻译包,在GitHub上star数颇高,被大量国内PHP项目直接或间接依赖。
受影响的四个包分别是:
-
laravel-lang/lang:502个标签,含502个版本 -
laravel-lang/http-statuses:233个版本 -
laravel-lang/attributes:86个标签 -
laravel-lang/actions:46个标签
这意味着:只要项目里用了这些包,并且composer.lock在2026-05-22之后重新生成过(composer update触发),无论用的是两年前的v1.0.0还是上周的v15.x,系统都会自动resolve到被污染的最新提交。
一个可怕的事实: 如果GitHub Actions里跑了composer update(而不是锁定lockfile的composer install),CI/CD runner的$GITHUB_TOKEN、AWS凭证、所有环境变量全部暴露。攻击者拿到这些密钥能干什么?横向移动、注册新的GitHub PAT、往云服务里开后门——都是常规操作。
六、修复与响应:四步走
第一步:立即冻结composer update
凡依赖了上述四个包的项目,在确认安全之前,不要运行composer update。如果composer.lock的SHA是2026-05-22之前生成的且未被改动,composer install仍安全。
第二步:检查lockfile,确认是否中毒
打开composer.lock,找到对应包的reference字段:
-
如果reference是 a5ea2e8fa92ccf29cdb1d2dadbeb27722b2bff37(laravel-lang/lang v15.29.5对应)、或bba2e443dc7ff1f8704f52a5375383e3f4f643b8(laravel-lang/http-statuses v3.4.5对应)等这些被污染的提交SHA——恭喜,已经中招。 -
如果lockfile在2026-05-22之后从未更新,但依赖的标签被force push过,reference同样会被更新为恶意SHA。
第三步:旋转所有暴露的凭证
一旦发现中招,或者无法确认是否中招,假设所有在那个运行环境中存在过的凭证均已泄露。至少包括:
-
GitHub PAT(个人访问令牌) -
$GITHUB_TOKEN(Actions runner token) -
云服务商凭证(AWS Access Key、GCP Service Account、Azure Credential) -
容器镜像仓库凭证(Docker Hub、ECR、GCR等) -
SSH私钥和deploy keys -
CI/CD provider令牌
第四步:检查系统进程
在CI/CD runner或开发者机器上运行ps auxf,寻找:
-
ppid=1的孤立PHP进程 -
ppid=1的未命名ELF进程 -
/tmp下是否存在. laravel_locale目录
如果有,那基本实锤。
七、为什么说这是一个标志性事件
这次攻击有三个地方值得安全社区警醒:
第一,Git标签的信任模型被打破。 多年来,大家默认”只要是GitHub上打了tag的版本就是可信的”。但Composer解析标签用的是git checkout v1.0.0——它只关心标签指向哪个提交,从来不检查这个提交是否”真的属于”这个仓库的主人。现在攻击者证明了:只要拿到推送权限,就能把一个历史tag悄悄指向别处,而100%看起来”完全正常”。
第二,”只更新了一次”的开发者也可能中招。 正常思维是”我不主动更新到恶意版本就没事”。但这次攻击改的是历史版本——你以为你在用的是v2.0.4″稳定版”,殊不知它已经不是原来那个v2.0.4了。
第三,供应链安全的检测盲区。 事件中Packagist在接报后迅速反应,暂时下架了受影响版本。但问题是:在Packagist处理之前,已经有多少CI/CD runner跑完了composer update?GitHub Actions的日志里有没有记录所有对外HTTPS请求?大多数团队对此是盲目的。这次StepSecurity的Harden Runner能够捕获到网络请求并告警,正是因为他们在runner层面做了出口流量监控——这不是可选项,已经是必选项。
八、总结
这事儿吧,得从两边儿看——红队这波供应链攻击的思路确实很巧妙:不改版本号、不发恶意新包,而是对历史Git标签动刀子,利用Composer的files autoload实现”启动即触发”,整个过程不超过3秒完成部署和自删除,非常职业。蓝队这边呢,反思一下:光靠锁版本号和信任GitHub release是不够的,CI/CD runner的出口流量监控、composer.lock的SHA校验、以及组织层面的MFA强制和凭证轮换,才是真的防线。
如果你正在用Laravel-Lang这几个包,建议现在就去查一查——别等攻击者先动了你的密钥。
版权声明:本文由华盟网原创发布,保留所有权利。配图由华盟网授权使用。
👇 点击阅读原文,访问我的网站



















暂无评论内容