# Nginx
{{#include ../../banners/hacktricks-training.md}}
## 缺失根位置
在配置 Nginx 服务器时,**root 指令**通过定义文件提供的基础目录发挥着关键作用。考虑下面的示例:
```bash
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/](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
```
## 不安全的路径限制
查看以下页面以了解如何绕过指令,例如:
```plaintext
location = /admin {
deny all;
}
location = /admin/ {
deny all;
}
```
{{#ref}}
../../pentesting-web/proxy-waf-protections-bypass.md
{{#endref}}
## 不安全的变量使用 / HTTP 请求分割
> [!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 (回车) 和 \n (换行) 在 HTTP 请求中表示新行字符,它们的 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://blog.detectify.com/2019/06/14/http-response-splitting-exploitations-and-mitigations/)。
此外,这种技术在 [**这个演讲中解释**](https://www.youtube.com/watch?v=gWQyWdZbdoY&list=PL0xCSYnG_iTtJe2V6PQqamBF73n7-f1Nr&index=77) 中提供了一些易受攻击的示例和检测机制。例如,为了从黑箱的角度检测这种错误配置,您可以使用以下请求:
- `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的安全报告中被强调,可以在[这里](https://hackerone.com/reports/370094)查看。对错误信息的进一步调查导致识别出它在[Nginx代码库的SSI过滤模块](https://github.com/nginx/nginx/blob/2187586207e1465d289ae64cedc829719a048a39/src/http/modules/ngx_http_ssi_filter_module.c#L365)中的发生,确定服务器端包含(SSI)是根本原因。
要**检测此错误配置**,可以执行以下命令,该命令涉及设置一个referer头以测试变量打印:
```bash
$ curl -H ‘Referer: bar’ http://localhost/foo$http_referer | grep ‘foobar’
```
对系统进行的扫描显示出多个实例,其中用户可以打印Nginx变量。然而,易受攻击实例数量的减少表明,修补此问题的努力在某种程度上取得了成功。
## 原始后端响应读取
Nginx通过`proxy_pass`提供了一项功能,允许拦截后端产生的错误和HTTP头,旨在隐藏内部错误消息和头。这是通过Nginx在响应后端错误时提供自定义错误页面来实现的。然而,当Nginx遇到无效的HTTP请求时,会出现挑战。这样的请求会按原样转发到后端,后端的原始响应随后直接发送给客户端,而不经过Nginx的干预。
考虑一个涉及uWSGI应用的示例场景:
```python
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**](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_intercept_errors): 此指令使 Nginx 能够为状态码大于 300 的后端响应提供自定义响应。它确保对于我们的示例 uWSGI 应用程序,`500 Error` 响应被 Nginx 拦截并处理。
- [**proxy_hide_header**](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_hide_header): 正如其名称所示,此指令从客户端隐藏指定的 HTTP 头,增强隐私和安全性。
当发出有效的 `GET` 请求时,Nginx 正常处理,返回标准错误响应而不泄露任何秘密头。然而,无效的 HTTP 请求绕过此机制,导致原始后端响应的暴露,包括秘密头和错误消息。
## merge_slashes 设置为关闭
默认情况下,Nginx 的 **`merge_slashes` 指令** 设置为 **`on`**,这会将 URL 中的多个正斜杠压缩为一个斜杠。此功能虽然简化了 URL 处理,但可能无意中掩盖了 Nginx 后面应用程序中的漏洞,特别是那些容易受到本地文件包含 (LFI) 攻击的应用程序。安全专家 **Danny Robinson 和 Rotem Bar** 强调了与此默认行为相关的潜在风险,尤其是当 Nginx 作为反向代理时。
为了减轻此类风险,建议对易受这些漏洞影响的应用程序 **关闭 `merge_slashes` 指令**。这确保 Nginx 在不改变 URL 结构的情况下将请求转发到应用程序,从而不掩盖任何潜在的安全问题。
有关更多信息,请查看 [Danny Robinson 和 Rotem Bar](https://medium.com/appsflyer/nginx-may-be-protecting-your-applications-from-traversal-attacks-without-you-even-knowing-b08f882fd43d)。
### **Maclicious 响应头**
如 [**此文**](https://mizu.re/post/cors-playground) 所示,如果 Web 服务器的响应中存在某些头,它们将改变 Nginx 代理的行为。您可以在 [**文档中查看**](https://www.nginx.com/resources/wiki/start/topics/examples/x-accel/):
- `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`** 的内容(路径遍历)。
### **Map 指令中的默认值**
在 **Nginx 配置**中,`map` 指令通常在 **授权控制**中发挥作用。一个常见的错误是未指定 **默认** 值,这可能导致未经授权的访问。例如:
```yaml
http {
map $uri $mappocallow {
/map-poc/private 0;
/map-poc/secret 0;
/map-poc/public 1;
}
}
```
```yaml
server {
location /map-poc {
if ($mappocallow = 0) {return 403;}
return 200 "Hello. It is private area: $mappocallow";
}
}
```
没有 `default`,**恶意用户**可以通过访问 `/map-poc` 中的 **未定义 URI** 来绕过安全性。[Nginx 手册](https://nginx.org/en/docs/http/ngx_http_map_module.html) 建议设置 **默认值** 以避免此类问题。
### **DNS 欺骗漏洞**
在某些条件下,对 Nginx 进行 DNS 欺骗是可行的。如果攻击者知道 Nginx 使用的 **DNS 服务器** 并且能够拦截其 DNS 查询,他们可以伪造 DNS 记录。然而,如果 Nginx 配置为使用 **localhost (127.0.0.1)** 进行 DNS 解析,则此方法无效。Nginx 允许如下指定 DNS 服务器:
```yaml
resolver 8.8.8.8;
```
### **`proxy_pass` 和 `internal` 指令**
**`proxy_pass`** 指令用于将请求重定向到其他服务器,无论是内部还是外部。**`internal`** 指令确保某些位置仅在 Nginx 内部可访问。虽然这些指令本身并不是漏洞,但其配置需要仔细检查以防止安全漏洞。
## proxy_set_header Upgrade & Connection
如果 nginx 服务器配置为传递 Upgrade 和 Connection 头,则可以执行 [**h2c Smuggling attack**](../../pentesting-web/h2c-smuggling.md) 来访问受保护的/内部端点。
> [!CAUTION]
> 这个漏洞将允许攻击者 **与 `proxy_pass` 端点建立直接连接**(在这种情况下是 `http://backend:9999`),其内容不会被 nginx 检查。
从 [这里](https://bishopfox.com/blog/h2c-smuggling-request) 获取的窃取 `/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;
}
```
> [!WARNING]
> 请注意,即使 `proxy_pass` 指向特定的 **path**,例如 `http://backend:9999/socket.io`,连接仍将与 `http://backend:9999` 建立,因此您可以 **联系该内部端点内的任何其他路径。因此,proxy_pass 的 URL 中指定路径并不重要。**
## 尝试一下
Detectify 创建了一个 GitHub 仓库,您可以使用 Docker 设置自己的易受攻击的 Nginx 测试服务器,包含本文讨论的一些错误配置,并尝试自己找到它们!
[https://github.com/detectify/vulnerable-nginx](https://github.com/detectify/vulnerable-nginx)
## 静态分析工具
### [GIXY](https://github.com/yandex/gixy)
Gixy 是一个分析 Nginx 配置的工具。Gixy 的主要目标是防止安全错误配置并自动检测缺陷。
### [Nginxpwner](https://github.com/stark0de/nginxpwner)
Nginxpwner 是一个简单的工具,用于查找常见的 Nginx 错误配置和漏洞。
## 参考文献
- [**https://blog.detectify.com/2020/11/10/common-nginx-misconfigurations/**](https://blog.detectify.com/2020/11/10/common-nginx-misconfigurations/)
- [**http://blog.zorinaq.com/nginx-resolver-vulns/**](http://blog.zorinaq.com/nginx-resolver-vulns/)
- [**https://github.com/yandex/gixy/issues/115**](https://github.com/yandex/gixy/issues/115)
{{#include ../../banners/hacktricks-training.md}}