从WAF开发角度看文件上传的攻与防

作者:媒体转发 时间:2018-04-19 21:59

字号

这几天在重写JXWAF的文件上传处理模块,初期只关注了功能实现,写完后碰巧看到【技术分享】文件上传和WAF的攻与防(https://www.secpulse.com/archives/66100.html)这篇文章,发现成了标准的绕过样本,赶紧把防绕过的代码补上。现在市面上大部分文章都是站在攻击方的角度来分析WAF文件上传功能的绕过,这篇文章站在防御方,也就是WAF开发者角度来分析WAF文件上传的攻与防。

二、代码分析

以下为核心的功能实现代码:

if content_type and ngx.re.find(content_type, [=[^multipart/form-data; boundary=]=],"oij") and tonumber(ngx.req.get_headers()["Content-Length"]) ~= 0 then
local form, err = upload:new()
local _file_name = {}
local _form_name = {}
local _file_type = {}
local t ={}
local _type_flag = "false"
if not form then
ngx.log(ngx.ERR, "failed to new upload: ", err)
ngx.exit(500)
end
ngx.req.init_body()
ngx.req.append_body("--" .. form.boundary)
local lasttype, chunk
local count = 0
while true do
count = count + 1
local typ, res, err = form:read()
if not typ then
ngx.say("failed to read: ", err)
return nil
end
if typ == "header" then
chunk = res[3]
ngx.req.append_body("\r\n" .. chunk)
if res[1] == "Content-Disposition" then
local _tmp_form_name = ngx.re.match(res[2],[=[(.+)\bname="([^"]+)"(.*)]=],"oij")
local _tmp_file_name = ngx.re.match(res[2],[=[(.+)filename="([^"]+)"(.*)]=],"oij")
if _tmp_form_name then
table.insert(_form_name,_tmp_form_name[2]..count)
end
if _tmp_file_name then
table.insert(_file_name,_tmp_file_name[2])
end

end
if res[1] == "Content-Type" then
table.insert(_file_type,res[2])
_type_flag = "true"
chunk = string.format([=[Content-Type: %s]=],res[2])
ngx.req.append_body("\r\n" .. chunk)
end
end
if typ == "body" then
chunk = res
if lasttype == "header" then
ngx.req.append_body("\r\n\r\n")
end
ngx.req.append_body(chunk)
if _type_flag == "true" then
_type_flag = "false"
t[_form_name[#_form_name]] = ""
else
if lasttype == "header" then
t[_form_name[#_form_name]] = res
else
t[_form_name[#_form_name]] = ""
end
end
end
if typ == "part_end" then
ngx.req.append_body("\r\n--" .. form.boundary)
end
if typ == "eof" then
ngx.req.append_body("--\r\n")
break
end
lasttype = typ
end

对于文件上传功能的检测,主要关注两点,一个是文件名的获取,另一个是文件类型的获取。

首先来谈谈第一种绕过情形

4.11 Header在boundary前添加任意字符

问题出现在对Content-Type的匹配上,上述代码对Content-Type使用的匹配正则为”^multipart/form-data; boundary=”",从功能实现上来说,正则这样写没啥问题,但是当出现类似上述的情况时,比如Content-Type: multipart/form-data; jxwafboundary=—————————9585485410332,即可绕过正则,因为正则要求; boundary中间只能存在一个空格,不符合就无法匹配,当不匹配时一般就被当成普通POST请求处理,无法获取上传文件相关参数的情况下,自然也就无法防护。

针对这种绕过方法,防绕过也比较简单,初期的方法是将正则修改为”^multipart/form-data;.*?boundary=”,后来觉得搞不好会有乱七八糟的后端语言支持其他奇葩方式,就干脆将正则改为”^multipart/form-data”。

4.1去掉引号

4.2 双引号变成单引号

4.3 大小写

4.4 空格

4.6 交换name和filename的顺序

4.8 多个filename

4.9 多个分号

4.13 name和filename添加任意字符串

以上都可以归类为正则绕过的问题,所以统一来讲。

首先来看用于文件名获取的正则”(.+)filename=”([^"]+)”(.*)”

正常匹配如下图

TIM图片20180413152537.png

可以成功匹配到,现在试试第一种绕过方法,去掉引号

TIM2.png

可以看到,正则匹配到filename=“就结束了,匹配失败,经测试可以成功上传文件

责任编辑:CQITer新闻报料:400-888-8888   本站原创,未经授权不得转载
继续阅读
热新闻
推荐
关于我们联系我们免责声明隐私政策 友情链接