Nginx

Tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Вивчайте та практикуйте Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

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

Missing root location

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

server {
root /etc/nginx;

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

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

Ця конфігурація породжує критичну проблему безпеки. Простий GET-запит, наприклад GET /nginx.conf, може викрити конфіденційну інформацію, віддавши файл конфігурації Nginx, що знаходиться за адресою /etc/nginx/nginx.conf. Установлення root у менш чутливий каталог, наприклад /etc, може знизити ризик, але все одно може дозволити ненавмисний доступ до інших критичних файлів, включно з іншими файлами конфігурації, access logs та навіть зашифрованими обліковими даними, що використовуються для HTTP basic authentication.

Alias LFI Misconfiguration

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

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

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

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

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

Детальніше: https://www.acunetix.com/vulnerabilities/web/path-traversal-via-misconfigured-nginx-alias/

Тести Accunetix:

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.

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

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

Дізнайтеся більше про ризики CRLF injection та response splitting за адресою https://blog.detectify.com/2019/06/14/http-response-splitting-exploitations-and-mitigations/.

Також ця техніка пояснено в цій доповіді з кількома вразливими прикладами та механізмами виявлення. Наприклад, щоб виявити це неправильне налаштування з боку blackbox, ви можете виконати такі запити:

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

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

Інші приклади виявлення:

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

Деякі з вразливих конфігурацій, представлених у тій доповіді, були:

  • Зверніть увагу, як $uri встановлюється без змін у фінальному 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;
}

Будь-яка змінна

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

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

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

Сканування цієї неправильнoї конфігурації в системах виявило кілька випадків, коли користувач міг виводити змінні 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 перевіряє існування кожного файлу в зазначеному порядку. Якщо файл існує, він буде негайно відданий. Якщо жодного зі вказаних файлів не існує, запит буде передано до резервного варіанту, який може бути іншим URI або конкретною сторінкою помилки.

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

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, ми вийдемо за межі кореневого каталогу (визначеного в конфігурації 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

Читання сирої відповіді backend

Nginx надає можливість через proxy_pass, яка дозволяє перехоплювати помилки та HTTP заголовки, що генеруються backend, з метою приховування внутрішніх повідомлень про помилки та заголовків. Це досягається тим, що Nginx повертає кастомні сторінки помилок у відповідь на помилки backend. Проте виникають проблеми, коли Nginx отримує некоректний HTTP-запит. Такий запит пересилається на backend у тому вигляді, в якому його отримали, і сиру відповідь backend потім відправляється клієнту без втручання Nginx.

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

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

Коли надходить валідний GET запит, Nginx обробляє його як звичайно, повертаючи стандартну помилкову відповідь без витоку секретних заголовків. Однак неправильний HTTP запит обходить цей механізм, внаслідок чого відбувається витік сирих відповідей бекенду, включно із секретними заголовками та повідомленнями про помилки.

merge_slashes set to off

За замовчуванням merge_slashes directive Nginx встановлено в on, що стискає кілька слешів у URL до одного. Ця функція, хоч і спрощує обробку URL, може ненавмисно приховувати вразливості в додатках за Nginx, особливо ті, що вразливі до local file inclusion (LFI) атак. Фахівці з безпеки Danny Robinson and Rotem Bar вказували на потенційні ризики, пов’язані з цією поведінкою за замовчуванням, особливо коли Nginx працює як reverse-proxy.

Щоб зменшити такі ризики, рекомендується turn the merge_slashes directive off для додатків, схильних до цих вразливостей. Це гарантує, що Nginx пересилає запити до додатку без зміни структури URL, тим самим не маскуючи жодних прихованих проблем безпеки.

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

У конфігурації Nginx, директива map часто використовується для authorization control. Поширена помилка — не вказати значення default, що може призвести до несанкціонованого доступу. Наприклад:

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 радить встановити значення за замовчуванням, щоб уникнути таких проблем.

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

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

resolver 8.8.8.8;

proxy_pass та internal директиви

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

proxy_set_header Upgrade & Connection

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

Caution

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

Example of vulnerable configuration to steal /flag from here:

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 вказує на конкретний шлях, наприклад http://backend:9999/socket.io, з’єднання буде встановлено з http://backend:9999, тож ви можете звертатися до будь-якого іншого шляху всередині цієї внутрішньої кінцевої точки. Отже, не має значення, чи вказано шлях у 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, які показали, що single hostile QUIC session може призвести до падіння worker-процесів або leak пам’яті, якщо експериментальний модуль ngx_http_v3_module скомпільовано і відкрито сокет listen ... quic. Вразливі збірки: 1.25.0–1.25.5 і 1.26.0; виправлення включено в 1.27.0/1.26.1. Розкриття пам’яті (CVE-2024-34161) додатково вимагає MTU більших за 4096 байт, щоб чутливі дані проявилися (деталі в nginx advisory 2024, наведено нижче).

Recon & exploitation hints

  • HTTP/3 is opt-in, so scan for Alt-Svc: h3=":443" responses or brute-force UDP/443 QUIC handshakes; once confirmed, fuzz the handshake and STREAM frames with custom quiche-client/nghttp3 payloads to trigger worker crashes and force log leakage.
  • Швидко визначте підтримку цілі за допомогою:
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)

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

План атаки

# 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

Якщо ціль вразлива, друге рукостискання завершується без пред’явлення клієнтського сертифіката, що дозволяє розкрити захищені локації.

Що перевіряти

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

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

The HTTP/2 Rapid Reset attack (CVE-2023-44487) still affects nginx when operators crank keepalive_requests or http2_max_concurrent_streams beyond the defaults: an attacker opens one HTTP/2 connection, floods it with thousands of streams, then immediately issues RST_STREAM frames so the concurrency ceiling is never reached while CPU keeps burning on tear-down logic. Nginx defaults (128 concurrent streams, 1000 keepalive requests) keep the blast radius small; pushing those limits “substantially higher” makes it trivial to starve workers even from a single client (see the F5 write-up referenced below).

Поради для виявлення

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

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

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

Detectify створила репозиторій на GitHub, де ви можете використати Docker, щоб розгорнути власний вразливий тестовий сервер Nginx з деякими з неправильних конфігурацій, обговорених у цій статті, і спробувати знайти їх самостійно!

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

Інструменти статичного аналізу

gixy-ng & Gixy-Next & GIXY

  • Gixy-Next (оновлений форк GIXY) — інструмент для аналізу конфігурацій Nginx, мета якого — знаходити вразливості, небезпечні директиви та ризикові неправильні конфігурації. Також знаходить конфігурації, що впливають на продуктивність, і виявляє пропущені можливості для підвищення безпеки, що дозволяє автоматизовано виявляти помилки.
  • gixy-ng (активно підтримуваний форк GIXY) — інструмент для аналізу конфігурацій Nginx, мета якого — знаходити вразливості, небезпечні директиви та ризикові неправильні конфігурації. Також знаходить конфігурації, що впливають на продуктивність, і виявляє пропущені можливості для підвищення безпеки, що дозволяє автоматизовано виявляти помилки.

Nginxpwner

Nginxpwner — простий інструмент для пошуку поширених неправильних конфігурацій Nginx та вразливостей.

Джерела

Tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Вивчайте та практикуйте Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

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