Nginx, универсальный веб-сервер, имеет ключевое значение для многочисленных интернет-инфраструктур, занимает доминирующую долю рынка с момента своего создания в 2004 году, получил широкое распространение на веб-сайтах и в контейнерах Docker. В этой статье рассматриваются тонкости Nginx, основное внимание уделяется директивам location и alias, которые играют центральную роль в том, как Nginx обрабатывает определенные URL-адреса. Мы также изучим потенциальные уязвимости, возникающие из-за неправильных конфигураций, и продемонстрируем, как они могут привести к эксплойтам безопасности, опираясь на исследования, представленные Orange Tsai на конференции BlackHat 2018.

Руководство дополнительно проиллюстрирует эти моменты посредством тщательного изучения популярных репозиториев с открытым исходным кодом, с использованием GitHub Code Search для выявления потенциальных уязвимостей конфигурации Nginx. Реальные тематические исследования с участием Bitwarden и Google HPC Toolkit подчеркнули значительный риск раскрытия данных, если эти уязвимости не будут устранены. Кроме того, мы представим NavGix, автоматизированный инструмент, предназначенный для обнаружения этих уязвимостей методом «черного ящика», предоставляющий исчерпывающую информацию о сложностях, уязвимостях и возможных неправильных конфигурациях Nginx.

Краткий обзор Nginx

Nginx — это универсальный веб-сервер, который также может функционировать как обратный прокси-сервер, балансировщик нагрузки, почтовый прокси-сервер и HTTP-кеш. Был создан и выпущен публично в 2004 году.

Согласно данным W3Tech, по состоянию на июнь 2022 года Nginx занимает самую высокую долю рынка среди веб-серверов: его используют 33,6% веб-сайтов в Интернете. Кроме того, согласно Docker, Nginx является самой распространенной технологией в их контейнерах. Эта значительная популярность делает уязвимости, связанные с Nginx, еще более важными и интригующими.

Директивы Location и Alias

Директива location — это директива блока, которая может содержать другие директивы и используется для определения того, как Nginx должен обрабатывать запросы для определенных URL-адресов.

Она часто используется в сочетании с директивой alias для сопоставления URL-адресов с определенными местоположениями файлов на сервере. Они могут быть определены в файле nginx.conf или в отдельном файле конфигурации.

Синтаксис директивы location:

location [modifier] /path/to/URL {
    # other directives
}

modifier опционален и может быть иметь следующие значения:

  • =: точное совпадение

  • ~: совпадение регулярного выражения чувствительное к регистру

  • ~*: совпадение регулярного выражения нечувствительное к регистру

  • ^~: совпадение префикса (прекратить дальнейший поиск, если это совпадает)

Пример использования директивы location вnginx.conf:

location /assets/ { # defines a location block for requests matching /assets

  alias /opt/production/assets/; # maps the request to the assets folder

}

Определяем неправильные настройки

На конференции BlackHat 2018 Orange Tsai представил свое исследование по взлому парсеров URL. Среди других впечатляющих результатов он продемонстрировал технику, обнаруженную в 2016 году в ходе испытания CTF от HCTF, созданного @iaklis.

Чтобы техника сработала нужны следующие условия:

  • Директиваlocation не должна иметь завершающую косую черту

  • Директива aliasдолжна быть указана внутри location и должна заканчиваться косой чертой.

Слева правильная конфигурация, справа — уязвимая
Слева правильная конфигурация, справа — уязвимая

Достигаем результата

В приведенном выше уязвимом примере Nginx будет сопоставлять любые URL-адреса, начинающиеся с /img, и возвращать все, что следует за этой косой чертой, с добавленным alias пути /var/images/.

Это означает, что и запрос /img/profile.jpg, и запрос /imgprofile.jpg вернут один и тот же файл. Поскольку директива alias заканчивается косой чертой, дополнительная косая черта не требуется после совпадающего местоположения.

Пример возврата одного и того же файла разными путями
Пример возврата одного и того же файла разными путями

Принимая во внимание, что мы можем получить доступ к целевой папке через любой URL-адрес запроса, начинающийся с /img, мы можем попытаться получить доступ к вездесущему каталогу .., тем самым достигнув родительского каталога для целевого, отправив запрос к /img.. для приведенного примера.

Если мы получаем ответ о редиректе от Nginx, мы можем предположить, что Nginx обнаружил каталог и пытается перенаправить нас в /img../, как это обычно происходит при доступе к каталогу.

И мы действительно перенаправлены!
И мы действительно перенаправлены!

Следовательно, любой файл или дочерний каталог в родительском каталоге целевой папки будут доступны для нас, и Nginx с готовностью их вернет. В нашем лабораторном примере это означает, что мы можем получить доступ ко всем файлам в папке /var/, учитывая, что целевая папка в конфигурации — /var/images/. Это позволяет нам использовать простые приемы, такие как GET, /img../log/nginx/access.log для загрузки логов, расположенных в /var/log/nginx/access.log.

Серьезность этой уязвимости может сильно колебаться в зависимости от проекта, от незначительной до критической. Степень его последствий в первую очередь определяется тем, содержит ли доступный каталог конфиденциальные данные, которые могут способствовать дополнительным атакам или привести к раскрытию частной информации.

Достигаем результата без косой черты alias

Похожая уязвимость, но без косой черты на хвосте
Похожая уязвимость, но без косой черты на хвосте

Сразу появляется вопрос, можно ли использовать эту уязвимость без косой черты в конце директивы alias. Ответ положительный, но это будет означать, что использование обходных последовательностей для выхода из каталога больше невозможно. Это связано с тем, что все, после совпадающего location добавляется к alias, а добавление последовательности .. к пути без завершающей косой черты, приведет только к несуществующему имени папки, например /var/images../

Однако мы все еще можем использовать это неправильное поведение для доступа к другим каталогам, имя которых начинается с имени целевого каталога. В результате мы не сможем получить доступ к /var/images/../log/, но все равно сможем получить доступ к каталогу /var/images_confidential, выполнив запрос GET к /img_confidential.

В этом случае Nginx добавляет _confidential к целевому пути /var/images, возвращая URL-адреса из комбинированного пути /var/images и _confidential, что приводит к /var/images_confidential.

Охотимся на open-source репозитории

В качестве отправной точки в поисках этой уязвимости мы решили изучить популярные репозитории GitHub, в которых обнаружится эта проблема. Выявление этой конкретной уязвимости в средах с доступом к исходному коду становится значительно более осуществимым, прежде всего благодаря двум основным факторам:

  1. Обнаружение: использование простых инструментов анализа кода, таких как поиск по регулярным выражениям, позволяет нам эффективно выявлять потенциально уязвимые файлы конфигурации Nginx в этих проектах.

  2. Эксплуатация: знание точного целевого каталога, которому присвоен alias, позволяет нам настроить инстанс локально, изучить каталоги с alias с помощью локальной коммандной строки и определить, к каким файлам можно получить доступ через уязвимость.

Поиск по коду GitHub

GitHub Code Search — это функция на GitHub, веб-платформе для контроля версий и совместной работы с использованием Git. Эта фича позволяет пользователям искать код во всех общедоступных репозиториях, размещенных на платформе, что делает ее особенно полезной для разработчиков, ищущих примеры, библиотеки или решения конкретных задач кодирования.

Кроме того, GitHub Code Search можно использовать для поиска фрагментов уязвимого кода в популярных проектах. Этого можно достичь различными методами, такими как простое совпадение строк, регулярные выражения, фильтры пути и многое другое. Например, для поиска уязвимости Nginx Alias Traversal можно использовать следующее регулярное выражение:

/location \/[_.a-zA-Z0-9-\/]*[^\/][\s]\{[\s\n]*alias \/[_.a-zA-Z0-9-\/]*\/;/

При изучении результатов поиска по этому запросу становится очевидно, что значительное количество репозиториев содержат эту конкретную уязвимость.

Из-за присущих регулярным выражениям ограничений они могут неидеально подходить для сопоставления синтаксиса кода. Например, это конкретное регулярное выражение не найдет уязвимыме файлы конфигурации, содержащие комментарии между директивами. Тем не менее, он служит отправной точкой для нашего анализа.

Кейс #1: Утечка сейфа, логов и сертификатов Bitwarden

Bitwarden — это менеджер паролей с открытым исходным кодом, который помогает пользователям безопасно хранить свои пароли, учетные данные и другую конфиденциальную информацию. Он предлагает такие функции, как генерация паролей, автозаполнение и синхронизация между устройствами. Bitwarden поддерживает различные платформы, включая Windows, macOS, Linux, Android, iOS и веб-браузеры через расширения. Пользователи могут получить доступ к своим данным через веб-хранилище, настольные приложения, мобильные приложения или расширения браузера.

Bitwarden также предлагает вариант с хостингом у себя для тех, кто хочет поддерживать свой собственный сервер. Этот вариант мы и изучим.

Если мы ищем способы поднятия собственного инстанса сервера Bitwarden, один из представленных способов — это метод Unified docker, для упрощения развертывания платформы.

100 тыщ загрузок!
100 тыщ загрузок!

Поскольку наше регулярное выражение совпало с репозиторием Bitwarden, мы углубились в код в поисках потенциально уязвимых конфигураций Nginx и обнаружили следующее в папке для унифицированной настройки Docker.

Если используется эта конфигурация, то все файлы в /etc/bitwarden/attachments/ будут доступны по URL-адресу /attachments, но, оглядываясь назад на детали эксплойта, это также означает, что любые файлы, присутствующие в /etc/bitwarden/, будут также доступны для загрузки.

Но не будем забегать вперед, сначала оценим масштаб проблемы. Для этого мы можем либо изучить код, либо запустить локальный экземпляр и посмотреть на каталог локально в консоли.

Заглянув в Dockerfile для этого образа, мы находим дополнительную информацию об этом каталоге и о том, какие файлы он может содержать:

[...]
ENV BW_DB_FILE="/etc/bitwarden/vault.db"
[...]

Похоже, что эта переменная среды задает место хранения БД хранилища, и мы видим, что vault.db находится в /etc/bitwarden.

Bitwarden сохраняет базу данных в этом месте только в случаях, если пользователь решит использовать SQLite в качестве источника базы данных.

Таким образом, если мы отправим неавторизованный запрос к http://<instance>/attachments../vault.db, мы скачаем всю Bitwarden SQLite3 базу.

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

  • /attachments../logs/api.log

  • /attachments../logs/admin.log

  • /attachments../logs/identity.log

  • /attachments../logs/notifications.log

И, конечно же, файл сертификата также был в этой папке. Чтобы получить к нему доступ, все, что вам нужно сделать, это отправить запрос на /attachments../identity.pfx

Ключи защиты данных также были доступны, но у них было непредсказуемое имени файла, поэтому их утечка была невозможна.

Эта уязвимость была раскрыта Bitwarden и с тех пор была устранена. Bitwarden назначил награду в размере 6000 USD, что является самой высокой наградой, которую они выдали за свою программу HackerOne.

Кейс #2: Google HPC Toolkit — утечка учетных данных Google Cloud

During our foray through GitHub, we chanced upon a software solution developed by Google, known as the Cloud HPC Toolkit. This was introduced in 2022, designed as a robust framework to facilitate the deployment of high-performance computing (HPC) environments on Google Cloud.

Во время нашего набега на GitHub мы случайно наткнулись на программное решение от Google, известное как Cloud HPC Toolkit. Представлено в 2022 году как надежная платформа облягчающая развертывание сред высокопроизводительных вычислений (HPC) в Google Cloud.

HPC Toolkit может похвастаться веб-приложением на основе Django, предоставляя пользователям возможность удобно управлять своими средами HPC через веб-интерфейс.

Изучив раздел конфигурации, найденный нашим регулярным выражением, мы обнаружили, что был действительно определен уязвимый путь . Этот путь имел alias../hpc-toolkit/community/front-end/website/static/, подразумевая, что отправка запроса к /static../ предоставит нам доступ к папке веб-сайта.

Интересно, что база данных SQLite также находится в этой папке, и к ней можно получить доступ через определенный URL-адрес:

curl http://<frontend URL>/static../db.sqlite3 -O

Более того, секретный ключ Django был доступен по следующему пути

curl http://35.204.135.69/static../.secret_key

Доступ к этой БД очень важен для приложения, поскольку основной функцией HPC Toolkit является оркестрирование крупномасштабными ресурсами Google Cloud. В случае компрометации, злоумышленник может получить контроль над учетными данными GCP жертвы, которые там хранятся.

sqlite> select * from ghpcfe_credential;
1|production key|{
"type": "service_account",
"project_id": "andunduaindadaww",
"private_key_id": "3acb9f[... redacted from report ...]7c69",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEv[... redacted from report ...] 5Kdkvg=\n-----END PRIVATE KEY-----\n",
"client_email": "adwaw[...].com",
"client_id": "105114036295455180401",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/adwaw1f13f1f13-tkfe-sa%40andunduaindadaww.iam.gserviceaccount.com" }|1 sqlite>

Команда Google VRP отметила нашу работу, наградив нас 500 USD за обнаружение этой уязвимости. Они посчитали, что воздействие на приложение было недостаточно серьезным для большего вознаграждения. Я думал обсудить с ними сумму вознаграждения, но в итоге отказался от этого. Ведь признание наших усилий само по себе было наградой, и этого для нас было более чем достаточно.

NavGix: Обнаружение уязвимостей методом черный ящик

Существует несколько способов обнаружить эту уязвимость без необходимости доступа к файлу конфигурации Nginx. Первоначально потенциальные alias location могут быть идентифицированы, извлекая ссылки из исходного кода HTML на главной странице веб-сайта. Впоследствии можно попытаться обойти каталог, используя методы, описанные в предыдущих разделах этого отчета.

При отсутствии извлекаемых ссылок можно применить брут форс, нацеленный на общие псевдонимы. Следующий список продемонстрировал многообещающие результаты на этапе тестирования:

	var dictionary = []string{
		"static",
		"js",
		"images",
		"img",
		"css",
		"assets",
		"media",
		"lib",
	}

Автоматизированный инструмент NavGix был создан для помощи в перечислении и тестировании каталогов с alias на наличие уязвимостей.

Пример использования navgix
Пример использования navgix

После идентификации каталога, доступного для обхода alias с помощью NavGix, можно использовать дополнительные инструменты для поиска других доступных папок или файлов в пройденном каталоге. Основная цель здесь найти файлы, которые дадут следующий результат, например, файлы конфигурации с секретами, логи или исходный код.

Вывод

Хотя Nginx является надежным и невероятно универсальным инструментом, который питает значительную часть Интернета, он также легко уязвим. Эти потенциальные ловушки часто являются результатом неправильной конфигурации, которая может непреднамеренно превратить эту надежную электростанцию в слабое звено. Подход Nginx к безопасности возлагает на разработчиков значительную ответственность за опасные конфигурации, что подчеркивает важность глубокого понимания и осторожного внедрения.

Наше путешествие по миру репозиториев с открытым исходным кодом и реальных примеров из жизни, таких как Bitwarden и Google HPC Toolkit, показывает, насколько значительными могут быть эти уязвимости. Это отрезвляющее напоминание о том, что даже у самых надежных систем может быть ахиллесова пята.

Комментарии (1)


  1. robertd Автор
    04.07.2023 12:48

    Из комментариев:
    gixy (nginx configuration checker) ловит это: https://github.com/yandex/gixy/blob/master/docs/en/plugins/a...

    P.s. Кажется тулза от яндекса

    reply