加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

ngx_lua_waf利用HPP完全绕过防御机制

发布时间:2020-12-14 21:57:00 所属栏目:大数据 来源:网络整理
导读:漏洞概要 关注数( 81 )? 关注此漏洞 缺陷编号: WooYun-2015-104525 漏洞标题: ngx_lua_waf利用HPP完全绕过防御机制? 相关厂商: ngx_lua_waf 漏洞作者: phith0n 提交时间: 2015-03-31 11:12 公开时间: 2015-06-30 13:50 漏洞类型: 设计缺陷/逻辑错误

漏洞概要关注数(81)?关注此漏洞

缺陷编号: WooYun-2015-104525

漏洞标题: ngx_lua_waf利用HPP完全绕过防御机制?

相关厂商: ngx_lua_waf

漏洞作者: phith0n

认证白帽子

提交时间: 2015-03-31 11:12

公开时间: 2015-06-30 13:50

漏洞类型: 设计缺陷/逻辑错误

危害等级: 高

自评Rank: 12

漏洞状态: 已交由第三方合作机构(cncert国家互联网应急中心)处理

漏洞来源: http://www.wooyun.org,如有疑问或需要帮助请联系?help@wooyun.org

Tags标签:?白盒测试

17人收藏? 收藏
分享漏洞:

1


漏洞详情

披露状态:

2015-03-31: 细节已通知厂商并且等待厂商处理中
2015-04-01: 厂商已经确认,细节仅向厂商公开
2015-04-04: 细节向第三方安全合作伙伴开放(绿盟科技、唐朝安全巡航)
2015-05-26: 细节向核心白帽子及相关领域专家公开
2015-06-05: 细节向普通白帽子公开
2015-06-15: 细节向实习白帽子公开

简要描述:

这个洞比较有意思,利用代码中的一段错误,导致我们可以利用hpp来完全绕过防御规则。
WAF绕过中,对规则与正则的绕过总是有局限性的。这个洞也如我之前发的360webscan白名单绕过一样,不管你用怎样严格的正则,防御怎样的攻击,我这里直接无视。
不过与360webscan使用pathinfo来绕过不一样,我这里利用的是hpp(HTTP Parameter Pollution)。
这是不是乌云里第一个lua白盒审计漏洞~

详细说明:

首先,ngx_lua_waf是基于lua-nginx-module的一个灵活性很强的WAF,并且相对于脚本层的WAF(如360webscan等),效率也是相对高很多的。在drops里也对大家做了一些介绍:http://**.**.**.**/tips/5136

项目地址为:https://**.**.**.**/loveshell/ngx_lua_waf

看到ngx_lua_waf下init.lua的代码:https://**.**.**.**/loveshell/ngx_lua_waf/blob/master/init.lua 92行

code 区域
function args()
for _,rule in pairs(argsrules) do
local args = ngx.req.get_uri_args()
for key,val in pairs(args) do
if type(val)=='table' then
if val == false then
data=table.concat(val," ")
end
else
data=val
end
if data and type(data) ~= "boolean" and rule ~="" and ngxmatch(unescape(data),rule,"imjo") then
log('GET',ngx.var.request_uri,"-",rule)
say_html()
return true
end
end
end
return false
end



如上,args函数是针对GET请求的防御函数。argsrules是预置的规则table。

local args = ngx.req.get_uri_args(),这句话获取了GET变量作为局部变量args的值。

下面的for循环遍历args变量,key和val就是GET的键和值。

很奇怪的是这一段:

if type(val)=='table' then
if val == false then
data=table.concat(val," ")
end
else



先判断val的类型是否是table类型,如果是再判断他是否等于false。

这个逻辑明显有问题(既然是table,为何又等于false?),不知道是不是因为作者的笔误。不管是笔误也好,基于其他考虑也好,我们来思考一下这个语句会造成怎样的后果。

lua里table实际上就是类似于数组的东西,我们如果访问http://target/?a=1&a=2&a=3的话,这里的val就是{1,2,3}。

所以,type(val)=='table'是成立的,而val是不可能等于false的,没有进入中间的if语句。所以这时,data实际上是没赋值的(值是nil或上一次data的值,因为lua里默认变量都是全局的)!

而之后进行拦截的if语句:if data and type(data) ~= "boolean" and rule ~="" and ngxmatch(unescape(data),"imjo") then

因为data == nil(或上一次的值,也就是上一次提交的val,我们可以控制的,让他等于一个不被拦截的值),所以这个if语句也是不成立的,所以最后实际上args函数啥也没干就结束了!



所以这里,我们通过HPP的方式(/?a=1&a=2&a=3),绕过了ngx_lua_waf对GET变量的防御。

有一点要注意的,上一次的val一定不能被拦截,否则因为这次data沿用的上一次的val,所以也会拦截,即使使用hpp也绕不过。这里提一下,免得测试的时候出错。



另外,我提另一个正则的问题。

在源码中,我们可以看到所有正则都有用m修饰:ngxmatch(unescape(data),"imjo")

m表示multiline,匹配多行,也就是.是不匹配换行符的。所以导致我们可以直接用union%0aselect绕过默认的防御正则,不过这都是小问题了,将m改成s即可。

漏洞证明:

首先搭建好一切环境,并写一个waf.php如下:

<?php
header("X-XSS-Protection: 0");
echo $_GET['a'];
?>



很简单一个存在XSS漏洞的脚本,XSS测试比较方便,不用另外搭数据库什么的。

先测试一下http://vps-rpi/waf.php?a=1&a=2&a=%3Cimg%20src=1%20onerror=alert(1)%3E,利用hpp来绕过WAF,造成弹窗:

QQ20150329-2@2x.png





再测试一下,不利用hpp直接访问http://vps-rpi/waf.php?a=%3Cimg%20src=1%20onerror=alert(1)%3E:

QQ20150329-1@2x.png



可见被防御了。



访问了这两次以后,此时data==<img%20src=1%20onerror=alert(1)>。这个时候如果再用第一个payload,就会失败了。所以,只需要将data变成一个不会被拦截的值即可,那么就访问一下http://vps-rpi/waf.php?a=111,data就变成111了。之后,我们只要不访问/waf.php?a=<img%20src=1%20onerror=alert(1)>,那data的值就永远等于111。



另外,对于m和s的问题,这里也给个截图:

QQ20150329-4@2x.png



QQ20150329-5@2x.png





这个漏洞,虽然影响不大,但思路还是挺有意思。

修复方案:

那块逻辑有问题的代码需要改一下。

可以改成这样:

function args() for _,rule in pairs(argsrules) do local args = ngx.req.get_uri_args() for key,val in pairs(args) do if type(val)=='table' then data=table.concat(val," ") else data=val end if data and type(data) ~= "boolean" and rule ~="" and ngxmatch(unescape(data),"ijos") then log('GET',rule) say_html() return true end end end return false end

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读