Nginx

Tip

学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE) 学习和实践 Azure 黑客技术:HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks

缺失的 root location

在配置 Nginx 服务器时,root directive 起着关键作用,用于定义文件被服务的基目录。考虑下面的示例:

server {
root /etc/nginx;

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

在此配置中,/etc/nginx 被指定为根目录。该设置允许访问指定根目录下的文件,例如 /hello.txt。然而,重要的是要注意只定义了一个特定的 location (/hello.txt)。没有为根位置 (location / {...}) 配置。这一遗漏意味着 root 指令在全局生效,使得对根路径 / 的请求能够访问 /etc/nginx 下的文件。

这种配置带来了关键的安全考虑。一个简单的 GET 请求,比如 GET /nginx.conf,可能会通过返回位于 /etc/nginx/nginx.conf 的 Nginx 配置文件而暴露敏感信息。将 root 设置为较不敏感的目录(例如 /etc)可以缓解此风险,但仍可能允许对其他关键文件的非预期访问,包括其他配置文件、访问日志,甚至用于 HTTP basic authentication 的加密凭证。

Alias LFI 错误配置

在 Nginx 的配置文件中,需要仔细检查 location 指令。通过类似如下的配置,可能会无意中引入一种称为 Local File Inclusion (LFI) 的漏洞:

location /imgs {
alias /path/images/;
}

该配置容易受到 LFI 攻击,因为服务器会将类似 /imgs../flag.txt 的请求解释为试图访问预期目录之外的文件,实际上会解析为 /path/images/../flag.txt
该漏洞允许攻击者从服务器的文件系统中检索不应通过 Web 访问的文件。

为缓解此漏洞,应调整配置为:

location /imgs/ {
alias /path/images/;
}

更多信息: https://www.acunetix.com/vulnerabilities/web/path-traversal-via-misconfigured-nginx-alias/

Accunetix 测试:

alias../ => HTTP status code 403
alias.../ => HTTP status code 404
alias../../ => HTTP status code 403
alias../../../../../../../../../../../ => HTTP status code 400
alias../ => HTTP status code 403

不安全的路径限制

查看以下页面以了解如何绕过如下指令:

location = /admin {
deny all;
}

location = /admin/ {
deny all;
}

Proxy / WAF Protections Bypass

不安全的变量使用 / HTTP Request Splitting

Caution

变量 $uri$document_uri 易受攻击,这可以通过将它们替换为 $request_uri 来修复。

正则表达式也可能存在漏洞,例如:

location ~ /docs/([^/])? { … $1 … } - 有漏洞

location ~ /docs/([^/\s])? { … $1 … } - 无漏洞(检查空格)

location ~ /docs/(.*)? { … $1 … } - 无漏洞

下面的例子演示了 Nginx 配置中的一个漏洞:

location / {
return 302 https://example.com$uri;
}

字符 \r(Carriage Return)和 \n(Line Feed)在 HTTP 请求中表示换行字符,它们的 URL 编码形式表示为 %0d%0a。在发送到配置错误的服务器的请求中包含这些字符(例如 http://localhost/%0d%0aDetectify:%20clrf)会导致服务器发出一个名为 Detectify 的新 header。これは因为 $uri 变量会解码 URL 编码的换行字符,从而在响应中导致出现意外的 header:

HTTP/1.1 302 Moved Temporarily
Server: nginx/1.19.3
Content-Type: text/html
Content-Length: 145
Connection: keep-alive
Location: https://example.com/
Detectify: clrf

Learn more about the risks of CRLF injection and response splitting at https://blog.detectify.com/2019/06/14/http-response-splitting-exploitations-and-mitigations/.

此外,该技术在 explained in this talk 中进行了讲解,包含一些易受攻击的示例和检测机制。例如,为了从 blackbox 视角检测此错误配置,你可以发送以下请求:

  • https://example.com/%20X - Any HTTP code
  • https://example.com/%20H - 400 Bad Request

如果存在漏洞,第一个会返回(因为 “X” 可以是任意 HTTP 方法),而第二个会返回错误(因为 H 不是有效的方法)。因此服务器将接收到类似:GET / H HTTP/1.1 的请求,这会触发错误。

另一个检测示例:

  • http://company.tld/%20HTTP/1.1%0D%0AXXXX:%20x - Any HTTP code
  • http://company.tld/%20HTTP/1.1%0D%0AHost:%20x - 400 Bad Request

该演讲中展示的一些易受影响的配置包括:

  • 注意 $uri 在最终 URL 中按原样设置
location ^~ /lite/api/ {
proxy_pass http://lite-backend$uri$is_args$args;
}
  • 注意 $uri 再次出现在 URL(这次在参数内)
location ~ ^/dna/payment {
rewrite ^/dna/([^/]+) /registered/main.pl?cmd=unifiedPayment&context=$1&native_uri=$uri break;
proxy_pass http://$back;

现在在 AWS S3

location /s3/ {
proxy_pass https://company-bucket.s3.amazonaws.com$uri;
}

任意变量

发现在某些情况下,用户提供的数据可能会被当作 Nginx 变量 处理。导致该行为的原因尚不完全清楚,但这种现象既不罕见,也不容易验证。该异常在 HackerOne 的一份安全报告中被指出,可在此处查看。对错误信息的进一步调查将其定位到 Nginx 代码库的 SSI filter 模块,并将 Server Side Includes (SSI) 确定为根本原因。

要检测此错误配置,可执行下面的命令,该命令通过设置 referer header 来测试变量是否被打印:

$ curl -H ‘Referer: bar’ http://localhost/foo$http_referer | grep ‘foobar’

对这种错误配置的跨系统扫描发现了多个实例,用户可以打印 Nginx 变量。不过,可被攻击实例数量的减少表明修补该问题的工作在某种程度上取得了成功。

使用 try_files 与 $URI$ARGS 变量

下面的 Nginx 错误配置可能导致 LFI 漏洞:

location / {
try_files $uri$args $uri$args/ /index.html;
}

在我们的配置中有指令 try_files,用于按指定顺序检查文件是否存在。Nginx 会返回它找到的第一个文件。try_files 指令的基本语法如下:

try_files file1 file2 ... fileN fallback;

Nginx 将按指定顺序检查每个文件是否存在。如果文件存在,则会立即提供该文件。如果所有指定的文件都不存在,请求将被传递到回退选项,该回退选项可以是另一个 URI 或特定的错误页面。

但是,当在此指令中使用 $uri$args 变量时,Nginx 会尝试查找与请求 URI 及任何查询字符串参数组合匹配的文件。因此我们可以利用此配置:

http {
server {
root /var/www/html/public;

location / {
try_files $uri$args $uri$args/ /index.html;
}
}
}

使用以下 payload:

GET /?../../../../../../../../etc/passwd HTTP/1.1
Host: example.com

使用我们的 payload,我们将绕过根目录(在 Nginx 配置中定义)并加载 /etc/passwd 文件。在调试日志中我们可以观察到 Nginx 如何尝试这些文件:

...SNIP...

2025/07/11 15:49:16 [debug] 79694#79694: *4 trying to use file: "/../../../../../../../../etc/passwd" "/var/www/html/public/../../../../../../../../etc/passwd"
2025/07/11 15:49:16 [debug] 79694#79694: *4 try file uri: "/../../../../../../../../etc/passwd"

...SNIP...

2025/07/11 15:49:16 [debug] 79694#79694: *4 http filename: "/var/www/html/public/../../../../../../../../etc/passwd"

...SNIP...

2025/07/11 15:49:16 [debug] 79694#79694: *4 HTTP/1.1 200 OK

使用上述配置针对 Nginx 的 PoC: Example burp request

读取后端原始响应

Nginx 通过 proxy_pass 提供了一个功能,可以拦截后端产生的错误和 HTTP 头,从而隐藏内部错误信息和头部。这是通过 Nginx 在后端错误时返回自定义错误页面来实现的。然而,当 Nginx 遇到无效的 HTTP 请求时会出现问题。这样的请求会按原样转发到后端,后端的原始响应会在不经过 Nginx 处理的情况下直接返回给客户端。

考虑一个涉及 uWSGI 应用的示例场景:

def application(environ, start_response):
start_response('500 Error', [('Content-Type', 'text/html'), ('Secret-Header', 'secret-info')])
return [b"Secret info, should not be visible!"]

为此,Nginx 配置中使用了特定的指令:

http {
error_page 500 /html/error.html;
proxy_intercept_errors on;
proxy_hide_header Secret-Header;
}
  • proxy_intercept_errors: 该指令使 Nginx 在后端响应状态码大于 300 时提供自定义响应。比如对于我们的 uWSGI 应用,500 Error 响应会被 Nginx 拦截并处理。
  • proxy_hide_header: 顾名思义,该指令会向客户端隐藏指定的 HTTP 头,从而增强隐私和安全性。

当发出有效的 GET 请求时,Nginx 会正常处理,返回标准的错误响应而不会泄露任何秘密头。然而,某些无效的 HTTP 请求可以绕过该机制,导致暴露原始后端响应,包括秘密头和错误信息。

merge_slashes 设置为 off

默认情况下,Nginx 的 merge_slashes 指令 被设置为 on,它会将 URL 中的多个连续斜杠压缩为单个斜杠。该特性在简化 URL 处理的同时,可能会无意中掩盖部署在 Nginx 之后的应用程序中的漏洞,尤其是易受 local file inclusion (LFI) 攻击的应用。安全专家 Danny Robinson and Rotem Bar 已指出这种默认行为的潜在风险,特别是在 Nginx 作为反向代理时。

为降低此类风险,建议对易受这些漏洞影响的应用将 merge_slashes 指令设置为 off。这样可以确保 Nginx 在转发请求到应用时不修改 URL 结构,从而不会掩盖潜在的安全问题。

更多信息请参见 Danny Robinson and Rotem Bar

Maclicious 响应头

this writeup 所示,某些头如果出现在 Web 服务器的响应中,会改变 Nginx 代理的行为。可以在 in the docs 中查看它们:

  • X-Accel-Redirect: 指示 Nginx 将请求在内部重定向到指定位置。
  • X-Accel-Buffering: 控制 Nginx 是否应对响应进行缓冲。
  • X-Accel-Charset: 在使用 X-Accel-Redirect 时为响应设置字符集。
  • X-Accel-Expires: 在使用 X-Accel-Redirect 时设置响应的过期时间。
  • X-Accel-Limit-Rate: 在使用 X-Accel-Redirect 时限制响应的传输速率。

例如,头部 X-Accel-Redirect 会导致 nginx 进行内部重定向。因此,如果 nginx 配置包含 root /,而 Web 服务器的响应包含 X-Accel-Redirect: .env,则 nginx 会发送 /.env 的内容(路径遍历)。

map 指令中的默认值

Nginx 配置 中,map 指令通常在 授权控制 中发挥作用。一个常见错误是不指定 默认 值,这可能导致未授权访问。例如:

http {
map $uri $mappocallow {
/map-poc/private 0;
/map-poc/secret 0;
/map-poc/public 1;
}
}
server {
location /map-poc {
if ($mappocallow = 0) {return 403;}
return 200 "Hello. It is private area: $mappocallow";
}
}

如果没有 default,恶意用户可以通过访问 /map-poc 中的 未定义的 URI 绕过安全。 The Nginx manual 建议设置 默认值 以避免此类问题。

DNS Spoofing Vulnerability

在某些条件下,对 Nginx 的 DNS spoofing 是可行的。如果攻击者知道 Nginx 使用的 DNS 服务器 并且能够拦截其 DNS 查询,就可以伪造 DNS 记录。然而,如果 Nginx 被配置为使用 localhost (127.0.0.1) 进行 DNS 解析,该方法将无效。Nginx 允许按如下方式指定 DNS 服务器:

resolver 8.8.8.8;

proxy_passinternal 指令

proxy_pass 指令用于将请求重定向到其他服务器(内部或外部)。internal 指令确保某些 location 仅能在 Nginx 内部访问。虽然这些指令本身不是漏洞,但其配置需要仔细检查以防止安全疏漏。

proxy_set_header Upgrade & Connection

如果 nginx 服务器被配置为传递 Upgrade 和 Connection 报头,可能会发生 h2c Smuggling attack,从而访问受保护/内部端点。

Caution

该漏洞将允许攻击者 proxy_pass 端点建立直接连接(在此示例中为 http://backend:9999),其内容不会被 nginx 检查。

Example of vulnerable configuration to steal /flag from here:

server {
listen       443 ssl;
server_name  localhost;

ssl_certificate       /usr/local/nginx/conf/cert.pem;
ssl_certificate_key   /usr/local/nginx/conf/privkey.pem;

location / {
proxy_pass http://backend:9999;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
}

location /flag {
deny all;
}

Warning

注意即使 proxy_pass 指向一个特定的 路径(例如 http://backend:9999/socket.io),连接仍然会建立到 http://backend:9999,因此你可以 访问该内部端点中的任何其他路径。这意味着在 proxy_pass 的 URL 中指定路径并不重要。

HTTP/3 QUIC 模块 远程 DoS & leak (2024)

2024 年间,Nginx 披露了 CVE-2024-31079、CVE-2024-32760、CVE-2024-34161 和 CVE-2024-35200,显示当实验性的 ngx_http_v3_module 被编译启用并暴露了 listen ... quic 套接字时,单个恶意 QUIC 会话 就能使 worker 进程崩溃或导致内存 leak。受影响的构建为 1.25.0–1.25.5 和 1.26.0,1.27.0/1.26.1 已包含修复;内存泄露(CVE-2024-34161)还需要 MTU 大于 4096 字节才能将敏感数据暴露出来(详情见下文 2024 年 nginx advisory)。

Recon & exploitation hints

  • HTTP/3 是可选启用的,因此通过扫描 Alt-Svc: h3=":443" 响应或对 UDP/443 进行 QUIC 握手爆破来确认支持;一旦确认,使用自定义的 quiche-client/nghttp3 payloads 对握手和 STREAM 帧进行 fuzz,以触发 worker 崩溃并强制日志泄露。
  • 快速 fingerprint 目标支持:
nginx -V 2>&1 | grep -i http_v3
rg -n "listen .*quic" /etc/nginx/

TLS 会话恢复绕过客户端证书认证 (CVE-2025-23419)

2025 年 2 月的一份公告披露,使用 OpenSSL 构建的 nginx 1.11.4–1.27.3 允许从一个基于名称的虚拟主机重用 TLS 1.3 会话 到另一个主机,因此与无需证书的主机协商过的客户端可以重放 ticket/PSK 跳入受 ssl_verify_client on; 保护的 vhost,从而完全绕过 mTLS。该漏洞在多个虚拟主机共享相同的 TLS 1.3 会话缓存和 tickets 时触发(参见下面引用的 2025 nginx 公告)。

攻击者操作流程

# 1. Create a TLS session on the public vhost and save the session ticket
openssl s_client -connect public.example.com:443 -sess_out ticket.pem

# 2. Replay that session ticket against the mTLS vhost before it expires
openssl s_client -connect admin.example.com:443 -sess_in ticket.pem -ign_eof

如果目标存在该漏洞,第二次握手会在不出示客户端证书的情况下完成,从而暴露受保护的位置。

需要审计的内容

  • 共享 ssl_session_cache shared:SSL 并启用 ssl_session_tickets on; 的混合 server_name 块。
  • 期望使用 mTLS 的 Admin/API 块,但从公共主机继承了共享会话缓存/票据设置。
  • 在全局启用 TLS 1.3 会话恢复的自动化(例如 Ansible roles),而未考虑 vhost 隔离。

HTTP/2 Rapid Reset resilience (CVE-2023-44487 behavior)

当操作员将 keepalive_requestshttp2_max_concurrent_streams 设置高于默认值时,HTTP/2 Rapid Reset attack (CVE-2023-44487) 仍会影响 nginx:攻击者打开一个 HTTP/2 连接,用数千个流淹没它,然后立即发送 RST_STREAM 帧,使并发上限永远不会被达到,而 CPU 不断在连接拆除逻辑上消耗。Nginx 默认值(128 并发流,1000 keepalive 请求)将影响范围保持较小;将这些限制“显著提高”会让单个客户端就能轻易耗尽 worker(见下文引用的 F5 分析)。

检测提示

# Highlight risky knobs
rg -n "http2_max_concurrent_streams" /etc/nginx/
rg -n "keepalive_requests" /etc/nginx/

那些在这些指令中显示异常高值的主机是首要目标:单个 HTTP/2 客户端可以循环创建流并立即发送 RST_STREAM 帧,从而保持 CPU 占用高企而不触发并发上限。

Try it yourself

Detectify 创建了一个 GitHub 仓库,你可以使用 Docker 搭建包含本文讨论的一些错误配置的易受攻击的 Nginx 测试服务器,并自行尝试发现这些问题!

https://github.com/detectify/vulnerable-nginx

Static Analyzer tools

GIXY

Gixy 是一个用于分析 Nginx 配置的工具。Gixy 的主要目标是防止安全错误配置并自动化缺陷检测。

Nginxpwner

Nginxpwner 是一个用于查找常见 Nginx 错误配置和漏洞的简单工具。

References

Tip

学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE) 学习和实践 Azure 黑客技术:HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks