Translated ['src/network-services-pentesting/pentesting-web/nginx.md'] t

This commit is contained in:
Translator 2025-07-12 09:39:48 +00:00
parent 0c83aa9994
commit 8f84c9285f
2 changed files with 71 additions and 21 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

View File

@ -5,7 +5,7 @@
## Missing root location <a href="#missing-root-location" id="missing-root-location"></a>
在配置 Nginx 服务器时,**root 指令** 扮演着关键角色,它定义了文件提供的基础目录。考虑下面的示例:
在配置 Nginx 服务器时,**root 指令**通过定义文件提供的基础目录发挥着关键作用。考虑下面的示例:
```bash
server {
root /etc/nginx;
@ -16,19 +16,19 @@ proxy_pass http://127.0.0.1:8080/;
}
}
```
在此配置中,`/etc/nginx` 被指定为根目录。此设置允许访问指定根目录中的文件,例如 `/hello.txt`。然而,重要的是要注意,仅定义了一个特定位置(`/hello.txt`)。根位置(`location / {...}`)没有配置。这一遗漏意味着根指令适用于全局,使得对根路径 `/` 的请求能够访问 `/etc/nginx` 下的文件。
在此配置中,`/etc/nginx` 被指定为根目录。此设置允许访问指定根目录中的文件,例如 `/hello.txt`。然而,重要的是要注意,仅定义了一个特定位置(`/hello.txt`)。根位置(`location / {...}`)没有配置。这一遗漏意味着根指令在全局范围内适用,使得对根路径 `/` 的请求能够访问 `/etc/nginx` 下的文件。
此配置引发了一个关键的安全考虑。一个简单的 `GET` 请求,例如 `GET /nginx.conf`,可能会通过提供位于 `/etc/nginx/nginx.conf` 的 Nginx 配置文件暴露敏感信息。将根目录设置为不那么敏感的目录,例如 `/etc`,可以减轻此风险,但仍可能允许意外访问其他关键文件,包括其他配置文件、访问日志,甚至用于 HTTP 基本身份验证的加密凭据。
此配置引发了一个关键的安全考虑。一个简单的 `GET` 请求,例如 `GET /nginx.conf`,可能会通过提供位于 `/etc/nginx/nginx.conf` 的 Nginx 配置文件暴露敏感信息。将根目录设置为不那么敏感的目录,例如 `/etc`,可以减轻此风险,但仍可能允许对其他关键文件的意外访问,包括其他配置文件、访问日志,甚至用于 HTTP 基本身份验证的加密凭据。
## Alias LFI Misconfiguration <a href="#alias-lfi-misconfiguration" id="alias-lfi-misconfiguration"></a>
在 Nginx 的配置文件中,需要仔细检查 "location" 指令。通过类似以下的配置可能会无意中引入一种称为本地文件包含LFI的漏洞
在 Nginx 的配置文件中,"location" 指令需要仔细检查。通过类似以下的配置可能会无意中引入一种称为本地文件包含LFI的漏洞
```
location /imgs {
alias /path/images/;
}
```
此配置容易受到 LFI 攻击,因为服务器将请求 `/imgs../flag.txt` 解释为尝试访问预期目录之外的文件,实际上解析为 `/path/images/../flag.txt`。此缺陷允许攻击者从服务器的文件系统中检索不应通过网络访问的文件。
此配置容易受到 LFI 攻击,因为服务器将请求 `/imgs../flag.txt` 解释为尝试访问超出预期目录的文件,实际上解析为 `/path/images/../flag.txt`。此缺陷允许攻击者从服务器的文件系统中检索不应通过网络访问的文件。
为了减轻此漏洞,应调整配置为:
```
@ -48,7 +48,7 @@ alias../ => HTTP status code 403
```
## 不安全的路径限制 <a href="#unsafe-variable-use" id="unsafe-variable-use"></a>
查看以下页面以了解如何绕过如:
查看以下页面以了解如何绕过指令,例如:
```plaintext
location = /admin {
deny all;
@ -62,7 +62,7 @@ deny all;
../../pentesting-web/proxy-waf-protections-bypass.md
{{#endref}}
## 不安全的变量使用 / HTTP 请求<a href="#unsafe-variable-use" id="unsafe-variable-use"></a>
## 不安全的变量使用 / HTTP 请求分 <a href="#unsafe-variable-use" id="unsafe-variable-use"></a>
> [!CAUTION]
> 易受攻击的变量 `$uri``$document_uri`,可以通过用 `$request_uri` 替换它们来修复。
@ -81,7 +81,7 @@ location / {
return 302 https://example.com$uri;
}
```
在HTTP请求中字符\r回车和\n换行表示新行字符它们的URL编码形式表示为`%0d%0a`。在请求中包含这些字符(例如,`http://localhost/%0d%0aDetectify:%20clrf`)到一个配置错误的服务器,会导致服务器发出一个名为`Detectify`的新头。这是因为$uri变量解码了URL编码的新行字符从而导致响应中出现意外的头
字符 \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
@ -93,7 +93,7 @@ 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://www.youtube.com/watch?v=gWQyWdZbdoY&list=PL0xCSYnG_iTtJe2V6PQqamBF73n7-f1Nr&index=77) 了几个脆弱的示例和检测机制。例如,为了从黑箱的角度检测这种错误配置,您可以使用以下请求:
- `https://example.com/%20X` - 任何 HTTP 代码
- `https://example.com/%20H` - 400 错误请求
@ -105,7 +105,7 @@ Detectify: clrf
- `http://company.tld/%20HTTP/1.1%0D%0AXXXX:%20x` - 任何 HTTP 代码
- `http://company.tld/%20HTTP/1.1%0D%0AHost:%20x` - 400 错误请求
在该演讲中发现的一些易受攻击的配置包括:
在该演讲中发现的一些脆弱配置包括:
- 注意 **`$uri`** 在最终 URL 中是如何设置的
```
@ -127,17 +127,67 @@ 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是根本原因。
发现**用户提供的数据**在某些情况下可能被视为**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变量。然而易受攻击实例数量的减少表明修补此问题的努力在某种程度上是成功的。
### 使用 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;
}
}
}
```
使用以下有效载荷:
```
GET /?../../../../../../../../etc/passwd HTTP/1.1
Host: example.com
```
使用我们的有效载荷,我们将逃离根目录(在 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
![示例burp请求](../../images/nginx_try_files.png)
## 原始后端响应读取
Nginx通过`proxy_pass`提供了一项功能允许拦截后端产生的错误和HTTP头旨在隐藏内部错误消息和头。这是通过Nginx在响应后端错误时提供自定义错误页面来实现的。然而当Nginx遇到无效的HTTP请求时会出现挑战。这样的请求会按原样转发到后端后端的原始响应随后直接发送给客户端而不经过Nginx的干预。
Nginx通过`proxy_pass`提供了一项功能允许拦截后端产生的错误和HTTP头旨在隐藏内部错误消息和头信息。这是通过Nginx在响应后端错误时提供自定义错误页面来实现的。然而当Nginx遇到无效的HTTP请求时会出现挑战。这样的请求会按原样转发到后端后端的原始响应直接发送给客户端而不经过Nginx的干预。
考虑一个涉及uWSGI应用的示例场景
```python
@ -145,7 +195,7 @@ 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 配置中使用了特定的指令:
此,在 Nginx 配置中使用了特定的指令:
```
http {
error_page 500 /html/error.html;
@ -153,16 +203,16 @@ 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_intercept_errors**](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_intercept_errors): 此指令使 Nginx 能够为状态码大于 300 的后端响应提供自定义响应。它确保对于我们的示例 uWSGI 应用程序,`500 错误` 响应被 Nginx 拦截并处理。
- [**proxy_hide_header**](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_hide_header): 正如其名称所示,此指令从客户端隐藏指定的 HTTP 头,增强隐私和安全性。
当发出有效的 `GET` 请求时Nginx 正常处理,返回标准错误响应而不泄露任何秘密头。然而,无效的 HTTP 请求绕过此机制,导致原始后端响应的暴露,包括秘密头和错误消息。
## merge_slashes 设置为关闭
## merge_slashes 设置为 off
默认情况下Nginx 的 **`merge_slashes` 指令** 设置为 **`on`**,这会将 URL 中的多个正斜杠压缩为一个斜杠。此功能虽然简化了 URL 处理,但可能无意中掩盖了 Nginx 后面应用程序中的漏洞,特别是那些容易受到本地文件包含 (LFI) 攻击的应用程序。安全专家 **Danny Robinson 和 Rotem Bar** 强调了这种默认行为可能带来的风险,尤其是当 Nginx 作为反向代理时。
为了减轻此类风险,建议对易受这些漏洞影响的应用程序 **关闭 `merge_slashes` 指令**。这确保 Nginx 在不改变 URL 结构的情况下将请求转发给应用程序,从而不掩盖任何潜在的安全问题。
为了减轻此类风险,建议对易受这些漏洞影响的应用程序 **关闭 `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)。
@ -180,7 +230,7 @@ proxy_hide_header Secret-Header;
### **Map 指令中的默认值**
**Nginx 配置**中,`map` 指令通常在 **授权控制**中发挥作用。一个常见的错误是未指定 **默认** 值,这可能导致未经授权的访问。例如:
**Nginx 配置**中,`map` 指令通常在 **授权控制** 中发挥作用。一个常见的错误是未指定 **默认** 值,这可能导致未经授权的访问。例如:
```yaml
http {
map $uri $mappocallow {
@ -199,7 +249,7 @@ return 200 "Hello. It is private area: $mappocallow";
}
}
```
没有 `default`**恶意用户**可以通过访问 `/map-poc` 中的 **未定义 URI** 来绕过安全性。[Nginx 手册](https://nginx.org/en/docs/http/ngx_http_map_module.html) 建议设置 **默认值** 以避免此类问题。
没有 `default`**恶意用户** 可以通过访问 `/map-poc` 中的 **未定义 URI** 来绕过安全性。[Nginx 手册](https://nginx.org/en/docs/http/ngx_http_map_module.html) 建议设置 **默认值** 以避免此类问题。
### **DNS 欺骗漏洞**
@ -218,7 +268,7 @@ resolver 8.8.8.8;
> [!CAUTION]
> 该漏洞将允许攻击者 **与 `proxy_pass` 端点建立直接连接**(在此情况下为 `http://backend:9999`),其内容不会被 nginx 检查。
从 [这里](https://bishopfox.com/blog/h2c-smuggling-request) 获取窃取 `/flag` 的易受攻击配置示例:
从 [这里](https://bishopfox.com/blog/h2c-smuggling-request) 获取的窃取 `/flag` 的漏洞配置示例:
```
server {
listen 443 ssl;
@ -251,7 +301,7 @@ Detectify 创建了一个 GitHub 仓库,您可以使用 Docker 设置自己的
### [GIXY](https://github.com/yandex/gixy)
Gixy 是一个分析 Nginx 配置的工具。Gixy 的主要目标是防止安全错误配置并自动检测缺陷
Gixy 是一个分析 Nginx 配置的工具。Gixy 的主要目标是防止安全错误配置并自动化缺陷检测。
### [Nginxpwner](https://github.com/stark0de/nginxpwner)