CVE-2019-11043(FPM 远程代码执行漏洞)¶
漏洞描述¶
CVE-2019-11043 是一个远程代码执行漏洞,使用某些特定配置的 Nginx + PHP-FPM 的服务器存在漏洞,可允许攻击者远程执行代码。
向Nginx + PHP-FPM的服务器 URL发送 %0a 时,服务器返回异常。
影响版本¶
在 Nginx + PHP-FPM 环境下,当启用了上述 Nginx 配置后,以下 PHP 版本受本次漏洞影响,另外,PHP 5.6版本也受此漏洞影响,但目前只能 Crash,不可以远程代码执行:
- PHP 7.0 版本
- PHP 7.1 版本
- PHP 7.2 版本
- PHP 7.3 版本
环境配置¶
- Vulhub项目
- Docker-compose启动

漏洞复现¶
工具复现¶
首先安装go环境
下载工具
MSF复现¶

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

从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 len = script_path_translated_len;
len为url路径长度
当请求url为http://127.0.0.1/index.php/123%0atest.php
script_path_translated来自于nginx的配置,为/var/www/html/index.php/123\ntest.php
ptlen则为url路径第一个斜杠之前的内容长度
当请求url为http://127.0.0.1/index.php/123%0atest.php
pt为/var/www/html/index.php
这两个变量的差就是后面的路径长度,由于路径可控,则path_info可控。

由于path_info可控,在1222行我们就可以将指定地址的值置零,根据漏洞发现者的描述,通过将指定的地址的值置零,可以控制使_fcgi_data_seg结构体的char* pos置零。
Important
exp作者通过开启自动包含,并设置包含目录为/tmp,之后设置log地址为/tmp/a并将payload写入log文件,通过auto_prepend_file自动包含/tmp/a文件构造后门文件
PHP-fpm 远程代码执行漏洞(CVE-2019-11043)分析
修复建议¶
在经过对漏洞的深入研究后,我们推荐两种方案修复这个漏洞。
- 临时修复:
修改nginx相应的配置,并在php相关的配置中加入
在这种情况下,会有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
Important
漏洞利用条件:
1、Nginx + php_fpm,且配置location ~ [^/]\.php(/|$)会将请求转发到php-fpm。
2、Nginx配置fastcgi_split_path_info并且以^开始以$,只有在这种条件下才可以通过换行符来打断正则表达式判断。 ps: 则允许index.php/321 -> index.php
3、fastcgi_param中PATH_INFO会被定义通过fastcgi_param PATH_INFO $fastcgi_path_info;,当然这个变量会在fastcgi_params默认定义。
4、在nginx层面没有定义对文件的检查比如try_files $uri =404,如果nginx层面做了文件检查,则请求不会被转发给php-fmp。