事件经过
2021年3月28日,php-src的master分支在git.php.net上出现了两个提交,推送者署名为PHP创始人Rasmus Lerdorf和核心开发者Nikita Popov。提交标题为“[skip-ci] Fix typo”——这个主题小到足以跳过审查,而且借助skip-ci前缀,还被设计成绕过持续集成。该改动位于一个被广泛包含的头文件中,它检查服务器变量中的HTTP User-Agent,如果该值以字符串“zerodium”开头,就把头文件剩余部分作为PHP代码执行:在任何运行被污染解释器的服务器上实现远程代码执行。
它没有得逞,原因很有启发性:社区成员在阅读公开信息流时,数小时内就发现了这些提交——一位评论者在提交本身上标记了该改动,PHP开发者Jake Birchall确认它会执行来自user-agent头的代码。Popov当晚宣布,一切迹象都指向git.php.net服务器被入侵,而非任何个人账户。提交文本本身带有这样一行:“REMOVETHIS: sold to zerodium, mid 2017”,暗示该后门多年前已被兜售给一家漏洞利用供应商。
项目的应对是移除该资产,而非修复它。git.php.net当场停用;此前一直处于次要地位的GitHub镜像成为规范仓库;写权限转移到php GitHub组织,成员资格要求双因素认证;所有PHP发布暂停两周,同时对仓库进行审计以排查进一步污染。这两个提交从未到达任何最终用户。
代价
没有最终用户受到影响——两个提交在任何发布之前都已被回滚。真正的代价是项目自身的git基础设施,以及所有PHP发布被冻结两周。
原因
项目运行自己的git服务器,并使用自研的karma系统管理写权限——这是一个定制化的认证面,小型核心团队必须完全独自防守。
该服务器上的提交身份依赖推送时的签核,而非加密签名,因此任何控制服务器的人都可以冒充项目最受信任的名字提交。
伪装针对审查流程做了调校:一个单词的“typo”修复,位于几乎处处包含的头文件中,并加上前缀以完全跳过CI。
拯救了项目的GitHub镜像多年来一直是二等副本——之所以可恢复,只是因为团队选择在紧急情况下将它们提升为主。
教训
自托管版本控制不会给项目带来任何好处,只会带来一个必须独自防守的攻击面。镜像只有在需要它们的那一刻就准备好成为事实来源时,才会有所回报。
后续
php.net在调查进行期间正式将发布暂停两周,并表示这些恶意提交“被立即发现并回滚,因此从未到达最终用户”。仓库经过审查,以排查这两个提交之外的污染;GitHub成为php-src的永久规范家园,组织成员资格现在要求2FA。后门的代码注释——“sold to zerodium, mid 2017”——仍公开留在提交历史中;该供应商从未确认购买过它。
从这里,追溯依据
参考来源
- Changes to Git commit workflow (php.internals #113838) news-web.php.net · news-web.php.net ·
- PHP releases on hold php.net · php.net ·
- [skip-ci] Fix typo (commit c730aa26) GitHub php/php-src · github.com ·
- PHP's Git server hacked to add backdoors to PHP source code BleepingComputer · bleepingcomputer.com ·