Калькулятор с ключами: как чтение одного файла привело к компрометации публичного облака
Внешний сервис для расчета стоимости тарифов стал точкой входа в инфраструктуру крупной 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. Вспомогательные сервисы, тестовые панели, калькуляторы и внутренние интеграции должны проходить такой же строгий контроль, как и центральные компоненты платформы.
