目錄php
HTTP報文包體的解析html
Transfer-Encodingnginx
Charsetgit
溢量數據程序員
HTTP協議兼容性github
HTTP請求行種的空格web
高層數據tomcat
本文主要從繞過WAF過程當中須要注意的角色和點出發,嘗試理解它們的運做,構建一個簡單的知識框架。
首先,WAF分爲非嵌入型WAF和嵌入型WAF,非嵌入型WAF指的是硬WAF、雲WAF、虛擬機WAF之類的;而嵌入型WAF指的是Web容器模塊類型的WAF、代碼層WAF。非嵌入型WAF對Web流量的解析徹底是靠自身的,而嵌入型WAF拿到的Web數據是已經被解析加工好的。因此非嵌入型的受攻擊機面還涉及到其餘層面,而嵌入型WAF從Web容器模塊類型WAF、代碼層WAF往下走,其對抗畸形報文、掃操做繞過的能力愈來愈強。固然,在部署維護成本方面,也是越高的。
有些WAF設置的是針對域名的防禦,有些時候,咱們嘗試將域名改爲ip地址能夠繞過WAF的防禦。
咱們先來探討一個問題。HTTP請求的服務器在接收到該請求時,會關心哪些頭部字段,以及如何根據這些頭部字段作出對Request-body 進行相應的解析處理。說實話,要搞清這些東西,最好仍是查看web容器的源碼,但筆者如今還沒作到這一步,在這裏僅能根據自身的認知說起一些頭部字段。這些頭部字段的關係,筆者認爲能夠總結爲以下:
Transfer-Encoding(Content-Encoding(Content-Type(charset(data))))
關於Transfer-Encoding,傳送門——>數據的分段編碼(transfer-encoding)
Apache+php對chunked類型的HTTP請求的處理太怪了。RFC2616中說明了,客戶端或服務器,收到的HTTP報文中,若是同時存在chunked與Content-Length,則必定要忽略掉content-length,而在Apache中卻不能缺乏。理由是Apache自己是不支持解析chunked的(對於Apache來講,因爲沒有解析HTTP請求chunked的代碼邏輯,因此必定要從content-length中查看該報文的長度,而chunked多是被PHP解析了的,因此這兩個頭部必定要同時存在)。這一結論也很好地解釋了一些不解的現象,如利用chuncked編碼能夠繞過安全狗Apache。 經過shodan搜索相關服務器,簡單測試一下,關於常見中間件、語言與chuncked的關係有以下參考:
ASPX | PHP | Java | |
Apache | X | Y | |
Nginx | Y | Y | |
IIS | Y | Y | |
Tomcat | X |
那關於chunked,能夠有什麼利用思路呢? 思路一,構造一個chunked請求體,嘗試繞過WAF。其中能夠涉及到利用chunked自己的一些規範、特性。 好比,假如WAF會解析chunked,但加入一些chunked的擴展,WAF就解析不了。 反過來,腦洞一下,假如WAF意識到了解析chunked時應該忽略這些擴展,那麼在Tomcat下咱們是否是能夠利用它一下。
相關文章:利用分塊傳輸吊打全部WAF
Content-Type
Web容器應該不怎麼關心Content-Type這個字段,後臺語言會識別該字段並進行對應的數據解析。而咱們利用該字段的話,主要從如下思路出發:後臺語言會識別哪些類型的Content-Type,這些Content-Type對咱們繞WAF有沒有用。 PHP默認會處理application/x-www-form-urlencoded、multipart/form-data兩種。而JAVA後臺對於multipart/form-data類型Content-Type的識別處理,須要藉助三方庫或是框架,默認狀況下是沒法處理的,但如今通常都用框架,而框架可能默認狀況下就會識別並處理這類型的請求。 後臺接收到application/x-www-form-urlencoded請求的數據時,會本身解碼一次,若是開發人員本身又解碼一次或屢次,就造成了雙重編碼、多重編碼。 對於multipart/form-data,非嵌入型的WAF與模塊類型的WAF,都只能本身識別並解析區分字段內容,因此在這一塊你能夠發揮本身想象,進行各類騷操做來進行繞過,可是,你應該要確認你當前所要繞過的WAF是否是真的作了這塊的內容識別。筆者的意思是說,若是它遇到這種類型Request,只是對Body內容進行所有的規則匹配,而不會解析出其中的表單內容,那你可能就不必進行那些騷操做了。實際上,有的非嵌入型WAF就是這麼「懶」。multipart/form-data的相關騷操做能夠參考Protocol-Level Evasion of Web Application Firewalls
charset是被添加在Content-Type字段後面的,用來指明消息內容所用的字符集,它也僅被後臺語言所關心。
• application/x-www-form-urlencoded;charset=ibm037
• multipart/form-data; charset=ibm037,boundary=blah
• multipart/form-data; boundary=blah ; charset=ibm037
JAVA的Servlet默認是接受大多數的charset的,不過正常點的程序員都會設置強制編碼。 有以下示例: 後臺代碼
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String userName = req.getParameter("user"); resp.getOutputStream().println("username :"+userName); }
請求(Burpsui設置User Options-Character sets-Use a specific ..)
POST /test HTTP/1.1 Host: 127.0.0.1:8081 Content-Type: application/x-www-form-urlencoded; charset=ibm037 Content-Length: 25 %A4%A2%85%99=%99%96%96%A3
輸出
HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Content-Length: 16 username :root
至少能夠支持IBM037, IBM500, cp875, and IBM1026字符集的中間件+語言的狀況,能夠參考下面表格:
Target | QueryString | POST Body | & and = | URL-encoding |
Nginx, uWSGI – Django – Python3 | ✔ | ✔ | ✔ | ❌ |
Nginx, uWSGI – Django – Python2 | ✔ | ✔ | ❌ | ✔ (sometimes required) |
Apache Tomcat – JSP | ❌ | ✔ | ❌ | ✔ (sometimes required) |
IIS – ASPX (v4.x) | ✔ | ✔ | ❌ | ✔ (optional) |
IIS – ASP classic | ❌ | ❌ | ||
Apache/IIS – PHP | ❌ | ❌ |
筆者當初有時在瞎想,其中想到,會不會存在URI數量過多,產生繞過呢?沒想到就存在這樣的一個CVE,CVE-2018-9230-OpenResty URI參數溢出漏洞。
不要緊,思想還在嘛,還存在不少的變形,如經過multipart/form-data的方式來發送數據量比較大的報文,但又屬於正常的HTTP請求,按照道理來講,對較上層的WAF(非嵌入型、模塊類型)應該會有必定殺傷力的。
傳送門——> 繞過網站WAF(圖片繞過)
在RFC2616文檔中,有說到,HTTP頭部字段的構造。
SP = <US-ASCII SP, space (32)> HT = <US-ASCII HT, horizontal-tab (9)> LWS = [CRLF] 1*( SP | HT ) message-header = field-name ":" [ field-value ] field-name = token field-value = *( field-content | LWS ) field-content = <the OCTETs making up the field-value and consisting of either *TEXT or combinations of token, separators, and quoted-string>
簡單點來講就是
Test-Header: Test
等效於(空格替換成\x09)
Test-Header: Test
但筆者發現,在請求行中,你也能夠這樣作(即使RFC2616 5.1節中指明瞭請求行中只能用空格)。因而,將一個HTTP/1.1的請求變換成以下:
OPTIONS * HTTP/1.1
Host: dest.com
看着可能不明顯,但其中的SP都被筆者替換成了HT,並且,SP、HT能夠是1到多個,頭部字段中SP 、HT能夠是零個。常見的web容器都是接受這種HTTP請求的。
關於這條,相關細節能夠到WAF Bypass Techniques ,筆者就不細講了。發明做者說它用這條技巧來繞過WAF(非嵌入型)對服務器上的一些目錄的訪問限制。 根據本文前面所說,能夠知道,對於嵌入型一類的WAF,是根本不可能利用pipelining來進行繞過的——嵌入型WAF得到的數據的來源是Web容器,web容器識別出這是兩個包,對於WAF也是兩個包。 不過這上面的兩點感受對WAF都沒啥用,snort都能識別,那基本上全部WAF廠商都能識別吧。不過知道多點不虧,上面第一點在筆者某次測試中仍是體現了一點價值。
如今愈來愈多的Web容器都開始支持比較高級的協議了,正常來講,這塊不可能不出現新的安全問題的,筆者以前簡單查看了HTTP/2.0 與Websocket的主體內容,未發現有什麼利用點,後面也未花時間去研究,寫在這裏也算給本身一個備忘錄。
在一個HTTP請求中,諸如json、base64這樣的數據,是由後臺代碼調用相應的解析庫來進行解析的,即使是同結構,不一樣語言不一樣庫也可能存在一些差別。
PHP解析Base64沿襲了其一向「弱」風格,即使你的字符串含有PHP非法字符串,它也能夠成功解析並處理。
測試代碼:
echo base64_decode($_POST[‘test’]);
POST提交
test=M#TIzNA==
頁面返回
1234
在HTTP請求體中傳遞JSON數據,通常狀況下若是網站用的框架,則Content-Type須要指定application/json類型;若是用了三方庫,如fastjson,content-type隨意便可。 能夠將嘗試將key或vaule替換成\uxxxx的unicode字符。
POST /json.do HTTP/1.1 Host: 127.0.0.1:8081 Content-Type: application/json Content-Length: 68 {"\u006e\u0061\u006d\u0065":"'\u0072\u006f\u006f\u0074","age":"18"} HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Content-Type: text/plain;charset=ISO-8859-1 Content-Length: 44 User{name=''root', age=18, contactInfo=null}
這裏的unicode關聯到JSON,只是一個實際的場景,但能夠本身發揮。
soap之類的協議應該也屬於XML類,能夠利用這類標記語言的實體編碼特性。另外發送請求前考慮一下Content-Type類型。
POST /xml.do HTTP/1.1 Host: 127.0.0.1:8081 Content-Type: application/xml Content-Length: 93 <?xml version="1.0" ?> <admin> <name>"'root</name> </admin> HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Content-Type: text/plain;charset=ISO-8859-1 Content-Length: 31 Admin{name='"'root', age=null}
還有一個字符表示方式,八進制,如#十六進制的值爲23,八進制表示爲\43,也是一個可能的點,如在OGNL中就可使用。
sqlmap的tamper腳本中有個腳本,將’替換爲%ef%bc%87,聽說是UTF-8全角字符,可是這種說明沒有根本地解釋這個問題,筆者也不知道什麼環境下產生這種利用條件。直到某一天,看到一篇文章,它們之間彷佛存在某在聯繫——Unicode同形字引發的安全問題,現階段筆者也只能這樣認知這個tamper腳本。 有個趣的網站,它已經整理好了,https://www.irongeek.com/homoglyph-attack-generator.php
Char | 同形 |
ᅟ ᅠ ㅤ | |
! | ! ǃ ! |
「 | 」 ״ ″ " |
$ | $ $ |
% | % % |
& | & & |
‘ | ‘ ' |
( | ( ﹝ ( |
) | ) ﹞ ) |
* | * ⁎ * |
+ | + + |
, | , ‚ , |
– | – ‐ - |
. | . ٠ ۔ ܁ ܂ ․ ‧ 。 . 。 |
/ | / ̸ ⁄ ∕ ╱ ⫻ ⫽ / ノ |
0 | 0 O o Ο ο О о Օ O o |
1 | 1 I ا 1 |
2 | 2 2 |
3 | 3 3 |
4 | 4 4 |
5 | 5 5 |
6 | 6 6 |
7 | 7 7 |
8 | 8 Ց 8 |
9 | 9 9 |
IIS %,在參數中,若是%後面不是符合URL編碼十六進制值,就會忽略該%符合,如id=%%20,等價於id=%20。 IIS asp 中的GET請求方式提交Body表單,後臺可接收。 IIS asp的參數污染中,經過,逗號鏈接污染參數。 Tomcat 路徑跳轉中容許;符號,/..;/..;/。 PHP $_REQUEST能夠接收cookie中的參數。 這塊想不到更多的了…
思考一下,WAF拿到一個數據以後,在對其進行內容匹配時,是否是會將其放入一個固定大小的內存空間中,這個空間的大小是有限的。假設HTTP Request的body部分大小爲2333字節,該內存大小爲2000字節,那麼其核心引擎在作內容匹配時,是否是先處理2000字節,在處理剩下的333字節。至於如何利用,能夠發揮本身的想象。
一個是利用URL中的白名單,如圖片、JS等靜態資源文件。 還能夠嘗試利用下面這些頭部字段
X-Forwarded-For: 127.0.0.1
X-Client-IP: 127.0.0.1
Client-IP: 127.0.0.1
另外能夠嘗試修改Host頭部字段。
前面所講的都是輸入角度,這裏咱們談談輸出角度。咱們在Request中發送Pyaload,會但願從Response的回顯或基於時間這些信息通道來獲取Payload執行成功後的相關信息。若是存在某種WAF,檢測到Response中的回顯數據存在敏感信息,Resonse響應包可能就被阻斷掉了。(固然,除了基本的回顯數據通道,還有基於時間的數據通道)
遇到這種狀況,應對的方法之一就是使用OOB思想來繞過。如XXE OOB、SQL注入OOB、命令注入OOB,等等。
假如頁面可能有敏感數據返回,而當前攻擊場景又利用不了OOB,你能夠嘗試使用Range方法來繞過防火牆。 普通請求與頁面結果:
POST /test/test.php HTTP/1.1 Host: 192.168.17.138 Content-Type: application/x-www-form-urlencoded Content-Length: 9 Range: bytes=10-30 user=root HTTP/1.1 200 OK Server: Apache/2.4.23 (Win32) OpenSSL/1.0.2j PHP/5.2.17 Content-Length: 42 Content-Type: text/html SELECT password from user where user = ''
添加了range,請求獲取返回頁面0到10的數據:
POST /test/test.php HTTP/1.1 Host: 192.168.17.138 Content-Type: application/x-www-form-urlencoded Content-Length: 9 Range: bytes=0-10 user=root HTTP/1.1 206 Partial Content Server: Apache/2.4.23 (Win32) OpenSSL/1.0.2j PHP/5.2.17 Content-Range: bytes 0-10/394 Content-Length: 11 Content-Type: text/html SELECT pass
添加了range,請求獲取返回頁面10到30的數據:
POST /test/test.php HTTP/1.1 Host: 192.168.17.138 Content-Type: application/x-www-form-urlencoded Content-Length: 9 Range: bytes=10-30 user=root HTTP/1.1 206 Partial Content Server: Apache/2.4.23 (Win32) OpenSSL/1.0.2j PHP/5.2.17 Content-Range: bytes 10-30/394 Content-Length: 21 Content-Type: text/html sword from user where
Range方式應該是全部Web容器默認支持的,這個東西仍是有點意思,有點做用。
看CVE時發現的,3whs bypass ids
Attack scenario TCP flow scheme: Client -> [SYN] [Seq=0 Ack= 0] -> Evil Server Client <- [SYN, ACK] [Seq=0 Ack= 1] <- Evil Server Client <- [PSH, ACK] [Seq=1 Ack= 1] <- Evil Server # Injection before the 3whs is completed Client <- [FIN, ACK] [Seq=83 Ack= 1] <- Evil Server Client -> [ACK] [Seq=1 Ack= 84] -> Evil Server Client -> [PSH, ACK] [Seq=1 Ack= 84] -> Evil Server
在三次握手未完成以前,服務端返回了數據,能夠形成HTTP流量檢測的繞過,該種攻擊場景多是被用於掛馬、釣魚之類的。在連接中做者給出了對應的PCAP包,能夠下載來看看,算是漲見識。 在傳輸層這裏,還有一些簡單而具有實際意義的操做,好比將一個TCP報文分片成不少不少份,一份幾個字節,十幾個字節,對端服務器能正常接收,而對非嵌入型的WAF就是一個考驗;還有,咱們知道,TCP是可靠的協議,那麼咱們再將這些報文進行一個合適的亂序,那麼是否也可行。
對於非嵌入型WAF,在解析SSL數據時,須要該SSL通訊端服務器的密鑰(非對稱)。客戶端在與Web服務器進行HTTPS通訊時,協商SSL的加密方式能夠有不少種,若是其中有一種加密方式剛好是WAF沒法識別的,那麼WAF就只能睜眼瞎了。 Bypassing Web-Application Firewalls by abusing SSL/TLS
筆者以前瞭解到,中小公司的防火牆的流量處理能力是很弱的,因此DOS確實可行,算是最後的方案。
其餘說明,RFC7230對文章中所說的RFC2616的描述未發生修改。 本文參考資料彙總以下
原文連接:對過WAF的一些認知
RCF2616:https://tools.ietf.org/html/rfc2616
Bypassing Web-Application Firewalls by abusing SSL/TLS:https://0x09al.github.io/waf/bypass/ssl/2018/07/02/web-application-firewall-bypass.html
WAF Bypass Techniques https://2018.appsec.eu/presos/HackerWAF-Bypass-TechniquesSoroush-Dalili_AppSecEU2018.pptx
Application Security Weekly: Reverse Proxies Using Weblogic, Tomcat, and Nginx:https://www.acunetix.com/blog/web-security-zone/asw-reverse-proxies-using-weblogic-tomcat-and-nginx/
Protocol-Level Evasion of Web Application Firewalls https://media.blackhat.com/bh-us-12/Briefings/Ristic/BHUS12RisticProtocolLevelSlides.pdf
Chunked HTTP transfer encoding:https://swende.se/blog/HTTPChunked.html
Impedance Mismatch and Base64:https://www.trustwave.com/en-us/resources/blogs/spiderlabs-blog/impedance-mismatch-and-base64/
HTTP 協議中的 Transfer-Encoding:https://imququ.com/post/transfer-encoding-header-in-http.html
淺談json參數解析對waf繞過的影響:https://xz.aliyun.com/t/306
3whs bypass ids:https://www.exploit-db.com/exploits/44247/
Web Application Firewall (WAF) Evasion Techniques:https://medium.com/secjuice/waf-evasion-techniques-718026d693d8
BypassWAF新思路(白名單):https://www.chainnews.com/articles/774551652625.htm
利用分塊傳輸吊打全部WAF:https://www.anquanke.com/post/id/169738
HTTP Request Smuggling:https://www.cgisecurity.com/lib/HTTP-Request-Smuggling.pdf