【漏洞分析】Nginx range 过滤器整形溢出漏洞 (CVE–2017–7529)预警分析

https://p0.ssl.qhimg.com/t017347ebbc659bfd5a.jpg

作者:shilei && redrain@360CERT

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 函数中的循环:

http://p5.qhimg.com/t01d18067385431b26c.png

http://p1.qhimg.com/t0110553aa2b3176253.png

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

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

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

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

一个缓存文件的例子:

http://p3.qhimg.com/t01b892526a43ba8c5e.png

如此我们来看看如何构造 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 见前文所述)就不能通过循环外面的检测:

http://p5.qhimg.com/t01e1464c19dba79ce1.png

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

http://p8.qhimg.com/t0135975cd5ee3269c8.png

尾部为:

http://p4.qhimg.com/t01fc99948f9535e396.png

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

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

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

 

VI.漏洞利用验证

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

http://p1.qhimg.com/t014aa0ac7ce87b5209.png

缓存文件内容如下:

http://p9.qhimg.com/t017998a038120ea5c1.png

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

http://p6.qhimg.com/t0198f78776796ac67a.png

 

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

 

(完)