Схема kill-chain на плотной бумаге, снятая сверху. Пять узлов от поиска токена до утечки данных, соединённых стрелками, латунное пресс-папье и перьевая ручка.


AWS-ключ формата AKIA* в git-истории приватного репозитория - удалён из кода восемь месяцев назад, но aws sts get-caller-identity возвращает живой IAM-аккаунт с доступом к трём S3-бакетам. От находки в старом коммите до чтения продакшн-данных клиентов - двадцать минут. Этот сценарий повторяется из проекта в проект при аудите облачных сред: секреты удаляют из HEAD-ветки, но забывают про историю коммитов, форки и артефакты CI/CD. При этом, по оценке soteri.io, более половины утёкших на GitHub credentials - generic-секреты без структурированного формата, которые стандартные regex-правила не ловят. То есть даже если сканер стоит - он молчит.

Место утёкших секретов в цепочке атаки​

Поиск hardcoded secrets - не изолированная техника, а полноценный этап kill chain, который связывает разведку с получением доступа к облачной инфраструктуре. Разложим по MITRE ATT&CK.

Reconnaissance. Сканирование публичных репозиториев на предмет утёкших ключей - техника Code Repositories (T1593.003). Атакующий использует GitHub Search API, поисковые дорки и автоматические сканеры для обнаружения открытых секретов. Это первый шаг, и он бесплатный.

Credential Access. Найденные секреты классифицируются по типу: Credentials In Files (T1552.001) для API-ключей и паролей в конфигурационных файлах, Private Keys (T1552.004) для SSH- и TLS-ключей, Steal Application Access Token (T1528) для OAuth-токенов и service account credentials.

Initial Access и Privilege Escalation. Валидный cloud-токен - прямой путь к Cloud Accounts (T1078.004), который одновременно покрывает тактики initial access, persistence и privilege escalation. Один утёкший GCP service account JSON с ролью Owner - и проект ваш целиком.

Lateral Movement и Collection. Через скомпрометированные токены атакующий перемещается по инфраструктуре: Application Access Token (T1550.001) для lateral movement, Code Repositories (T1213.003) для сбора данных из приватных репозиториев, Data from Cloud Storage (T1530) для доступа к S3/GCS/Azure Blob.

Контекст применения: эта цепочка работает и на внешнем пентесте (сканирование публичных репозиториев), и на внутреннем (доступ к приватным репо организации через скомпрометированный аккаунт разработчика). На внешнем - начинаете с T1593.003. На внутреннем, когда уже есть доступ к GitLab/Bitbucket - сразу переходите к T1213.003 и T1552.001.

Где искать утёкшие токены и API-ключи в облачных средах​

Git-репозитории: история коммитов хранит всё​

Самый очевидный и самый богатый источник. GitHub secret scanning сканирует «всю историю Git на всех ветках репозитория» (согласно документации). Атакующий делает то же самое. Ключевые точки поиска:
  • История коммитов и удалённые ветки. Команда git log -p --all -S 'AKIA' ищет строку во всех коммитах, доступных через ветки и теги. Но --all не охватывает unreachable (dangling) коммиты - для них нужен git log --all --reflog -p -S 'AKIA' или git fsck --lost-found. Такие коммиты живут до сборки мусора (git gc), а её запускают далеко не все.
  • Файлы конфигурации. .env, config.yaml, appsettings.json, шаблоны Terraform и CloudFormation - стандартные места, где разработчики оставляют credentials во время локального тестирования. Даже позднее добавление .env в .gitignore не удаляет файл из уже существующих коммитов - вот этот нюанс многие упускают.
  • Pull request и issue. GitHub сканирует описания и комментарии в issues, PR, Discussions и даже wikis. Атакующий тоже: запрос org:target-company filename:.env или org:target-company "API_KEY" через GitHub Search API возвращает результаты за секунды.
  • Форки и gists. Публичный форк приватного репозитория наследует всю историю, включая секреты. Secret gists индексируются и доступны по прямой ссылке - считай, публичные.

CI/CD пайплайны и не-git платформы

Секреты утекают не только через код. Типичные advisory для Azure DevOps и GitHub Enterprise включают pipeline secret leakage, YAML-инъекции в self-hosted агентах и кражу OAuth-токенов приложений. В GCP - утечки signed URL и некорректная конфигурация IAM.
  • Bitbucket Pipelines и GitLab CI. Переменные окружения, переданные через аргументы командной строки, попадают в логи сборки. Артефакты билда могут содержать .env файлы, которые сохраняются как скачиваемые архивы. Видел это на проектах не раз - разработчик думает, что пайплайн «внутри», а артефакты скачивает кто угодно с доступом к проекту.
  • Jira и Confluence. Разработчики прикрепляют к тикетам конфигурационные файлы, скриншоты с токенами, дампы ошибок с заголовками Authorization. Поиск по Jira text ~ "AKIA" OR text ~ "Bearer" OR text ~ "sk_live" - первое, что стоит сделать при внутреннем аудите.
  • Логи и мониторинг. Разработчики добавляют отладочный вывод (console.log, логирование HTTP-заголовков) и забывают его удалить. Секреты попадают в Kibana, Grafana, облачные системы хранения логов - зачастую с доступом для десятков сотрудников. Классика: Authorization: Bearer sk_live_... прямо в Kibana, доступной всему отделу.

Сканирование секретов в репозиториях: trufflehog, gitleaks, detect-secrets​

Сравнение инструментов и архитектурные отличия​

Три инструмента доминируют в open-source сегменте. Их архитектура принципиально различается, и выбор зависит от сценария.

Критерийtrufflehoggitleaksdetect-secrets
Подход к детекцииRegex + entropy + верификация через API провайдераRegex-паттерны через .gitleaks.tomlEntropy + regex + плагины
Верификация найденных секретовДа, автоматически проверяет «живость» ключаНетНет
Сканирование git-историиПолная история всех ветокПолная история всех ветокFilesystem snapshot (без встроенной итерации по git-истории)
Управление false positivesСредства ограниченыallowlist в конфиге и inline-комментарииBaseline-файл с интерактивным аудитом
Скорость на больших репоМедленнее за счёт верификацииВысокая (написан на Go)Средняя (Python)
Расширение паттерновCustom detectors.gitleaks.toml (regex)Плагины + regex
Когда использоватьВнешний пентест: нужно быстро понять, какие ключи живыеБыстрый аудит истории, CI/CD gatesDevSecOps-процесс с длительным мониторингом
Когда НЕ использоватьСкрытый аудит: верификация создаёт логи у провайдераНужна автоматическая проверка «живости»Требуется полное сканирование git-истории

Gitleaks (актуальные релизы 8.x, см. github.com/gitleaks/gitleaks/releases; написан на Go, активно поддерживается) - мой выбор для быстрого сканирования истории репозитория. Ставится через brew install gitleaks на macOS или скачиванием бинарника для Linux. Ключевая команда: gitleaks detect --source . --log-opts="--all" --verbose - сканирует все коммиты всех веток. Быстрый, нежадный до ресурсов, конфиг понятный.

detect-secrets (актуальные релизы 1.x, см. github.com/Yelp/detect-secrets/releases; от Yelp, Python) - другой подход: инструмент создаёт baseline-файл через detect-secrets scan > .secrets.baseline, затем через detect-secrets audit .secrets.baseline вы интерактивно размечаете каждую находку как true/false positive. Дальше алертит только на новые. Подходит для длительного мониторинга, но не имеет встроенной интеграции для итерации по git-истории (в отличие от gitleaks --log-opts); ориентирован на сканирование filesystem snapshot и работу через pre-commit.

trufflehog - единственный из тройки, кто умеет верифицировать найденные секреты, обращаясь к API провайдера (AWS, GitHub, Slack и т.д.). На пентесте это спасает часы ручной проверки, но создаёт логи на стороне провайдера. Если заказчик просит скрытый аудит - трафик верификации выдаст вашу активность. Имейте в виду.

Ограничения инструментов: что пропустят все три​

Ни один из инструментов - не серебряная пуля. Конкретные сценарии, где стандартный скан провалится:
  • Base64-encoded секреты. Строка QUtJQTEyMzQ1Njc4OUFCQ0RFRkc= - это AKIA1234567890ABCDEFG в base64. Большинство regex-паттернов не декодируют base64 перед проверкой. Разработчик положил ключ в .env.example в закодированном виде - сканер промолчит.
  • Кастомные форматы токенов. По данным soteri.io, более половины утёкших credentials на GitHub - generic-секреты без характерного префикса (не AKIA*, не sk_live_). Entropy-фильтры помогают, но порождают ложные срабатывания на хешах, UUID и сжатых данных. Типичные пороги: для base64-строк entropy > 4.5, для hex - > 3.0, для алфавитно-цифровых - > 3.7. Подбирать под проект приходится вручную.
  • Секреты в бинарных файлах. Скомпилированные артефакты, Docker-образы, архивы - за пределами текстового сканирования. Нужны отдельные инструменты для анализа контейнеров (trivy, grype).
  • Нестандартные платформы. Jira-вложения, Confluence-страницы, Slack-каналы - ни gitleaks, ни detect-secrets их не покрывают. Тут ручной поиск или интеграция через API платформ. Автоматизации пока нет нормальной.

Поиск API-ключей в репозиториях: пошаговый workflow пентестера​

Требования к окружению​

  • ОС: Linux (Kali, Ubuntu 22.04+) или macOS. Windows - через WSL2
  • RAM: 4 ГБ минимум, 8 ГБ рекомендуется для сканирования крупных репозиториев (100k+ коммитов)
  • Инструменты: git 2.30+, gitleaks 8.x (Go binary), Python 3.9+ для detect-secrets, jq для парсинга JSON-отчётов
  • Сетевые требования: интернет для клонирования репозиториев и верификации ключей. Для скрытого аудита - верификацию выполнять через VPN или прокси
  • Доступ: на внешнем пентесте - публичные репозитории, GitHub Search API (Search API требует аутентификации; rate limit - 30 req/min для authenticated requests; общий REST API: 60 req/hour без токена, 5000 req/hour с токеном). На внутреннем - доступ к GitLab/Bitbucket/Jira организации

Сканирование и кастомные паттерны​

📚 Часть контента скрыта. Этот материал доступен участникам сообщества с рангом One Level или выше
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме

Валидация найденных credentials​

Найденный секрет бесполезен без валидации - это может быть тестовый ключ, давно отозванный токен или placeholder из документации. Валидация зависит от типа:
  • AWS Access Key (AKIA*). Выполняете AWS_ACCESS_KEY_ID=AKIA... AWS_SECRET_ACCESS_KEY=... aws sts get-caller-identity - если ответ содержит ARN и Account ID, ключ живой. Далее aws iam list-attached-user-policies покажет права аккаунта. Это создаёт запись в CloudTrail - учитывайте при скрытом аудите.
  • GitHub Personal Access Token (ghp_*). Запрос curl -H "Authorization: token ghp_..." https://api.github.com/user - если 200, токен валиден. Проверяйте scopes через заголовок X-OAuth-Scopes в ответе. Иногда попадаются токены с repo и admin:org - джекпот.
  • Slack Webhook URL. Отправляете POST с тестовым payload на URL вида https://hooks.slack.com/services/T.../B.../... - если 200, webhook активен и позволяет отправлять сообщения в канал.
  • GCP Service Account JSON. Аутентифицируетесь через gcloud auth activate-service-account --key-file=key.json, затем gcloud projects list покажет доступные проекты.
Каждую валидацию документируйте: тип секрета, источник (файл, коммит, платформа), результат проверки, скоуп доступа. Это ляжет в отчёт и определит severity находки.

Что засветится в логах: OPSEC при сканировании секретов​

При cloud-пентесте важно понимать, какие следы оставляет ваш аудит. Без этого понимания можно триггернуть SOC на первой же валидации.
  • GitHub Advanced Security генерирует алерты при обнаружении секретов в push - если вы тестируете push protection, администраторы получат email-уведомление. Push Protection совместима с десятками типов токенов (согласно документации GitHub), и администраторы видят события обхода защиты.
  • GitLab Secret Detection работает в двух режимах: push protection (блокирует коммит до попадания в репозиторий) и pipeline-сканирование. Оба режима логируют результаты. GitLab Duo на Ultimate-тарифе дополнительно снижает false positives через AI-анализ, присваивая confidence score каждой находке.
  • CloudTrail / Cloud Audit Logs. Использование AWS-ключа создаёт запись в CloudTrail (userIdentity содержит accessKeyId), что позволяет SOC обнаружить аномалию по source IP. В GCP - каждый вызов API с service account записывается в Cloud Audit Logs. Если SOC настроен на алерт «первое использование credentials с нового IP» - ваша верификация триггернёт инцидент. На одном проекте именно так и случилось: проверили один ключ, через 15 минут прилетел звонок от безопасников заказчика.
  • GitHub API rate limiting. GitHub Search API требует аутентификации; rate limit для authenticated requests - 30 запросов в минуту. Резкий всплеск запросов от одного IP может привлечь внимание.
Рекомендации: на внешнем пентесте верификацию выполнять через VPN, для каждого провайдера использовать минимально инвазивный read-only endpoint. На внутреннем - согласовать с заказчиком, какие действия допустимы и какие SOC-алерты можно игнорировать.

Чеклист аудита секретов в облачных средах​

Нумерованный список действий - можно передать заказчику как часть отчёта:
  1. Клонировать все доступные репозитории организации (включая архивные) с полной историей (git clone --mirror)
  2. Запустить gitleaks с --log-opts="--all" по каждому репозиторию, используя стандартные правила + кастомный .gitleaks.toml под специфику заказчика
  3. Проверить GitHub/GitLab/Bitbucket Search API на наличие секретов в описаниях issue, PR, wiki
  4. Проверить Jira и Confluence: текстовый поиск по характерным паттернам (AKIA, sk_live_, -----BEGIN, Bearer, ghp_, glpat-)
  5. Проверить CI/CD пайплайны: логи сборок, артефакты, переменные окружения без маскирования
  6. Валидировать каждый найденный секрет через read-only endpoint провайдера
  7. Определить скоуп доступа для каждого живого секрета (права, ресурсы, данные)
  8. Проверить, сканируются ли репозитории встроенными средствами платформы (GitHub Secret Scanning, GitLab Secret Detection)
  9. Проверить наличие pre-commit хуков в .pre-commit-config.yaml - их отсутствие означает, что секреты свободно попадают в историю
  10. Документировать: секрет, источник, дата коммита, автор, статус (живой/отозванный), скоуп - для каждой находки
Публичные инциденты крупных облачных провайдеров показывают: даже крупнейшие компании не застрахованы. Масштаб последствий определяется не наличием сканера, а скоростью ротации обнаруженного секрета.

Основная проблема, которую вижу из проекта в проект, - разрыв между обнаружением и реагированием. Организации внедряют gitleaks в CI/CD, получают отчёт с десятками находок в git-истории и... ничего не делают. Секрет формально «удалён из кода» - но не отозван у провайдера, история не очищена через [URL='https://github.com/newren/git-filter-repo']git filter-repo[/URL] или BFG Repo-Cleaner, а форки с полной копией истории продолжают жить своей жизнью.

Инструменты сканирования секретов в репозиториях сегодня достаточно зрелые: regex + entropy + верификация покрывают абсолютное большинство структурированных форматов. Слабое звено - не технология обнаружения, а процесс ротации. В ближайшие пару лет объём утёкших credentials будет расти пропорционально росту микросервисной архитектуры и количеству service account-ов. Значительная часть облачных инцидентов будет начинаться с секрета, который сканер нашёл, а ответственный не отозвал. Единственный рабочий подход - автоматическая ротация (AWS Secrets Manager, HashiCorp Vault) в связке с pre-commit хуками и CI/CD-сканированием. Без ротации всё остальное - отчёты ради отчётов.

Если хотите отработать эту цепочку руками - на HackerLab есть лабы с утёкшими credentials в git-истории, от обнаружения до эксплуатации.
 
Добрый день, отличная статья !
Работал по этой же теме, используя opensource утилиты и своей оркестрацией для полного охвата, с последующей валидацией ключей но остался вопрос, как можно дальше реализовать проект более масштабно ?
 
Мы в соцсетях:

Взломай свой первый сервер и прокачай скилл — Начни игру на HackerLab

Похожие темы

🚀 Первый раз на Codeby?
Гайд для новичков: что делать в первые 15 минут, ключевые разделы, правила
Начать здесь →
🔴 Свежие CVE, 0-day и инциденты
То, о чём ChatGPT ещё не знает — обсуждаем в реальном времени
Threat Intel →
💼 Вакансии и заказы в ИБ
Pentest, SOC, DevSecOps, bug bounty — работа и проекты от проверенных компаний
Карьера в ИБ →

HackerLab