Nginx漏洞复现系列
2023-06-15 17:12:39 # Web Security # Nginx

前言

在漏洞复现的过程中,我并不想单纯地复现漏洞,而是想要找出漏洞成因和原理,不想当一个脚本小子。

我在了解这些漏洞的过程中,发现国内的很多文章中漏洞原理和成因都解释得不清不楚,想要完全搞清楚一个漏洞的成因十分困难,有时甚至花上一天去研究一个漏洞的成因,于是我决定将我所理解的知识点详细记录下来。

Nginx介绍

Nginx(engine X)是一款轻量级的Web服务器、反向代理服务器,由于它的内存占用少,启动极快,高并发能力强,在互联网项目中广泛应用。

简单来说,代理就像一个中介。

我们借助VPN来访问一些网站,而VPN就是一个正向代理的例子。我们向VPN发送请求,VPN再把我们的请求发送给目标服务器,而目标服务器并不知道我们真实的IP地址,只知道与他交互的人(正向代理服务器)。所以可知正向代理是代理客户端(我们)的

反向代理中,代理是代理服务端的。我们客户端不需要进行任何配置,即可发送请求给对方网站,发送的请求会通过反代理服务器,然后反代理服务器再把请求传给最终的目标服务器,最后返回给客户端,而我们是不知道真实的目标服务器IP地址的。所以可知,反向代理代理目标服务器

Nginx解析漏洞

漏洞介绍

该漏洞与nginxphp版本无关,是用户配置不当造成的漏洞。

漏洞原理

什么是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

我们刚刚说到了fastcgiNginxPHP解析器的关系,那么现在来说下漏洞涉及到的配置。

什么是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解析器处理。

image-20210722142211210

当我们访问/shell.png/aaa.php时,nginx不会对aaa.php是否存在进行检查,而是直接将路径提交给fastcgi,并将fastcgiSCRIPT_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格式,然后直接上传,发现提示image-20210722150828954

猜测是因为要检测文件头(具体没有研究),于是我重新上传一张正常的png图,用burp suite抓包修改

image-20210722151008554

image-20210722151106496

发送后得到地址image-20210722151134510

访问:image-20210722151207147

已被解析为php文件,上冰蝎,成功:

image-20210722151257093

Reference

Is the PHP option cgi-fix-pathinfo really dangerous with Nginx+PHP-FPM

Nginx(PHP/fastcgi)的PATH_INFO问题

Nginx + PHP CGI的一个可能的安全漏洞

深入理解 PHP 项目关于 PATHINFO 使用问题

Nginx 文件名逻辑漏洞(CVE-2013-4547)

漏洞介绍

影响版本:Nginx 0.8.41 ~ 1.4.3 / 1.5.0 ~ 1.5.7

错误地解析了用户请求,检测URI时的逻辑错误导致用户可以绕过对截断符%00的检测,从而形成漏洞。

漏洞原理

image-20210722230026675

从Nginx的配置文件中,我们可以看到,php后缀的文件被交给了fastcgi处理。fastcgi、Nginx和PHP解析器的关系 在之前的解析漏洞有提到。

假设我们尝试访问一个图片,访问的网址是/test.png \0.php, nginx收到访问请求,开始判断这个是什么文件。nginx会先检测URI,发现在检测uri的时候,nginx会做如下检测:开始一个字节一个字节的检测,检测到\0的时候会判断其为非法字符。

1
2
3
4
5
6
7
8
9
case sw_check_uri:      
……
case '.':
r->complex_uri = 1; //此作为flag会判断使用ngx_http_parse_complex_uri方法,对路径修复
state = sw_uri;
break;
……
case '\0': //当遇到\0时,将会判断为非法字符
return NGX_HTTP_PARSE_INVALID_REQUEST;

但代码中还有一层逻辑,就是当检测到有空格的时候,会执行到另一部分代码 sw_check_uri_http_09中:这时候的ch变成了我们的截断符%00,这里没有满足它的case,所以他将执行最后一段default代码,即返回到sw_check_uri中,这样\0就并未检测到,也不会被判断为非法字符

image-20210722232400410

此时ch又变成了下一个字符.,之后被判断为PHP文件,该请求被交给了fastcgi处理,fastcgi\0截断字符截断,所以最终交给PHP解析器解析的地址是/test.png[空格],因此test[空格].png将被解析为PHP类。

漏洞复现

为了让截断符号不被检测到,我们需要用空格绕过检测,而空格应该在截断符号之前。需要注意的是,在windows环境下,空格是会被自动去掉的,而Linux是不可以去掉的。而我们的目标环境是Linux,所以我们必须上传带有空格的图片,这样PHP解析器才能找到这个文件,如果是Windows,就不用带空格。

先用burp suite抓包修改上传一个含木马的图片test.png[空格]

image-20210723000546878

image-20210723000742595这里我以phpinfo()作为检测。

上传后得到地址

image-20210722234129588

访问文件test.png1, 再次用burp suite抓包修改。这里说下为什么要访问png1 - 我尝试过,直接访问test.png的话,burp suite是抓不到包的。

image-20210722234425902

修改GET路径为/uploadfiles/test.png[空格][空格].png,然后选中第二个空格修改hex值为00(截断符的意思)

image-20210722234823479

修改完毕后再发送请求。

image-20210723000838302

漏洞利用成功。

Reference

【漏洞复现】Nginx 文件名逻辑漏洞(CVE-2013-4547)

CVE-2013-4547 Nginx解析漏洞深入利用及分析

Nginx 目录穿越漏洞

漏洞介绍

该漏洞是用户配置不当造成的。

漏洞原理

在分析漏洞原理之前,这里我们先讲一下nginx配置文件中aliasroot的定义

alias是目录别名

root是最上层目录

root

1
2
3
4
location /hello/ {
root /var/www/image
}
# 若按照上述配置的话,访问/hello目录里面的文件时, nginx会自动去/var/www/image/hello去找

alias

1
2
3
4
location /hello/ {
alias /var/www/image/
}
# 若按照上述配置的话,访问/hello目录里面的文件时, nginx会自动去/var/www/image目录找文件

这个漏洞我们主要针对alias来说。

打开靶场的配置文件,我们可以看到location /files后面没有以/结尾

image-20210725140009372

这意味着我们可以跨越到其他目录。

当我们访问/files..的时候,/files会变为/home/,而我们访问的地址将是/home/..,实际便跨越了目录。

漏洞复现

image-20210725140308072

成功访问了上级目录

Reference

Nginx: nginx配置文件中的 alias 和 root