漏洞原理
补丁发布的日期是2017年7月11日15:48:23
所以我们可以到 github
上去查找修改的地方
可以看到做了一定的限制
- 图一修改,防止因为end的问题,导致
content_length-end
后的结果为负数,最后的结果无论如何都是0,而不会是负数了,对cache文件的读取也只能从0开始 - 图二修改,防止溢出后小于了size后绕过判断
正常情况下,如果我们 传入一串完整的range,那么他会检查 start
,保证不会溢出为负值
假如我们传入的范围是 1-1000
那么这里就是将 -
前后的两个数字分出来,分别赋值给 start
和 end
这两个函数,同时这里做了判断,不能是字符,同时也不能是负数,所以要动手脚的话,只能在后面运算的地方做
如果我们传入的end的值,是比 content_length
,文件内容的值大的,那么相减,start的值就是负数
在这种情况下,因为end的值会设定成centent_length-1,所以在后面的判断里肯定为 假
,因为range的范围早就超过了 content_length
if (size > content_length) {
return NGX_DECLINED;
}
正常情况来说,因为 -1
的关系,range的长度肯定是小于原始文件的长度的,所以一旦到了这一步,就直接原始文件返回,不进行range处理,为了绕过if判断,就需要将size整数溢出了
-----分割线-----
我们在测试的时候,需要将start的值设置为负数,这样在读取的时候,nginx才会将缓存文件前面的内容读取出来
假设我们的值为 7877
,那么为了读取前面的值,就得7877加上600=8477
我们给它第一个值为 -8477
,这个值是函数 end
的值,在运算的时候,start就等于了文件总长度7877减去end的值8477,最后等于负数-600,而end就等于8476
第一个值计算过后,此时的size值本应该不为8477的(下面为size的计算方法)
代码语言:javascript复制size = end - start
但是注意到第 362行
的一个判断
因为前面算的end的值是大于文件长度的,所以在这里会被强行等于原始文件的长度,那么到后面计算的时候
就会变成了 7877-(-600)=7877 600=8477
因为需要整数溢出,所以最后size的值得是 0x8000000000000000
,所以我们给的第二个range值要在这个基础上计算
那么 0x8000000000000000-8477
的值就是range2的值了
这里计算出来的结果是 9223372036854767331
第二个值进入的时候,因为size是 =
所以就相当于是 range2 range1,最后的值刚好就能整数溢出了
于是便绕过了这个判断,最后请求的range范围便是-600到文件结束,从而导致信息泄露
代码语言:javascript复制if (size > content_length) {
return NGX_DECLINED;
}