nginx简介
Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,在BSD-like 协议下发行。其特点是占有内存少,并发能力强,事实上nginx的并发能力在同类型的网页服务器中表现较好,中国大陆使用nginx网站用户有:百度、京东、新浪、网易、腾讯、淘宝等。
环境搭建
git clone https://github.com/detectify/vulnerable-nginx.gitcd vulnerable-nginxdocker-compose up -d浏览器访问:http://xxx.xxx.xxx.xxx:5000/cats
根目录位置丢失
危害:在某些情况下,访问者可能会访问其他配置文件、访问日志甚至 HTTP 基本身份验证的加密凭据
示例
root指令指定 Nginx 的根文件夹。nginx的根文件夹是/etc/nginx
,这意味着我们可以访问该文件夹中的文件。上面的配置没有针对/(location / {...})
的位置,只有/cats
的位置。因此,root 指令会被设置为全局,这意味着对/的请求会将你带到本地路径/etc/nginx
。
像GET /nginx.conf
这样简单的请求都能显示存储在/etc/nginx/nginx.conf
中Nginx 配置文件的内容。如果将根设置为/etc
,则对/nginx/nginx.conf
的GET请求将显示配置文件。
root指令指定/etc/nginx
文件夹位置,可访问该文件夹下所有文件
请求访问http://192.168.240.129:5000/nginx.conf成功看到了nginx.conf文件内容
收集的近 50000 个Nginx 配置文件中,最常见的根路径如下:
off-by-slash
危害
这可能导致服务器状态通过 URL公开,或者可能让不希望公开访问的路径可访问
结合一条缺少尾斜杠的location指令与一条alias指令,来读取 Web 应用程序的源代码。鲜为人知的是,它还可以与其他指令(例如proxy_pass)一起使用。
示例
如下图。路径指向的是 /usr/share/nginx/html/
一条缺少尾斜杠的location
指令与一条alias指令
在cats
后加.. 可越权访问 nginx
下的文件
http://192.168.240.129/cats../flag.txt
它还可以与其他指令(例如proxy_pass
)一起使用
proxy_pass http://apache:80/catpictures/;
如果一个 Nginx 服务器运行能在 server 访问的以下配置,则可以假定访问者只能访问http://apache:80/catpictures/
下的路径
当请求http://192.168.240.129:5000/image
时,Nginx将首先规范化 URL。然后,它会查看前缀/images
是否与URL 匹配,本例中是匹配的
然后,服务器从 URL 中删除该前缀,保留/1.jpg
路径。再将此路径添加到proxy_pass
URL 中,从而得到最终URL http://apache:80/images//1.jpg
请求http://192.168.240.129:5000/image../
可以利用这种错误配置,这将导致 Nginx 请求URL:
http://apache:80/catpictures../
,其标准化为http://apache:80/
成功查看到secret.html
导致访问者看到可能让不希望公开访问的路径可访问
不安全的变量使用
1、使用 $uri 可导致 CRL
F
注入
危害
与Nginx 变量有关的另一个错误配置是使用$uri
或$document_uri
代替$request_uri
。$uri
和$document_uri包含标准化的 URI,而 Nginx 中的normalization
包括对 URI 解码的 URL。在 Nginx 配置中创建重定向时经常会使用$uri,结果导致 CRLF 注入
示例
一个易受攻击的 Nginx 配置
HTTP 请求的换行符为\r
(回车)和\n
(换行)。对换行符进行 URL 编码将导致以下字符表示形式%0d%0a
。如果将这些字符包含在对配置错误的服务器的一个请求中
(例如http://192.168.240.129/images-credits%0d%0aDetectify:%20clrf)
,则该服务器将使用一个名为Detectify的新标头进行响应,因为 $uri 变量包含URL 解码的换行符。
2、SCRIPT_NAME
危害
有可能发生 XSS
像下面这样的配置
location ~ \.php$ { include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_pass 127.0.0.1:9000; }
主要问题是 Nginx 会将所有 URL 发送到以.php结尾的 PHP 解释器,即使该文件在磁盘上不存在。这是 Nginx 创建的“陷阱和常见错误”文档中提到的,在许多 Nginx 配置中都常见的错误。如果这个 PHP 脚本试图基于SCRIPT_NAME定义一个基本 URL,则将发生 XSS。
<?php if(basename($_SERVER['SCRIPT_NAME']) ==basename($_SERVER['SCRIPT_FILENAME'])) echo dirname($_SERVER['SCRIPT_NAME']); ?> GET /index.php/<script>alert(1)</script>/index.phpSCRIPT_NAME = /index.php/<script>alert(1)</script>/index.php
3、Any 变量
危害
用户可以在其中打印 Nginx 变量的值
在某些情况下,用户提供的数据可以视为 Nginx 变量。目前尚不清楚为什么会发生这种情况,但如这份H1报告所示,这种情况并不罕见或不容易测试。如果搜索错误消息,我们可以看到它是在SSI过滤器模块中找到的,表明这是由 SSI 引起的。
一种测试方法是设置一个引用标头值:
$ curl -H ‘Referer: bar’ http://localhost/foo$http_referer | grep ‘foobar’
原始后端响应读取
危害
隐藏内部错误消息和标头以便 Nginx 处理
使用 Nginx 的proxy_pass
,可以拦截后端创建的错误和 HTTP 标头。如果你这个方法会非常有用。如果后端回答一个错误,Nginx 将自动提供一个自定义错误页面。但如果 Nginx 无法理解这是一个 HTTP 响应怎么办?
如果一个客户端向 Nginx 发送了一个无效的 HTTP 请求,则该请求将按原样转发到后端,后端将使用其原始内容来应答。然后,Nginx 将无法理解无效的 HTTP 响应,而将其转发给客户端。想象一个这样的 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;}
如果后端的响应状态大于 300,proxy_intercept_errors将提供一个自定义响应。在上面的 uWSGI 应用程序中,我们将发送一个500 Error,Nginx 将拦截该错误。
proxy_hide_header可以自解释;它将从客户端隐藏任何指定的 HTTP 标头。
如果我们发送一个普通的 GET 请求,则 Nginx 将返回:
HTTP/1.1 500 Internal Server ErrorServer: nginx/1.10.3Content-Type: text/htmlContent-Length: 34Connection: close
但是,如果我们发送一个无效的 HTTP 请求,例如:
GET /? XTTP/1.1Host: 127.0.0.1Connection: close
我们将收到以下答复:
XTTP/1.1 500 ErrorContent-Type: text/htmlSecret-Header: secret-infoSecret info, should not be visible!
merge_slashes 设置为 off
此配置项表示是否合并相邻的“/”,例如,//test///a.txt,在配置为on时,会将其匹配为location /test/a.txt;如果配置为off,则不会匹配,URI将仍然是//test///a.txt。
危害
如果 Nginx 用作反向代理,并且被代理的应用程序容易受到本地文件包含内容的影响,则在请求中使用额外的斜杠可能会留出恶意利用空间。