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 сегменте. Их архитектура принципиально различается, и выбор зависит от сценария.| Критерий | trufflehog | gitleaks | detect-secrets |
|---|---|---|---|
| Подход к детекции | Regex + entropy + верификация через API провайдера | Regex-паттерны через .gitleaks.toml | Entropy + regex + плагины |
| Верификация найденных секретов | Да, автоматически проверяет «живость» ключа | Нет | Нет |
| Сканирование git-истории | Полная история всех веток | Полная история всех веток | Filesystem snapshot (без встроенной итерации по git-истории) |
| Управление false positives | Средства ограничены | allowlist в конфиге и inline-комментарии | Baseline-файл с интерактивным аудитом |
| Скорость на больших репо | Медленнее за счёт верификации | Высокая (написан на Go) | Средняя (Python) |
| Расширение паттернов | Custom detectors | .gitleaks.toml (regex) | Плагины + regex |
| Когда использовать | Внешний пентест: нужно быстро понять, какие ключи живые | Быстрый аудит истории, CI/CD gates | DevSecOps-процесс с длительным мониторингом |
| Когда НЕ использовать | Скрытый аудит: верификация создаёт логи у провайдера | Нужна автоматическая проверка «живости» | Требуется полное сканирование 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покажет доступные проекты.
Что засветится в логах: 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 может привлечь внимание.
Чеклист аудита секретов в облачных средах
Нумерованный список действий - можно передать заказчику как часть отчёта:- Клонировать все доступные репозитории организации (включая архивные) с полной историей (
git clone --mirror) - Запустить gitleaks с
--log-opts="--all"по каждому репозиторию, используя стандартные правила + кастомный.gitleaks.tomlпод специфику заказчика - Проверить GitHub/GitLab/Bitbucket Search API на наличие секретов в описаниях issue, PR, wiki
- Проверить Jira и Confluence: текстовый поиск по характерным паттернам (
AKIA,sk_live_,-----BEGIN,Bearer,ghp_,glpat-) - Проверить CI/CD пайплайны: логи сборок, артефакты, переменные окружения без маскирования
- Валидировать каждый найденный секрет через read-only endpoint провайдера
- Определить скоуп доступа для каждого живого секрета (права, ресурсы, данные)
- Проверить, сканируются ли репозитории встроенными средствами платформы (GitHub Secret Scanning, GitLab Secret Detection)
- Проверить наличие pre-commit хуков в
.pre-commit-config.yaml- их отсутствие означает, что секреты свободно попадают в историю - Документировать: секрет, источник, дата коммита, автор, статус (живой/отозванный), скоуп - для каждой находки
Основная проблема, которую вижу из проекта в проект, - разрыв между обнаружением и реагированием. Организации внедряют 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-истории, от обнаружения до эксплуатации.