浅谈CRLF注入
简介
CRLF(Carriage Return Line Feed)又称HRS(HTTP Response Splitting)是一种网络安全漏洞,利用的是在HTTP响应中未能正确处理用户输入的漏洞。CRLF注入攻击通过在用户输入中插入换行符(回车符和换行符),可能导致HTTP响应头被篡改,进而造成响应拆分、跨站脚本(XSS)或其他攻击。
漏洞原理
CRLF(Carriage Return Line Feed)注入漏洞利用的是HTTP响应中未能正确处理用户输入的缺陷。攻击者可以通过插入回车符(CR,\r
)和换行符(LF,\n
)来操控HTTP响应,导致HTTP响应头被篡改或分割,从而实现各种恶意攻击。
漏洞危害
1. HTTP响应拆分(HTTP Response Splitting)
CRLF注入最常见的危害是HTTP响应拆分。攻击者利用该漏洞可以将一个HTTP响应拆分为多个响应,从而引发多种安全问题。
2. 跨站脚本(XSS)攻击
通过HTTP响应拆分,攻击者可以注入恶意的JavaScript代码。当用户浏览器解析并执行这些代码时,可能导致跨站脚本(XSS)攻击,窃取用户的敏感信息(如Cookies、会话令牌)或进行其他恶意操作。
示例:
1 | 200 OK |
3. 会话固定
CRLF注入可以使攻击者插入会话,使其固定为攻击者设置的凭证
示例:
1 | 200 OK |
4. 缓存中毒
攻击者可以通过CRLF注入将恶意内容缓存到服务器上。如果Web应用程序使用了缓存机制(如CDN或代理服务器),恶意内容可能被缓存,影响后续请求的用户。
示例: 攻击者注入一个恶意响应,使得缓存服务器缓存了带有恶意脚本的响应内容。随后,每次用户请求相同资源时,都会从缓存中获取到恶意内容。
5. HTTP请求/响应劫持
通过CRLF注入,攻击者可以注入多个响应,导致浏览器或中间代理服务器解析错误的响应内容,从而进行HTTP请求/响应劫持,劫持用户会话或劫持Web页面内容。
6. 信息泄露
攻击者可以通过注入额外的响应内容来窃取服务器的内部信息,如敏感的响应头或错误信息,进一步加深攻击。
漏洞出现场景
- 用户可控的自定义头部字段(但没什么用)
- CORS漏洞中的Access-Allow-Origin直接接收Origin值导致的该响应头可控(但没什么用)
- URL重定向漏洞中Location头可控
- Referer头注入,某些Web应用程序可能会根据用户输入动态生成HTTP头部用于跨站点追踪(但没什么用)
- GET、POST参数值出现在了响应包头部且可控
- 日志注入,输入直接写入日志文件,导日志文件可伪造条目
- 邮件头注入,发送电子邮件时,把用户输入的内容直接插入到电子邮件头中
- API注入,某些Web应用程序可能会接受用户输入并将其作为HTTP头的一部分发送到外部API
- 文件上传中的文件名,将文件名直接包含在HTTP响应头
换行Payload
- 回车符 (Carriage Return,
\r
或%0D
): 表示回到当前行的开头 - 换行符 (Line Feed,
\n
或%0A
): 表示换到下一行
当这两个字符组合在一起(\r\n
或 %0D%0A
)时,表示一个完整的换行操作。HTTP协议中的头部字段和实际内容通常使用CRLF来分隔,因此这种组合在注入攻击中尤为关键
Demo演示分析
Demo-1
1 |
|
直接接收用户输入来设置X-Custom-Header响应头部,没有任何过滤
演示
注意:这里就不要再输入框直接输入了,因为是GET提交,”%”会被URL编码一次,就不再是换行符了,采用抓包修改或者Hackbar
都出现了警告,翻译是**”警告:标头不能包含多个标头,在 D:\phpStudy\PHPTutorial\WWW\crlf\index.php 第 5 行检测到换行符”**,也就是被拦截了,查了一下原因,是php版本太高了,已经有了防御CRLF攻击的机制
于是切换一个低版本的php:5.2
切换为了现有的最低的版本,还是不行。没事换一个demo来看呢,或许这种demo场景太”露骨”了,于是很多版本都会拦截,换一种场景演示
Demo-2
- 由于php对头部某些危险字符有着严格的过滤拦截机制,于是采用node.js来搭建demo-2
1 | const http = require('http'); |
演示
还是被拦截了呜呜
看来,Node.js 对于 HTTP 头部的内容也有严格的字符限制,不允许有控制字符(如 \r
和 \n
)出现在头部字段的内容中
那就不折腾了,反正就是这么个道理对吧哈哈,之后搞懂了怎么搭建再来补充这篇文章……
漏洞利用
1. Web缓存投毒
攻击者可以通过 CRLF 注入修改 Web 缓存服务器的缓存内容,影响后续用户的缓存数据。这种攻击可以导致缓存中注入恶意内容或伪造的响应。
示例攻击:
假设一个 Web 应用程序在某些条件下返回不同的内容,但没有对用户输入进行验证。攻击者可以提交以下内容:
1 | Cache-Control: no-cache\r\nX-Custom-Header: injected |
如果缓存服务器处理用户输入不当,这可能会导致缓存中的内容被恶意修改,之后再专门研究Web缓存投毒,此处简单提一句
2. 跨站脚本攻击(XSS)
攻击者可以利用 CRLF 注入来实现跨站脚本攻击,特别是当注入的内容被后续用户渲染时。
示例攻击:
假设一个应用程序允许用户输入内容并将其回显到 HTML 页面中。攻击者可以提交如下内容:
1 | <script>alert('XSS');</script>\r\nX-Injection-Header: injected |
如果用户输入未经过滤直接嵌入到 HTML 中,脚本将被执行,造成 XSS 攻击。
不仅如此,通过注入两个CRLF还能造成一个无视浏览器Filter的反射型XSS:
比如一个网站接受url参数http://test.sina.com.cn/?url=xxx,xxx放在Location后面作为一个跳转。如果我们输入的是:
1 | http://test.sina.com.cn/?url=%0d%0a%0d%0a<img src=1 onerror=alert(/xss/)> |
我们的返回包就会变成这样:
1 | 302 Moved Temporarily |
为什么说是无视浏览器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
我们来一个真实案例吧。 新浪某分站含有一个url跳转漏洞,危害并不大,于是我就想到了CRLF Injection,当我测试
1 | http://xxx.sina.com.cn/?url=%0a%0d%0a%0d%3Cimg%20src=1%3E |
的时候,发现图片已经输出在页面中了,说明CRLF注入成功了:
那么我们试试XSS看看:
看控制台,果然被XSS Filter拦截了。
那么我们就注入一个
1 | X-XSS-Protection:0 |
成功绕过XSS Filter!
3.固定会话攻击
1 | http://www.sina.com.cn%0aSet-cookie:JSPSESSID%3Dwooyun |
注入了一个换行,此时的返回包就会变成这样:
1 | 302 Moved Temporarily |
这个时候这样我们就给访问者设置了一个SESSION,造成一个“会话固定漏洞”
4. 邮件头注入
如果 Web 应用程序允许用户提供邮件头部字段(如通过电子邮件发送功能),CRLF 注入可以用来在邮件中注入额外的邮件头部。
示例攻击:
假设一个应用程序允许用户指定电子邮件的“发件人”字段,攻击者可以提交如下内容:
1 | Sender: attacker@example.com\r\nBcc: victim@example.com |
这将导致电子邮件发送到一个额外的 Bcc 收件人,可能导致信息泄露。
工具推荐
漏洞修复
过滤 \r 、\n 之类的行结束符,避免输入的数据污染其他 HTTP 首部字段。