Nginx

学习与实践 AWS 黑客技术:HackTricks 培训 AWS 红队专家 (ARTE) 学习与实践 GCP 黑客技术:HackTricks 培训 GCP 红队专家 (GRTE)

支持 HackTricks

即时可用的漏洞评估与渗透测试设置。从任何地方运行完整的渗透测试,使用 20 多种工具和功能,从侦察到报告。我们不替代渗透测试人员 - 我们开发自定义工具、检测和利用模块,以便让他们有更多时间深入挖掘、获取 shell 并享受乐趣。

缺失的根目录

在配置 Nginx 服务器时,root 指令通过定义文件提供的基础目录发挥着关键作用。考虑以下示例:

server {
root /etc/nginx;

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

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

此配置引发了一个关键的安全考虑。一个简单的 GET 请求,例如 GET /nginx.conf,可能会通过提供位于 /etc/nginx/nginx.conf 的 Nginx 配置文件来暴露敏感信息。将根目录设置为不那么敏感的目录,例如 /etc,可以减轻此风险,但仍可能允许意外访问其他关键文件,包括其他配置文件、访问日志,甚至用于 HTTP 基本身份验证的加密凭据。

Alias LFI Misconfiguration

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

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

此配置容易受到LFI攻击,因为服务器将请求如/imgs../flag.txt解释为尝试访问意图之外的文件,有效地解析为/path/images/../flag.txt。此缺陷允许攻击者从服务器的文件系统中检索不应通过网络访问的文件。

为了减轻此漏洞,应调整配置为:

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 请求拆分

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

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

location ~ /docs/([^/])? { … $1 … } - 易受攻击

location ~ /docs/([^/\s])? { … $1 … } - 不易受攻击(检查空格)

location ~ /docs/(.*)? { … $1 … } - 不易受攻击

Nginx 配置中的一个漏洞通过以下示例演示:

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

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

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

了解有关 CRLF 注入和响应拆分风险的更多信息,请访问 https://blog.detectify.com/2019/06/14/http-response-splitting-exploitations-and-mitigations/

此外,这种技术在 这个演讲中解释,提供了一些易受攻击的示例和检测机制。例如,为了从黑箱的角度检测此错误配置,您可以使用以下请求:

  • https://example.com/%20X - 任何 HTTP 代码

  • https://example.com/%20H - 400 错误请求

如果存在漏洞,第一个将返回,因为 "X" 是任何 HTTP 方法,第二个将返回错误,因为 H 不是有效的方法。因此,服务器将接收到类似于 GET / H HTTP/1.1 的内容,这将触发错误。

另一个检测示例是:

  • http://company.tld/%20HTTP/1.1%0D%0AXXXX:%20x - 任何 HTTP 代码

  • http://company.tld/%20HTTP/1.1%0D%0AHost:%20x - 400 错误请求

在该演讲中发现的一些易受攻击的配置是:

  • 注意 $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;
}

Any variable

发现用户提供的数据在某些情况下可能被视为Nginx 变量。这种行为的原因仍然有些模糊,但并不罕见,也不容易验证。这个异常在HackerOne的安全报告中被强调,可以在这里查看。对错误消息的进一步调查导致识别出它在Nginx代码库的SSI过滤模块中的发生,确定服务器端包含(SSI)是根本原因。

检测此错误配置,可以执行以下命令,该命令涉及设置引用头以测试变量打印:

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

扫描此配置错误的系统揭示了多个实例,其中用户可以打印Nginx变量。然而,易受攻击实例数量的减少表明修补此问题的努力在某种程度上取得了成功。

原始后端响应读取

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 错误 响应被 Nginx 拦截并处理。

  • proxy_hide_header: 正如其名称所示,此指令从客户端隐藏指定的 HTTP 头,增强隐私和安全性。

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

merge_slashes 设置为 off

默认情况下,Nginx 的 merge_slashes 指令 设置为 on,这会将 URL 中的多个正斜杠压缩为一个斜杠。此功能虽然简化了 URL 处理,但可能无意中掩盖了 Nginx 后面应用程序中的漏洞,特别是那些容易受到本地文件包含 (LFI) 攻击的应用程序。安全专家 Danny Robinson 和 Rotem Bar 强调了与此默认行为相关的潜在风险,尤其是当 Nginx 作为反向代理时。

为了减轻此类风险,建议对易受这些漏洞影响的应用程序 关闭 merge_slashes 指令。这确保 Nginx 在不更改 URL 结构的情况下将请求转发到应用程序,从而不掩盖任何潜在的安全问题。

有关更多信息,请查看 Danny Robinson 和 Rotem Bar

恶意响应头

此文 所示,如果某些头出现在来自 Web 服务器的响应中,它们将改变 Nginx 代理的行为。您可以在 文档中查看

  • 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 内部 重定向。因此,具有类似 root / 的 Nginx 配置和来自 Web 服务器的响应 X-Accel-Redirect: .env 将使 Nginx 发送 /.env 的内容(路径遍历)。

映射指令中的默认值

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 来绕过安全性。Nginx 手册 建议设置 默认值 以避免此类问题。

DNS 欺骗漏洞

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

resolver 8.8.8.8;

proxy_passinternal 指令

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

proxy_set_header Upgrade & Connection

如果 nginx 服务器配置为传递 Upgrade 和 Connection 头,则可以执行 h2c Smuggling attack 来访问受保护/内部端点。

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

这里 获取的示例漏洞配置以窃取 /flag

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;
}

请注意,即使 proxy_pass 指向特定的 路径,例如 http://backend:9999/socket.io,连接将与 http://backend:9999 建立,因此您可以 联系该内部端点内的任何其他路径。因此,proxy_pass 的 URL 中指定路径并不重要。

尝试一下

Detectify 创建了一个 GitHub 仓库,您可以使用 Docker 设置自己的易受攻击的 Nginx 测试服务器,包含本文讨论的一些错误配置,并尝试自己找到它们!

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

静态分析工具

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

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

参考资料

即时可用的漏洞评估和渗透测试设置。从任何地方运行完整的渗透测试,使用 20 多种工具和功能,从侦察到报告。我们不替代渗透测试人员 - 我们开发自定义工具、检测和利用模块,以便让他们有更多时间深入挖掘、获取 shell 并享受乐趣。

学习和实践 AWS 黑客攻击:HackTricks 培训 AWS 红队专家 (ARTE) 学习和实践 GCP 黑客攻击:HackTricks 培训 GCP 红队专家 (GRTE)

支持 HackTricks

Last updated