WAF如何应对payload编码绕过

web服务器在对外提供各种应用服务时,经常会遇到请求的payload经过混淆或者编码想要绕过web安全防火墙。

 

如果在http请求中添加编码很可能会绕过waf规则,甚至绕过语义分析。导致数据泄漏风险,本应该被拦截的请求,还是得到了请求对应的响应数据。

可以通过下面连接了解一下,想要绕过web安全防火墙经过处理的payload长什么样。这里是我参考owasp(感谢他们对web安全做出的贡献)整理的xss攻击方式,包含各种经过处理的payload绕过方法。

绕过WAF的XSS语句_晓镁的博客-CSDN博客

通常云waf厂商都会自研自己的解码引擎。针对不同使用场景(互联网/金融/政企)提供不同的解码组合方案。

我们以华为云waf为例,看看他们的编解码说明。

下面整理一下常见的基于nginx+lua实现针对http payload编解码操作。

以下代码提供参考:

--base64
local function _base64_decode(value)
	local val = ngx.decode_base64(tostring(value))
	if (val) then
		return val
	else 
		return value
	end
end

local function _base64_encode(value)
	local val = ngx.encode_base64(value)
	return val
end

--命令行
local function _cmd_line(value)
	local val = tostring(value)
	val = ngx.re.gsub(val,[=[[\\'"^]]=], '',"oij")
	val = ngx.re.gsub(val,[=[\s+/]=],'/',"oij")
	val = ngx.re.gsub(val, [=[\s+[(]]=],'(', "oij")
	val = ngx.re.gsub(val, [=[[,;]]=],' ', "oij")
	val = ngx.re.gsub(val, [=[\s+]=],' ', "oij")
	return string.lower(val)
end

--压缩空格
local function _compress_whitespace(value)
	return ngx.re.gsub(value, [=[\s+]=], ' ', "oij")
end 

--十六进制
local function _hex_decode(value)
	if type(value) ~= "string" then return value end
            
            local str

            if (pcall(function()
                str = value:gsub('..', function (cc)
                    return string.char(tonumber(cc, 16))
                end)
            end)) then
                return str
            else
                return value
            end
end

local function _hex_encode(value)
    if type(value) ~= "string" then return value end
            
    return (value:gsub('.', function (c)return string.format('%02x', string.byte(c))end))
end

--html处理
local function _html_decode(value)
   if type(value) ~= "string" then return value end
            
    local str = ngx.re.gsub(value, [=[&lt;]=], '<', "oij")
    str = ngx.re.gsub(str, [=[&gt;]=], '>', "oij")
    str = ngx.re.gsub(str, [=[&quot;]=], '"', "oij")
    str = ngx.re.gsub(str, [=[&apos;]=], "'", "oij")
    str = ngx.re.gsub(str, [=[&#(\d+);]=], function(n) return string.char(n[1]) end, "oij")
    str = ngx.re.gsub(str, [=[&#x(\d+);]=], function(n) return string.char(tonumber(n[1],16)) end, "oij")
    str = ngx.re.gsub(str, [=[&amp;]=], '&', "oij")
    return str
end

--字符串长度
local function _length(value)
    return tostring(#tostring(value))
end

--转换小写
local function _lowercase(value)
   return string.lower(tostring(value))
end

--MD5处理
local function _md5(value)
    if not value then return nil end
            
    return ngx.md5_bin(value)
end

--规范路径格式
local function _normalise_path(value)
	while (ngx.re.match(value, [=[[^/][^/]*/\.\./|/\./|/{2,}]=], "oij")) do
        value = ngx.re.gsub(value, [=[[^/][^/]*/\.\./|/\./|/{2,}]=], '/', "oij")
    end
    return value
end

--删除注释
local function _remove_comments(value)
    if type(value) ~= "string" then return value end            
        return ngx.re.gsub(value, [=[\/\*(\*(?!\/)|[^\*])*\*\/]=], '', "oij")
end

--删除注释字符
local function _remove_comments_char(value)
    if type(value) ~= "string" then return value end       
    return ngx.re.gsub(value, [=[\/\*|\*\/|--|#]=], '', "oij")
end

--删除空格
local function _remove_whitespace(value)
    if type(value) ~= "string" then return value end

    return ngx.re.gsub(value, [=[\s+]=], '', "oij")
end

--替换注释
local function _replace_comments(value)
    if type(value) ~= "string" then return value end
    --[=[ / *( *(?!/) | [^*])* *]=]
    return ngx.re.gsub(value, [=[\/\*(\*(?!\/)|[^\*])*\*\/]=], ' ', "oij")
end

--字符串SHA-1摘要
local function _sha1(value)
    if not value then return nil end
            
    return ngx.sha1_bin(value)
end

--sql_hex解码
local function _sql_hex_decode(value)
    if type(value) ~= "string" then return value end
            
    if (string.find(value, '0x', 1, true)) then
        value = string.sub(value, 3)
        local str
        if (pcall(function()
            str = value:gsub('..', function (cc)
                return string.char(tonumber(cc, 16))
            end)
        end)) then
            return str
        else
            return value
        end
    else
        return value
    end
end

--去除不必要的字符
local function _trim(value)
    if type(value) ~= "string" then return value end
            
    return ngx.re.gsub(value, [=[^\s*|\s+$]=], '')
end

local function _trim_left(value)
    if type(value) ~= "string" then return value end
        
    return ngx.re.sub(value, [=[^\s+]=], '')
end

local function _trim_right(value)
    if type(value) ~= "string" then return value end
            
    return ngx.re.sub(value, [=[\s+$]=], '')
end

--uri转码
local function _uri_decode(value)
	local value = tostring(value)
	return ngx.unescape_uri(value)
end 

local function _uri_encode(value)
	local value = tostring(value)
	return ngx.escape_uri(value)
end

更多的编解码操作,我们可以通过lua ffi调用已经编译好的so库来实现。

c语言有着非常多的编解码开源程序,我们把它们编译成so库通过lua ffi可以任意使用so里面的编解码函数。后面会重点介绍。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值