常见解码
某些商业waf解码类型,通常支持解码类型如下:
URL解码
JSON解析
base64解码
十六进制hex解码
斜杠转义
xml解析
php序列化对象解析
UTF7解码
本文解码格式
base64_decode
css_decode
hex_decode
cmd_line
compress_whitespace
html_decode
js_decode
lowercase
normalise_path
normalise_path_win
remove_comments
remove_comments_char
remove_nulls
remove_whitespace
replace_comments
replace_nulls
sql_hex_decode
uri_decode
trim
trim_left
trim_right
绕过waf的一些帖子
大小写绕过
简单编码绕过
注释绕过
分隔重写绕过
例如检测union,%55为U的16进制编码替代U,union写成%55nION,结合大小写可以绕过一些WAF。
解码代码
解码部分,nginx lua可以实现一部分。
另一部分需要调用c动态库实现,我们可以编写多种解码so提供给nginx lua调用。
local _M = {}
local base = require "owasp.base"
local hdec = require "resty.htmlentities"
local ffi = require "ffi"
local logger = require "owasp.log"
local util = require "owasp.util"
local Util = require "util"
require "resty.core.regex"
require "resty.core.hash"
require "resty.core.uri"
local ffi_cpy = ffi.copy
local ffi_new = ffi.new
local ffi_str = ffi.string
local c_buf_type = ffi.typeof("char[?]")
ffi.cdef[[
int js_decode(unsigned char *input, long int input_len);
int css_decode(unsigned char *input, long int input_len);
]]
_M.version = base.version
hdec.new()
local loadlib = function()
local so_name = 'libdecode.so'
local cpath = package.cpath
for k, v in string_gmatch(cpath, "[^;]+") do
local so_path = string_match(k, "(.*/)")
if so_path then
so_path = so_path .. so_name
local f = io.open(so_path)
if f ~= nil then
io.close(f)
return ffi.load(so_path)
end
end
end
end
local decode_lib = loadlib()
local function decode_buf_helper(value, len)
local buf = ffi_new(c_buf_type, len)
ffi_cpy(buf, value)
return buf
end
_M.lookup = {
base64_decode = function(value)
if not value then return end
--判断是否是base64编码
--if ngx_re_match(value,"^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$") ~= nil then
if type(value) == "string" then
local t_val = ngx_decode_base64(value)
if t_val then
return t_val
else
return value
end
end
return value
end,
css_decode = function(value)
if not value then return end
if not value then return end
local len = #value
local buf = decode_buf_helper(value, len)
local n = decode_lib.css_decode(buf, len)
return (ffi_str(buf, n))
end,
cmd_line = function(value)
if not value then return end
local str = tostring(value)
str = ngx_re_gsub(str, [=[[\\'"^]]=], '', 'oij')
str = ngx_re_gsub(str, [=[\s+/]=], '/', 'oij')
str = ngx_re_gsub(str, [=[\s+[(]]=], '(', 'oij')
str = ngx_re_gsub(str, [=[[,;]]=], ' ', 'oij')
str = ngx_re_gsub(str, [=[\s+]=], ' ', 'oij')
return string_lower(str)
end,
compress_whitespace = function(value)
if not value then return end
return ngx_re_gsub(value, [=[\s+]=], ' ', 'oij')
end,
hex_decode = function(value)
if not value then return end
return util.hex_decode(value)
end,
html_decode = function(value)
if not value then return end
local str = hdec.decode(value)
return str
end,
js_decode = function(value)
if not value then return end
local len = #value
local buf = decode_buf_helper(value, len)
local n = decode_lib.js_decode(buf, len)
return (ffi_str(buf, n))
end,
lowercase = function(value)
if not value then return end
return string_lower(tostring(value))
end,
normalise_path = function(value)
if not value then return end
while (ngx.re.match(value, [=[[^/][^/]*/\.\./|/\./|/{2,}]=], 'oij')) do
value = ngx_re_gsub(value, [=[[^/][^/]*/\.\./|/\./|/{2,}]=], '/', 'oij')
end
return value
end,
normalise_path_win = function(value)
if not value then return end
value = string_gsub(value, [[\]], [[/]])
return _M.lookup['normalise_path'](value)
end,
remove_comments = function(value)
if not value then return end
return ngx_re_gsub(value, [=[\/\*(\*(?!\/)|[^\*])*\*\/]=], '', 'oij')
end,
remove_comments_char = function(value)
if not value then return end
return ngx_re_gsub(value, [=[\/\*|\*\/|--|#]=], '', 'oij')
end,
remove_nulls = function(value)
if not value then return end
return ngx_re_gsub(value, [[\0]], '', 'oij')
end,
remove_whitespace = function(value)
if not value then return end
return ngx_re_gsub(value, [=[\s+]=], '', 'oij')
end,
replace_comments = function(value)
if not value then return end
return ngx_re_gsub(value, [=[\/\*(\*(?!\/)|[^\*])*\*\/]=], ' ', 'oij')
end,
replace_nulls = function(value)
if not value then return end
return ngx_re_gsub(value, [[\0]], ' ', 'oij')
end,
sql_hex_decode = function(value)
if not value then return end
if string_find(value, '0x', 1, true) then
value = string_sub(value, 3)
return util.hex_decode(value)
else
return value
end
end,
trim = function(value)
if not value then return end
return ngx_re_gsub(value, [=[^\s*|\s+$]=], '')
end,
trim_left = function(value)
if not value then return end
return ngx_re_sub(value, [=[^\s+]=], '')
end,
trim_right = function(value)
if not value then return end
return ngx_re_sub(value, [=[\s+$]=], '')
end,
uri_decode = function(value)
if not value then return end
return ngx_unescape_uri(value)
end,
}
return _M