Nginx range 过滤器整形溢出漏洞 (CVE–2017–7529)预警分析
2017-07-13 11:05

Author: shilei && redrain@360CERT

I. 背景介绍

II. 漏洞概述

III. 漏洞攻击面影响

影响面
影响版本
修复版本

IV. 修复建议

V. 漏洞详情

简要技术细节

VI. 漏洞利用验证

VII. 时间线

VIII. 参考来源

I. 背景介绍

A security issue was identified in nginx range filter. A specially crafted request might result in an integer overflow and incorrect processing of ranges, potentially resulting in sensitive information leak (CVE-2017-7529).

-- http://mailman.nginx.org/pipermail/nginx-announce/2017/000200.html

2017年7月11日,Nginx在官方公告中称发现了一个范围过滤器中的安全问题,并分配了CVE-2017-7529。通过精心构造的恶意请求能造成整数溢出,对范围值的不当处理会导致敏感信息泄漏。

II. 漏洞概述

当使用Nginx标准模块时,攻击者可以通过发送包含恶意构造range域的header请求,来获取响应中的缓存文件头部信息。在某些配置中,缓存文件头可能包含后端服务器的IP地址或其它敏感信息,从而导致信息泄露。

III. 漏洞攻击面影响

影响面

该漏洞影响所有0.5.6 - 1.13.2版本内默认配置模块的Nginx只需要开启缓,存攻击者即可发送恶意请求进行远程攻击造成信息泄露。

当Nginx服务器使用代理缓存的情况下,攻击者通过利用该漏洞可以拿到服务器的后端真实IP或其他敏感信息。

通过我们的分析判定,该漏洞利用难度低,可以归属于low-hanging-fruit的漏洞。在真实网络攻击中也有一定利用价值。

影响版本

Nginx version 0.5.6 - 1.13.2

修复版本

Nginx version 1.13.3, 1.12.1

IV. 修复建议

官方补丁已经在7月11日发布

http://mailman.nginx.org/pipermail/nginx-announce/2017/000200.html

http://nginx.org/download/patch.2017.ranges.txt

建议受影响用户尽快升级至1.13.3, 1.12.1或及时patch

V. 漏洞详情

简要技术细节

通过查看patch确定问题是由于对http header中range域处理不当造成,焦点在ngx_http_range_parse函数中的循环:

enter image description here

enter image description here

HTTP头部range域的内容大约为Range: bytes=4096-8192

bytes=<start>-<end>,字符串指针p中即为“bytes=”后面的内容

这段代码是要把“-”两边的数字取出分别赋值给start和end变量,标记读取文件的偏移和结束位置。

对于一般的页面文件这两个值怎么玩都没关系。但对于有额外头部的缓存文件若start值为负(合适的负值),那么就意味着缓存文件的头部也会被读取。

一个缓存文件的例子:

enter image description here

如此我们来看看如何构造Range内容才能把start设计为负值。

首先代码中cutoff和cutlim阀量保证了每次直接从串中读取时不会令start或end成负值。那么能令start为负的机会仅在suffix标记为真的小分支中。

因此我们需令suffix = 1,由此可推知Range的内容必然为Range:bytes=-xxx,即省略初始start值的形式。

那么我们可以通过Range中设end值大于content_length(真正文件的长度),这样start就自动被程序修正为负值了。

但是在写利用过程中发现一个问题,若end值很大那么start的绝对值也会很大,会超过缓存文件的起始头部,造成读取失败。若end值不够大,那么换算下来size = end – 1 >= content_length (end > content_length见前文所述),就不能通过循环外面的检测:

enter image description here

这样的话似乎无论设end为何值都无法达成利用了。继续跟进代码发现这个循环是个无条件循环:

enter image description here

尾部为:

enter image description here

也就是说若Range域形如Range: bytes=start-end,start1-end1,…,就还有机会继续完成利用。

我们可以构造一个Range: bytes=-X, -Y

一大一小两个end值,只需要控制前面一个end值小而后一个end值大,从而实现start值和size值皆为负数,控制start值负到一个合适的位置,那么就能成功利用读到缓存文件头部了。

VI. 漏洞利用验证

Nginx 默认模块配置开启缓存:

enter image description here

缓存文件内容如下:

enter image description here

利用漏洞成功读取反向越界读出491字节:

enter image description here

VII. 时间线

2017-7-11 Nginx官方发布安全通告和patch

2017-7-12 360CERT( https://cert.360.cn)完成漏洞分析和利用情况分析

2017-7-13 发布该预警分析通告

VIII. 参考来源

http://mailman.nginx.org/pipermail/nginx-announce/2017/000200.html

http://nginx.org/download/patch.2017.ranges.txt