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

Відсутнє кореневе місцезнаходження

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

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

Alias LFI Misconfiguration

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

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

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

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

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

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

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

plaintext
location = /admin {
deny all;
}

location = /admin/ {
deny all;
}

{{#ref}} ../../pentesting-web/proxy-waf-protections-bypass.md {{#endref}}

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

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-ін'єкції та розділення відповідей на https://blog.detectify.com/2019/06/14/http-response-splitting-exploitations-and-mitigations/.

Ця техніка також пояснена в цій доповіді з деякими вразливими прикладами та механізмами виявлення. Наприклад, щоб виявити цю неправильну конфігурацію з точки зору чорного ящика, ви можете використовувати ці запити:

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

Якщо вразливий, перший поверне "X" як будь-який HTTP метод, а другий поверне помилку, оскільки 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;
}

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

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

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

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

Читання сирцевої відповіді з бекенду

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

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

python
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 встановлено на off

За замовчуванням директива Nginx merge_slashes встановлена на on, що стискає кілька прямолінійних слешів у URL в один слеш. Ця функція, хоча і спрощує обробку URL, може ненавмисно приховувати вразливості в програмах за Nginx, особливо ті, що схильні до атак локального включення файлів (LFI). Експерти з безпеки Денні Робінсон і Ротем Бар підкреслили потенційні ризики, пов'язані з цією поведінкою за замовчуванням, особливо коли Nginx діє як реверс-проксі.

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

Для отримання додаткової інформації перегляньте Денні Робінсон і Ротем Бар.

Maclicious Response Headers

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

  • X-Accel-Redirect: Вказує Nginx на внутрішнє перенаправлення запиту на вказане місце.
  • X-Accel-Buffering: Контролює, чи повинен Nginx буферизувати відповідь.
  • X-Accel-Charset: Встановлює набір символів для відповіді при використанні X-Accel-Redirect.
  • X-Accel-Expires: Встановлює час закінчення терміну дії для відповіді при використанні X-Accel-Redirect.
  • X-Accel-Limit-Rate: Обмежує швидкість передачі для відповідей при використанні X-Accel-Redirect.

Наприклад, заголовок X-Accel-Redirect викличе внутрішнє перенаправлення в nginx. Тож наявність конфігурації nginx з чимось на кшталт root / і відповіді від веб-сервера з X-Accel-Redirect: .env змусить nginx надіслати вміст /.env (Path Traversal).

Default Value in Map Directive

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

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

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

Уразливість до DNS-спуфінгу

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

yaml
resolver 8.8.8.8;

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

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

proxy_set_header Upgrade & Connection

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

caution

Ця вразливість дозволила б зловмиснику встановити пряме з'єднання з кінцевою точкою proxy_pass (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 вказує на конкретний шлях такий як http://backend:9999/socket.io, з'єднання буде встановлено з http://backend:9999, тому ви можете контактувати з будь-яким іншим шляхом всередині цього внутрішнього кінцевого пункту. Тож не має значення, чи вказано шлях в URL proxy_pass.

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

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

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

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

GIXY

Gixy - це інструмент для аналізу конфігурації Nginx. Основна мета Gixy - запобігти неправильним налаштуванням безпеки та автоматизувати виявлення вразливостей.

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