Nginx is currently the most used Web
server in the world. Here are some common Nginx configurations that will make your website vulnerable to attacks.
The following most common misconfigurations are often exploited by attackers
- Missing root directory
- Unsafe variable usage
- Original backend response read
- merge_slashes is set to off
Missing root location
server {
root /etc/nginx;
location /hello.txt {
try_files $uri $uri/ =404;
proxy_pass http://127.0.0.1:8080/;
}
}
The root folder of Nginx specified in the root directive. In the above example, the root folder /etc/nginx
means that we can access the files in that folder. The above configuration does not have a location of / (location / {...})
, only /hello.txt
. Therefore, the root
directive will be set globally, which means that the request /
will take you to the local path /etc/nginx
A simple request GET /nginx.conf
will show that it is stored in /etc/nginx/nginx.conf
. If the root is set to /etc
, then a GET
request /nginx/nginx.conf
will show Configuration file. In some cases, other configuration files, access logs, and even encrypted credentials for HTTP basic authentication can be accessed
The most common root directory:
Off-By-Slash
server {
listen 80 default_server;
server_name _;
location /static {
alias /usr/share/nginx/static/;
}
location /api {
proxy_pass http://apiserver/v1/;
}
}
For the off-by-slash misconfiguration, due to the lack of slashes, it may move up one step on the path. The trailing slashes missing in the location
instruction, alias
can read the source code of the web application. What is less known is that this also applies to other commands such as proxy_pass
Break down how and why it happened:
location /api {
proxy_pass http://apiserver /v1/;
}
Use the Nginx server running the following configuration to access server
at. It may be assumed that you can only access the path under http://apiserver/v1/
http://server /api /user -> http://apiserver /v1/ /user
When http://server/api/user
is requested, Nginx will first normalize the URL. Then it will check if the prefix /api
matches the URL, in which case it will do so. Then remove the prefix from the URL so that /user
retains the path. Then add this path to the proxy_pass
URL to generate the final URL http://apiserver/v1//user
. Note that there is a double slash in the URL because the location directive does not end with a slash, and the proxy_pass
URL path ends with a slash. Most web servers will standardize http://apiserver/v1//user
to http://apiserver/v1/user
, which means that even if there is such a misconfiguration, everything will work as expected and may Will be ignored
This misconfiguration can be exploited by request, http://server/api../
This will cause Nginx request http://apiserver/v1/../
to be normalized to http://apiserver/
The possible impact of this depends on what can be achieved when using this misconfiguration. For example, it may cause the Apache server status to be exposed along with the URL http://server/api../server-status
, or it may make accessible paths that are not intended for public access
One sign of this misconfiguration of the Nginx server is that when the slash in the URL is removed, the server still returns the same response. For example, if two http://server/api/user
and http://server/apiuser
return the same response, the server may be vulnerable. This will result in the following request being sent:
http://server/api/user -> http://apiserver/v1//user
http://server/apiuser -> http://apiserver/v1/user
Unsafe variable use
Some frameworks, scripts, and Nginx configurations insecurely use variables stored by Nginx. This may cause problems such as XSS, bypassing HttpOnly protection, information leakage, etc., and in some cases even RCE
SCRIPT_NAME
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass 127.0.0.1:9000;
}
The main problem is that Nginx will send any URL to the PHP interpreter, even if the file does not exist.
If the PHP script tries to define a base URL based on, XSS SCRIPT_NAME
will happen
<?php
if(basename($_SERVER['SCRIPT_NAME']) ==
basename($_SERVER['SCRIPT_FILENAME']))
echo dirname($_SERVER['SCRIPT_NAME']);
?>
GET /index.php/<script>alert(1)</script>/index.php
SCRIPT_NAME = /index.php/<script>alert(1)</script>/index.php
Using $uri will cause CRLF injection:
Another misconfiguration related to Nginx variables is to use $uri or $document_uri instead of $request_uri. $uri and $document_uri contain the normalized URI, and normalizationNginx contains the URL that decodes the URI. Volema found that $uri is commonly used when creating redirects in Nginx configuration, which can lead to CRLF injection
An example of a vulnerable Nginx configuration is as follows:
location / {
return 302 https://example.com$uri;
}
The newline characters for HTTP requests are \r (carriage return) and \n (line feed). URL encoding newline characters will produce the following character representation %0d%0a. When these characters are included in the request, such as http://localhost/%0d%0aDetectify:%20clrf misconfigured server, the server will respond with a new header named, Detectify because the $uri variable contains the URL decoded Newline character
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
Any variable
In some cases, user-supplied data can be treated as Nginx variables. It is not clear why this happens, but as shown in H1 report, this situation is not uncommon or easy to test. If we search for the error message, we can see that it is found in SSI Filter Module , Which shows that this is caused by SSI
One way to test this is to set the quote header value:
curl -H 'Referer: bar' http://localhost/foo$http_referer | grep'foobar'
We scanned this misconfiguration and found several instances where users can print Nginx variable values. The number of vulnerable instances discovered has dropped, which may indicate that it has been patched
Original backend response read
Using Nginx's proxy_pass, it is possible to intercept errors and HTTP headers created by the backend. This is useful if you want to hide internal error messages and headers so they are handled by Nginx. If the backend answers one, Nginx will automatically provide a custom error page. But what if Nginx doesn't understand that this is an HTTP response?
If the client sends an invalid HTTP request to Nginx, the request will be forwarded to the backend as is, and the backend will respond with its original content. Then, Nginx will not be able to understand the invalid HTTP response and forward it to the client. Imagine a uWSGI application like this:
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!"]
And use the following instructions in Nginx:
http {
error_page 500 /html/error.html;
proxy_intercept_errors on;
proxy_hide_header Secret-Header;
}
If the response status of the backend is greater than 300, proxy_intercept_errors will provide a custom response. In the uWSGI application above, we will send a 500 Error response that will be intercepted by Nginx
proxy_hide_header is almost self-explanatory; it will hide any specified HTTP headers from the client
If we send a normal GET request, Nginx will return:
HTTP/1.1 500 Internal Server Error
Server: nginx/1.10.3
Content-Type: text/html
Content-Length: 34
Connection: close
But if we send an invalid HTTP request, such as:
GET /? XTTP/1.1
Host: 127.0.0.1
Connection: close
We will get the following response:
XTTP/1.1 500 Error
Content-Type: text/html
Secret-Header: secret-info
Secret info, should not be visible!
merge_slashes is set to close
The merge_slashes default, the slashes command is a mechanism to compress two or more slashes into one, so setting it to "on" /// will become /. If Nginx is used as a reverse proxy and the application being proxied is susceptible to local file inclusion, the use of extra slashes in the request may leave room to exploit it.
Post comment 取消回复