Перейти к содержимому

Lfr в облаке: как уязвимость калькулятора привела к компрометации инфраструктуры

Калькулятор с ключами: как чтение одного файла привело к компрометации публичного облака

Внешний сервис для расчета стоимости тарифов стал точкой входа в инфраструктуру крупной IT-компании. Через уязвимость класса LFR атакующим удалось прочитать локальные файлы сервера, найти секреты приложения и получить доступ к партнерскому API. Дальнейшая цепочка привела к административной панели публичного облака и учетной записи с максимальными полномочиями.

Разведка внешнего периметра

Во время внешнего пентеста среди доступных ресурсов обнаружили основной облачный сервис `cloud.company.com`. Он объединял API, проекты и организации, вычислительные мощности, биллинг и управление балансами.

Дополнительная разведка показала несколько связанных доменов. Особый интерес вызвали:

- `calc.company.com` - калькулятор стоимости облачных ресурсов;
- `cloud-admin.company.com` - предположительно административная часть платформы;
- `apipartner.company.com` - внутренний или партнерский API, о котором почти не было публичной информации.

Список URL собрали из открытых источников и архивов, после чего проверили JavaScript-файлы приложения. В клиентском коде обнаружили эндпоинт `/download_report`, предназначенный для скачивания отчетов.

При обращении к нему без параметров сервер возвращал сообщение о необходимости передать `file_name`. Такая логика сразу указывала на необходимость проверить обработку пользовательского пути: подобные функции нередко становятся причиной LFR или SSRF.

Как сработала LFR-уязвимость

Local File Read - это уязвимость, при которой приложение позволяет пользователю указать имя файла, а затем возвращает его содержимое. В отличие от удаленного выполнения кода, файл при этом не запускается: сервер лишь читает его и отправляет ответ.

Часто подобные ошибки связаны с обходом каталогов через последовательности `../`. Однако в данном случае обход не понадобился. Приложение принимало абсолютные пути. Поэтому вместо имени отчета ему передали путь к системному файлу.

Сервис не требовал авторизации и вернул содержимое файла `/etc/shadow`. Это также показало, что процесс работал с чрезмерными правами - от имени `root`. Даже если бы системный файл оказался недоступен, сама возможность читать произвольные файлы уже означала серьезную компрометацию.

После подтверждения LFR проверили несколько направлений:

1. исходный код приложения;
2. переменные окружения процесса;
3. аргументы запуска;
4. конфигурационные файлы;
5. секреты соседних сервисов;
6. ключи и учетные данные для интеграций.

Особенно ценны в таких ситуациях файлы из `/proc`, конфигурации подключения к базам данных, переменные окружения контейнеров и резервные копии настроек.

Поиск конфигурации и секретов

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

В конфигурации обнаружились два ключа:

- `key_calc` - учетные данные калькулятора;
- `key_billing` - ключ, связанный с биллинговой системой.

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

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

Авторизация в партнерском API

Публичная документация описывала только основной API облака. Для него использовался специальный заголовок `CLOUD-API-KEY`. О партнерском интерфейсе информации не было, поэтому формат авторизации пришлось определять экспериментально.

Ключи проверили в стандартном заголовке:

```http
Authorization: Bearer {key_billing}
```

Такой вариант оказался рабочим. Ключ `key_billing` позволил пройти аутентификацию в партнерском API. Адрес самого сервиса и маршруты к его методам также находились в конфигурации калькулятора.

На этом этапе у атакующих уже были:

- возможность читать файлы сервера;
- доступ к секретам приложения;
- действующий ключ биллинговой учетной записи;
- сведения о структуре внутренних API;
- потенциальный путь к административным операциям.

От партнерского API к облачной панели

Следующим шагом стало изучение методов партнерского API. В подобных интеграциях часто присутствуют функции синхронизации тарифов, управления балансами, формирования счетов и обмена данными между сервисами.

В ходе анализа удалось обнаружить механизм, связанный с административными операциями. Он позволил получить данные, необходимые для входа в `cloud-admin.company.com`. В цепочке также присутствовал пароль привилегированной учетной записи, который оказался недостаточно защищен и поддавался подбору.

Таким образом, одна уязвимость не дала мгновенного "полного контроля", но открыла последовательность переходов:

1. доступ к калькулятору;
2. чтение произвольных файлов;
3. извлечение конфигурации;
4. получение ключей партнерского API;
5. изучение внутренних методов;
6. компрометация привилегированной учетной записи;
7. вход в административную панель облака.

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

Почему атака стала возможной

Главной причиной оказался не один дефект, а сочетание нескольких проблем.

Отсутствие контроля путей

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

Безопасная реализация должна разрешать скачивание только заранее сформированных отчетов, а не любых объектов файловой системы.

Запуск от имени root

Даже при наличии LFR ущерб можно было существенно уменьшить, если бы процесс работал от имени отдельного непривилегированного пользователя. Запуск веб-приложения с правами `root` позволил читать системные и служебные файлы, которые в нормальной конфигурации должны быть недоступны.

Секреты в конфигурации

Ключи партнерского API хранились в открытом виде и обладали значительными полномочиями. Дополнительной проблемой стала возможность использовать один из них за пределами исходного сервиса.

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

Избыточные права сервисной учетной записи

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

Слабая защита административной учетной записи

Компрометация API-ключа не должна автоматически приводить к захвату панели управления. Дополнительные факторы аутентификации, ограничения по IP, короткоживущие токены и отдельные административные контуры способны разорвать такую цепочку.

Как защититься от подобных сценариев

Для предотвращения LFR следует:

- разрешать скачивание только файлов из заранее определенного каталога;
- использовать белый список допустимых имен;
- нормализовать путь до проверки;
- запрещать абсолютные пути и переходы через `..`;
- проверять, что итоговый путь остается внутри разрешенной директории;
- не передавать пользовательский ввод напрямую в файловые операции.

Также необходимо запускать приложения от отдельных системных пользователей без привилегий администратора. Доступ к `/proc`, конфигурациям и секретам должен дополнительно ограничиваться средствами операционной системы, контейнеров и политики доступа.

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

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

Итоги

В описанном сценарии точкой входа стал вспомогательный калькулятор тарифов, который на первый взгляд не относился к критическим компонентам облака. Однако простой дефект обработки пути позволил прочитать локальные файлы. Среди них нашлась конфигурация с действующими ключами партнерского API.

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

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

Прокрутить вверх