本文内容:

某站发现的一个 CRLF 漏洞以及一些利用思考

前言

最近真的是太忙了,实习要学习JS安全和浏览器漏洞挖掘之类的

但我二进制不是很好,所以还在狂补二进制知识,对于一个Web狗的感觉太酸爽了

而且学校安排的实习无聊且浪费时间,写着Java Spring和前端开发,但这明明是我不需要的-_-

今晚抽空测了一下熟悉的某站,发现了一个很少有人听说和利用的漏洞,就想放松一下,记录一下这个漏洞和实例,复习我久违的Webo(╥﹏╥)o

CRLF漏洞简介

HTTPHeader当中,状态行和首部中的每行以CRLF结束,首部与主体之间由一空行分隔

或者理解为首部最后一个字段有两个CRLF,首部和主体由两个CRLF分隔。

CRLF注入漏洞,是因为Web应用没有对用户输入做严格验证,导致攻击者可以输入一些恶意字符。攻击者一旦向请求行或首部中的字段注入恶意的CRLF,就能注入一些首部字段或报文主体,并在响应中输出,所以又称为HTTP响应拆分漏洞(HTTP Response Splitting)。

CRLF 指的是回车符(CR,ASCII 13,\r,%0d) 和换行符(LF,ASCII 10,\n,%0a)。

在HTTP规范中,行应该使用CRLF来结束。首部与主体由两个CRLF分隔,浏览器根据这两个CRLF来获取HTTP内容并显示

POST / HTTP/1.1
Host: www.baidu.com
Connection: close
Content-Length: 7
Cache-Control: max-age=0
Origin: https://www.baidu.com
Upgrade-Insecure-Requests: 1
DNT: 1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://www.baidu.com/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

a2u13=1

再看看他的十六进制表示

image-20200613002033698

可知他的 POST请求当中头部和消息体是通过两个\r\n进行分隔的

image-20200613002017528

头部之间是通过一个\r\n进行分隔的

知道 HTTP数据包是这么构成的就可以了,接下来讲一下实际的挖掘方法

例子

一般而言,CRLF漏洞多见于可控HTTP头部的属性,这里举个最常见的例子,302重定向

如果说,一个URL想要对重定向到一个新的地址,他可能会把参数放到GET请求中的query部位,或者放到POST数据当中,很明显这两个点是很容易控制的,比如:

http://xxx.xxx.com?goto=www.baidu.com

其中如果进行跳转的话,则会在302跳转包中新增一个字段

Location: www.baidu.com

如果此时程序员没有对跳转的地址进行过滤的话,就很有可能让我们实现插入CRLF从而实现头部注入,从而实现下面几个点的漏洞,这里拿一个真实的站点做演示

会话固定漏洞

如果我们在原跳转地址后面写上%0d%0a进行换行,插入自定义的字段Set-cookie:JSPSESSID%3DA2u13,然后经过解码之后,会在302跳转中看到我们的插入的Set-cookie已经生效了

image-20200613003110072

但下面还有个原本的Set-cookie怎么办呢,办法是把他通过两个CRLF挤到body当中,但是又因为是GET请求,所以被挤下去的头部也会被服务器忽略,从而实现了会话固定

image-20200613003616263

对于POST请求而言,原理一致,只要能让服务器解析原本的POST即可

XSS漏洞

由于我这个站是只能接受GET请求,对于POST请求会忽略消息体,所以我们用一个例子来展示一下

同样是http://xxx.xxx.com?goto=www.baidu.com

如果此时我们使用两个CRLF来划开消息头部和消息体

http://xxx.xxx.com?goto=www.baidu.com%0d%0aX-XSS-Protection%3A%200%0d%0a%0d%0a%3Cimg%20src%3D%23%20onerror%3Dalert(1)%3B%20%2F%3E

此时就会产生这种情况

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: www.baidu.com
X-XSS-Protection: 0

<img src=# onerror=alert(1); />

是不是我们插入的XSS语句进入了消息体当中?

而且插入了X-XSS-Protection: 0,对于一部分浏览器会关闭XSS-filter,就可以利用

但是这种利用还是有些鸡肋的,毕竟302跳转是没有POST消息体的

所以说,只要是能找到一个POST请求,并且头部可控无CRLF过滤时,就可以用来打XSS

绕过CSP

如果说你很幸运,发现可控的头部正好位于Content-Security-Policy的上方

那么就可以利用上面的采用两个CRLFCSP挤到消息体当中,从而使CSP失效

如果CSP下面有部分需要数据不能被挤到消息体当中时,可以提前把数据写到可控头部字段值中

不过这也是一个假想,毕竟这种站太少了,如果能遇到的话,可以利用CRLF漏洞完美绕过CSP的防护

修复措施

很简单,把传入头部字段的所有数据都过滤\r和\n即可