前言
在漏洞复现的过程中,我并不想单纯地复现漏洞,而是想要找出漏洞成因和原理,不想当一个脚本小子。
我在了解这些漏洞的过程中,发现国内的很多文章中漏洞原理和成因都解释得不清不楚,想要完全搞清楚一个漏洞的成因十分困难,有时甚至花上一天去研究一个漏洞的成因,于是我决定将我所理解的知识点详细记录下来。
Nginx介绍
Nginx(engine X)是一款轻量级的Web服务器、反向代理服务器,由于它的内存占用少,启动极快,高并发能力强,在互联网项目中广泛应用。
简单来说,代理就像一个中介。
我们借助VPN来访问一些网站,而VPN就是一个正向代理的例子。我们向VPN发送请求,VPN再把我们的请求发送给目标服务器,而目标服务器并不知道我们真实的IP地址,只知道与他交互的人(正向代理服务器)。所以可知正向代理是代理客户端(我们)的。
而反向代理中,代理是代理服务端的。我们客户端不需要进行任何配置,即可发送请求给对方网站,发送的请求会通过反代理服务器,然后反代理服务器再把请求传给最终的目标服务器,最后返回给客户端,而我们是不知道真实的目标服务器IP地址的。所以可知,反向代理代理目标服务器。
Nginx解析漏洞
漏洞介绍
该漏洞与nginx
、php
版本无关,是用户配置不当造成的漏洞。
漏洞原理
什么是CGI
CGI是外部应用程序与WEB服务器之间的接口标准。CGI规范允许Web服务器执行外部程序,并将它们的输出发送给Web浏览器,CGI将Web的一组简单的静态超媒体文档变成一个完整的新的交互式媒体。
那么我们就把他理解成是WEB服务器与程序之间的一种接口就好了。
Fastcgi、Nginx和PHP解析器的关系
首先,fastcgi
是一种协议,全称 快速通用网关接口(FastCommonGatewayInterface)
,是升级版的CGI。
这里我们只需要了解他们的运作流程。
如果web server(nginx)
收到请求/index.php
后,会开始查找文件,知道这不是一个静态文件后,需要找PHP
解析器来处理,而在交给PHP
解析器处理之前,需要fastcgi
来规定传什么数据或什么格式给PHP
解析器,之后PHP解析器会解析php.ini
,处理请求,处理后把结果返回给浏览器。
PATH_INFO和SCRIPT_FILENAME
我们刚刚说到了fastcgi
、Nginx
和PHP
解析器的关系,那么现在来说下漏洞涉及到的配置。
什么是PATH_INFO?
举一个例子,当你访问网址/hello.php/id/123
的时候,/id/123
便是你的PATH_INFO
什么是SCRIPT_FILENAME
在fastcgi
中的一个参数。当你访问网址/hello.php/id/123
的时候,/hello.php
便是你的SCRIPT_FILENAME
,即执行脚本的绝对路径。
转换成 PHP 中的变量就是
$_SERVER['SCRIPT_FILENAME']
,PHP 参考手册中对$_SERVER['SCRIPT_FILENAME']
参数说明为当前执行脚本的绝对路径。
漏洞成因
在nginx/default.conf
的配置文件中.php
后缀名的路径会交由fastcgi
协议的php
解析器处理。
当我们访问/shell.png/aaa.php
时,nginx不会对aaa.php
是否存在进行检查,而是直接将路径提交给fastcgi
,并将fastcgi
的SCRIPT_FILENAME
设为/shell.png/aaa.php
(上面有讲过该参数怎么得来的)
接着fastcgi
将这个参数SCRIPT_FILENAME
传给php
解析器(php-fpm)
这时候,PHP
解析器收到了这个SCRIPT_FILENAME
,但它发现aaa.php
并不存在,怎么办呢?
因为我们配置了cgi.fix_pathinfo=1
,所以php
会修正传过来的这个SCRIPT_FILENAME
,认为脚本执行的绝对路径不应该是/shell.png/aaa.php
而是存在的文件/shell.png
(他会根据提供的路径一直往上级目录找,直到找到存在的文件,但寻找到后他也不会判断找到的文件的后缀格式),同时PATH_INFO
应该是/aaa.php
所以我们所提交的/shell.png/aaa.php
请求,会被错误解析,从而引发安全漏洞 -> PHP
解析器会去解析非PHP
格式的shell.png
,而把/aaa.php
当作PATH_INFO
换句话说,PHP
解析器认为该执行的脚本是shell.png
,而后面的路径只是PATH_INFO
而已。
漏洞复现
准备一个冰蝎的PHP马,后缀改为jpg
格式,然后直接上传,发现提示
猜测是因为要检测文件头(具体没有研究),于是我重新上传一张正常的png
图,用burp suite
抓包修改
发送后得到地址
访问:
已被解析为php
文件,上冰蝎,成功:
Reference
Is the PHP option cgi-fix-pathinfo really dangerous with Nginx+PHP-FPM
Nginx(PHP/fastcgi)的PATH_INFO问题
Nginx 文件名逻辑漏洞(CVE-2013-4547)
漏洞介绍
影响版本:Nginx 0.8.41 ~ 1.4.3 / 1.5.0 ~ 1.5.7
错误地解析了用户请求,检测URI时的逻辑错误导致用户可以绕过对截断符%00
的检测,从而形成漏洞。
漏洞原理
从Nginx的配置文件中,我们可以看到,php
后缀的文件被交给了fastcgi
处理。fastcgi、Nginx和PHP解析器的关系 在之前的解析漏洞有提到。
假设我们尝试访问一个图片,访问的网址是/test.png \0.php
, nginx收到访问请求,开始判断这个是什么文件。nginx
会先检测URI
,发现在检测uri
的时候,nginx
会做如下检测:开始一个字节一个字节的检测,检测到\0
的时候会判断其为非法字符。
1 | case sw_check_uri: |
但代码中还有一层逻辑,就是当检测到有空格的时候,会执行到另一部分代码 sw_check_uri_http_09
中:这时候的ch
变成了我们的截断符%00
,这里没有满足它的case
,所以他将执行最后一段default
代码,即返回到sw_check_uri
中,这样\0
就并未检测到,也不会被判断为非法字符。
此时ch
又变成了下一个字符.
,之后被判断为PHP
文件,该请求被交给了fastcgi
处理,fastcgi
被\0
截断字符截断,所以最终交给PHP
解析器解析的地址是/test.png[空格]
,因此test[空格].png
将被解析为PHP
类。
漏洞复现
为了让截断符号不被检测到,我们需要用空格绕过检测,而空格应该在截断符号之前。需要注意的是,在windows环境下,空格是会被自动去掉的,而Linux是不可以去掉的。而我们的目标环境是Linux
,所以我们必须上传带有空格的图片,这样PHP解析器
才能找到这个文件,如果是Windows
,就不用带空格。
先用burp suite
抓包修改上传一个含木马的图片test.png[空格]
,
这里我以phpinfo()
作为检测。
上传后得到地址
访问文件test.png1
, 再次用burp suite
抓包修改。这里说下为什么要访问png1
- 我尝试过,直接访问test.png
的话,burp suite
是抓不到包的。
修改GET路径为/uploadfiles/test.png[空格][空格].png
,然后选中第二个空格修改hex值为00(截断符的意思)
修改完毕后再发送请求。
漏洞利用成功。
Reference
【漏洞复现】Nginx 文件名逻辑漏洞(CVE-2013-4547)
CVE-2013-4547 Nginx解析漏洞深入利用及分析
Nginx 目录穿越漏洞
漏洞介绍
该漏洞是用户配置不当造成的。
漏洞原理
在分析漏洞原理之前,这里我们先讲一下nginx
配置文件中alias
和root
的定义
alias
是目录别名
root
是最上层目录
root
1 | location /hello/ { |
alias
1 | location /hello/ { |
这个漏洞我们主要针对alias来说。
打开靶场的配置文件,我们可以看到location /files
后面没有以/
结尾
这意味着我们可以跨越到其他目录。
当我们访问/files..
的时候,/files
会变为/home/
,而我们访问的地址将是/home/..
,实际便跨越了目录。
漏洞复现
成功访问了上级目录