Перейти к содержанию

On this page Расследование цепочек поставок, восстановление доказательств и криминалистический анализ для репозиториев GitHub. Включает восстановление удалённых коммитов, обнаружение force-push, извлечение индикаторов компрометации (IOC), сбор доказательств из нескольких источников, формирование/проверку гипотез и структурированную подготовку криминалистических отчётов. Основано на системе OSS Forensics из RAPTOR (более 1800 строк).

Метаданные навыка

| | |---|--- | |Источник| Опционально — установка: hermes skills install official/security/oss-forensics | |Путь| optional-skills/security/oss-forensics |

Справочник: полный SKILL.md

info Ниже приведено полное определение навыка, которое Hermes загружает при его активации. Это те инструкции, которые видит агент, когда навык активен.

Навык криминалистической безопасности OSS

Семифазный многогаентный фреймворк для расследования атак на цепочки поставок открытого ПО. Адаптирован из криминалистической системы RAPTOR. Охватывает GitHub Archive, Wayback Machine, GitHub API, локальный анализ git, извлечение IOC, формирование и проверку гипотез на основе доказательств, а также создание итогового криминалистического отчёта.


⚠️ Защитные ограничения против галлюцинаций

Прочитайте их перед каждым шагом расследования. Их нарушение делает отчёт недействительным. 1. Правило «Сначала доказательства» : Каждое утверждение в любом отчёте, гипотезе или резюме ОБЯЗАТЕЛЬНО должно ссылаться хотя бы на один идентификатор доказательства (EV-XXXX). Утверждения без ссылок запрещены. 2. НЕ ВЫХОДИ ЗА РАМКИ : Каждый суб-агент (исследователь) работает только с одним источником данных. Не смешивайте источники. Исследователь GH Archive не обращается к GitHub API, и наоборот. Границы ролей жёсткие. 3. Разделение фактов и гипотез : Помечайте все непроверенные выводы как [HYPOTHESIS]. Только утверждения, проверенные по оригинальным источникам, могут быть представлены как факты. 4. Запрет на фабрикацию доказательств : Валидатор гипотез ОБЯЗАН механически проверить, что каждый упомянутый идентификатор доказательства действительно существует в хранилище, прежде чем принимать гипотезу. 5. Опровержение только с доказательствами : Гипотезу нельзя отклонить без конкретного аргумента, подкреплённого доказательствами. «Доказательств не найдено» недостаточно для опровержения — это лишь делает гипотезу неубедительной. 6. Двойная проверка SHA/URL : Любой SHA коммита, URL или внешний идентификатор, указанный как доказательство, должен быть независимо подтверждён как минимум из двух источников, прежде чем быть помеченным как проверенный. 7. Правило подозрительного кода : Никогда не запускайте код из исследуемого репозитория локально. Анализируйте только статически или используйте execute_code в изолированной среде. 8. Редактирование секретов : Любые ключи API, токены или учётные данные, обнаруженные в ходе расследования, должны быть отредактированы в итоговом отчёте. Логируйте их только внутренне.


Примеры сценариев

  • Сценарий A: Путаница зависимостей : Вредоносный пакет internal-lib-v2 загружен в NPM с версией выше, чем внутренняя. Исследователь должен отследить, когда этот пакет был впервые замечен и были ли в целевом репозитории PushEvents, обновляющие package.json до этой версии.
  • Сценарий B: Перехват мейнтейнера : Аккаунт давнего контрибьютора используется для пуша бэкдорного .github/workflows/build.yml. Исследователь ищет PushEvents от этого пользователя после длительного периода бездействия или с нового IP/местоположения (если определимо через BigQuery).
  • Сценарий C: Сокрытие через force-push : Разработчик случайно коммитит секрет, затем делает force-push, чтобы «исправить» ситуацию. Исследователь использует git fsck и GH Archive для восстановления оригинального SHA коммита и проверки, что было раскрыто.

Соглашение о путях : В этом навыке SKILL_DIR ссылается на корень директории установки навыка (папка, содержащая этот SKILL.md). При загрузке навыка SKILL_DIR разрешается в фактический путь — например, ~/.hermes/skills/security/oss-forensics/ или эквивалент optional-skills/. Все ссылки на скрипты и шаблоны относительны него.

Фаза 0: Инициализация

  1. Создайте рабочую директорию расследования: [code] mkdir investigation_$(echo "REPO_NAME" | tr '/' '')
    cd investigation
    $(echo "REPO_NAME" | tr '/' '_')

[/code] 2. Инициализируйте хранилище доказательств: [code] python3 SKILL_DIR/scripts/evidence-store.py --store evidence.json list

[/code] 3. Скопируйте шаблон криминалистического отчёта: [code] cp SKILL_DIR/templates/forensic-report.md ./investigation-report.md

[/code] 4. Создайте файл iocs.md для отслеживания индикаторов компрометации по мере их обнаружения. 5. Запишите время начала расследования, целевой репозиторий и заявленную цель расследования.


Фаза 1: Разбор запроса и извлечение IOC

Цель : Извлечь все структурированные цели расследования из запроса пользователя. Действия : * Разобрать запрос пользователя и извлечь: * Целевой репозиторий (owner/repo) * Целевых акторов (имена на GitHub, адреса email) * Временное окно интереса (диапазоны дат коммитов, временные метки PR) * Предоставленные индикаторы компрометации: SHA коммитов, пути файлов, имена пакетов, IP-адреса, домены, ключи API/токены, вредоносные URL * Любые связанные отчёты безопасности или посты в блогах от вендоров

Инструменты : Только логика или execute_code для извлечения с помощью регулярных выражений из больших текстовых блоков. Результат : Заполнить iocs.md извлечёнными IOC. Каждый IOC должен содержать: * Тип (из: COMMIT_SHA, FILE_PATH, API_KEY, SECRET, IP_ADDRESS, DOMAIN, PACKAGE_NAME, ACTOR_USERNAME, MALICIOUS_URL, OTHER) * Значение * Источник (предоставлено пользователем, выведено)

Справочник : См. evidence-types.md для таксономии IOC.


Фаза 2: Параллельный сбор доказательств

Запустить до 5 суб-агентов-исследователей с помощью delegate_task (пакетный режим, макс. 3 одновременно). Каждый исследователь работает с одним источником данных и не должен смешивать источники.

Заметка для оркестратора : Передайте список IOC из Фазы 1 и временное окно расследования в поле context каждой делегированной задачи.


Исследователь 1: Локальный Git

ГРАНИЦА РОЛИ : Вы работаете ТОЛЬКО с ЛОКАЛЬНЫМ GIT-РЕПОЗИТОРИЕМ. Не вызывайте никаких внешних API. Действия : [code] # Клонировать репозиторий
git clone https://github.com/OWNER/REPO.git target_repo && cd target_repo

# Полный лог коммитов со статистикой  
git log --all --full-history --stat --format="%H|%ae|%an|%ai|%s" > ../git_log.txt

# Обнаружить следы force-push (осиротевшие/висячие коммиты)  
git fsck --lost-found --unreachable 2>&1 | grep commit > ../dangling_commits.txt

# Проверить reflog на переписанную историю  
git reflog --all > ../reflog.txt

# Список ВСЕХ веток, включая удалённые удалённые ссылки  
git branch -a -v > ../branches.txt

# Найти подозрительные добавления больших бинарных файлов  
git log --all --diff-filter=A --name-only --format="%H %ai" -- "*.so" "*.dll" "*.exe" "*.bin" > ../binary_additions.txt

# Проверить аномалии GPG-подписей  
git log --show-signature --format="%H %ai %aN" > ../signature_check.txt 2>&1

[/code] Доказательства для сбора (добавить через python3 SKILL_DIR/scripts/evidence-store.py add): * Каждый SHA висячего коммита → тип: git * Признаки force-push (reflog показывающий перезапись истории) → тип: git * Неподписанные коммиты от проверенных контрибьюторов → тип: git * Подозрительные добавления бинарных файлов → тип: git

Справочник : См. recovery-techniques.md для доступа к коммитам, удалённым через force-push.


Исследователь 2: GitHub API

ГРАНИЦА РОЛИ : Вы работаете ТОЛЬКО с GitHub REST API. Не выполняйте git-команды локально. Действия : [code] # Коммиты (с пагинацией)
curl -s "https://api.github.com/repos/OWNER/REPO/commits?per_page=100" > api_commits.json

# Pull Request'ы, включая закрытые/удалённые  
curl -s "https://api.github.com/repos/OWNER/REPO/pulls?state=all&per_page=100" > api_prs.json

# Issues  
curl -s "https://api.github.com/repos/OWNER/REPO/issues?state=all&per_page=100" > api_issues.json

# Контрибьюторы и изменения коллабораторов  
curl -s "https://api.github.com/repos/OWNER/REPO/contributors" > api_contributors.json

# События репозитория (последние 300)  
curl -s "https://api.github.com/repos/OWNER/REPO/events?per_page=100" > api_events.json

# Проверить детали конкретного подозрительного SHA коммита  
curl -s "https://api.github.com/repos/OWNER/REPO/git/commits/SHA" > commit_detail.json

# Релизы  
curl -s "https://api.github.com/repos/OWNER/REPO/releases?per_page=100" > api_releases.json

# Проверить, существует ли конкретный коммит (force-push коммиты могут выдавать 404 на commits/, но успешно на git/commits/)  
curl -s "https://api.github.com/repos/OWNER/REPO/commits/SHA" | jq .sha

[/code] Цели для перекрёстной проверки (помечать расхождения как доказательства): * PR есть в архиве, но отсутствует в API → доказательство удаления * Контрибьютор есть в событиях архива, но отсутствует в списке контрибьюторов → доказательство отзыва прав * Коммит есть в PushEvents архива, но отсутствует в списке коммитов API → доказательство force-push/удаления

Справочник : См. evidence-types.md для типов событий GH.


Исследователь 3: Wayback Machine

ГРАНИЦА РОЛИ : Вы работаете ТОЛЬКО с CDX API Wayback Machine. Не используйте GitHub API. Цель : Восстановить удалённые страницы GitHub (README, issues, PR, релизы, вики-страницы). Действия : [code] # Поиск архивных снимков главной страницы репозитория
curl -s "https://web.archive.org/cdx/search/cdx?url=github.com/OWNER/REPO&output=json&limit=100&from=YYYYMMDD&to=YYYYMMDD" > wayback_main.json

# Поиск конкретного удалённого issue  
curl -s "https://web.archive.org/cdx/search/cdx?url=github.com/OWNER/REPO/issues/NUM&output=json&limit=50" > wayback_issue_NUM.json

# Поиск конкретного удалённого PR  
curl -s "https://web.archive.org/cdx/search/cdx?url=github.com/OWNER/REPO/pull/NUM&output=json&limit=50" > wayback_pr_NUM.json

# Получение лучшего снимка страницы  
# Используйте URL Wayback Machine: https://web.archive.org/web/TIMESTAMP/ORIGINAL_URL  
# Пример: https://web.archive.org/web/20240101000000*/github.com/OWNER/REPO

# Расширенный: поиск удалённых релизов/тегов  
curl -s "https://web.archive.org/cdx/search/cdx?url=github.com/OWNER/REPO/releases/tag/*&output=json" > wayback_tags.json

# Расширенный: поиск исторических изменений вики  
curl -s "https://web.archive.org/cdx/search/cdx?url=github.com/OWNER/REPO/wiki/*&output=json" > wayback_wiki.json

[/code] Доказательства для сбора : * Архивные снимки удалённых issues/PR с их содержимым * Исторические версии README, показывающие изменения * Доказательства содержимого, присутствующего в архиве, но отсутствующего в текущем состоянии GitHub

Справочник : См. github-archive-guide.md для параметров CDX API.


Исследователь 4: GH Archive / BigQuery

ГРАНИЦА РОЛИ : Вы работаете ТОЛЬКО с GITHUB ARCHIVE через BIGQUERY. Это защищённая от подделки запись всех публичных событий GitHub.

Предварительные требования : Требуются учётные данные Google Cloud с доступом к BigQuery (gcloud auth application-default login). Если они недоступны, пропустите этого исследователя и отметьте это в отчёте. Правила оптимизации затрат (ОБЯЗАТЕЛЬНЫ): 1. ВСЕГДА выполняйте --dry_run перед каждым запросом для оценки стоимости. 2. Используйте _TABLE_SUFFIX для фильтрации по диапазону дат и минимизации сканируемых данных. 3. SELECT только те колонки, которые нужны. 4. Добавляйте LIMIT, если не выполняете агрегацию.

[code] # Шаблон: безопасный BigQuery-запрос для PushEvents в OWNER/REPO
bq query --use_legacy_sql=false --dry_run "
SELECT created_at, actor.login, payload.commits, payload.before, payload.head,
payload.size, payload.distinct_size
FROM `githubarchive.month.*`
WHERE _TABLE_SUFFIX BETWEEN 'YYYYMM' AND 'YYYYMM'
AND type = 'PushEvent'
AND repo.name = 'OWNER/REPO'
LIMIT 1000
"
# Если стоимость приемлема, запустить повторно без --dry_run

# Обнаружение force-push: PushEvents с нулевым distinct_size означают, что коммиты были принудительно стёрты  
# payload.distinct_size = 0 AND payload.size > 0 → признак force push

# Проверка событий удаления веток  
bq query --use_legacy_sql=false "  
SELECT created_at, actor.login, payload.ref, payload.ref_type  
FROM \`githubarchive.month.*\`  
WHERE _TABLE_SUFFIX BETWEEN 'YYYYMM' AND 'YYYYMM'  
  AND type = 'DeleteEvent'  
  AND repo.name = 'OWNER/REPO'  
LIMIT 200  
"

[/code] Доказательства для сбора : * События force-push (payload.size > 0, payload.distinct_size = 0) * DeleteEvents для веток/тегов * WorkflowRunEvents для подозрительной CI/CD автоматизации * PushEvents, предшествующие «разрыву» в git-логе (доказательство перезаписи)

Справочник : См. github-archive-guide.md для всех 12 типов событий и шаблонов запросов.


Исследователь 5: Обогащение IOC

ГРАНИЦА РОЛИ : Вы обогащаете СУЩЕСТВУЮЩИЕ IOC из Фазы 1, используя ТОЛЬКО пассивные публичные источники. Не выполняйте никакой код из целевого репозитория. Действия : * Для каждого SHA коммита: попытка восстановления через прямой URL GitHub (github.com/OWNER/REPO/commit/SHA.patch) * Для каждого домена/IP: проверка пассивного DNS, записей WHOIS (через web_extract на публичных WHOIS-сервисах) * Для каждого имени пакета: проверка npm/PyPI на наличие соответствующих отчётов о вредоносных пакетах * Для каждого имени актора: проверка профиля GitHub, истории контрибуций, возраста аккаунта * Восстановление коммитов, удалённых через force-push, 3 методами (см. recovery-techniques.md)


Фаза 3: Консолидация доказательств

После завершения всех исследователей: 1. Запустите python3 SKILL_DIR/scripts/evidence-store.py --store evidence.json list, чтобы увидеть все собранные доказательства. 2. Для каждого доказательства проверьте, что хеш content_sha256 соответствует оригинальному источнику. 3. Сгруппируйте доказательства по: * Временной шкале : Отсортируйте все доказательства с временными метками хронологически * Актору : Сгруппируйте по имени на GitHub или email * IOC : Свяжите доказательства с соответствующим IOC 4. Выявите расхождения : элементы, присутствующие в одном источнике, но отсутствующие в другом (ключевые индикаторы удаления). 5. Пометьте доказательства как [VERIFIED] (подтверждено из 2+ независимых источников) или [UNVERIFIED] (только один источник).


Фаза 4: Формирование гипотез

Гипотеза должна: * Содержать конкретное утверждение (например, «Актор X сделал force-push в ветку BRANCH в DATE, чтобы стереть коммит SHA») * Ссылаться как минимум на 2 идентификатора доказательств, подтверждающих её (EV-XXXX, EV-YYYY) * Определять, какие доказательства могли бы её опровергнуть * Быть помечена [HYPOTHESIS] до валидации

Общие шаблоны гипотез (см. investigation-templates.md): * Компрометация мейнтейнера: легитимный аккаунт используется после перехвата для внедрения вредоносного кода * Путаница зависимостей: занятие имени пакета для перехвата установок * Инъекция в CI/CD: вредоносные изменения в workflow для выполнения кода во время сборок * Тайпсквоттинг: почти идентичное имя пакета для обмана допускающих опечатки * Утечка учётных данных: токен/ключ случайно закоммичен, затем удалён через force-push

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


Фаза 5: Валидация гипотез

Суб-агент-валидатор ОБЯЗАН механически проверить: 1. Для каждой гипотезы извлечь все упомянутые идентификаторы доказательств. 2. Проверить, что каждый ID существует в evidence.json (жёсткий сбой, если какой-либо ID отсутствует → гипотеза отклоняется как потенциально сфабрикованная). 3. Проверить, что каждое [VERIFIED] доказательство подтверждено из 2+ источников. 4. Проверить логическую согласованность: поддерживает ли временная шкала, отображаемая доказательствами, гипотезу? 5. Проверить альтернативные объяснения: может ли та же совокупность доказательств возникнуть из безвредной причины?

Результат : * VALIDATED: Все доказательства процитированы, проверены, логически согласованы, нет правдоподобного альтернативного объяснения. * INCONCLUSIVE: Доказательства поддерживают гипотезу, но существуют альтернативные объяснения или доказательств недостаточно. * REJECTED: Отсутствуют идентификаторы доказательств, непроверенные доказательства представлены как факты, обнаружена логическая несогласованность.

Отклонённые гипотезы возвращаются в Фазу 4 для доработки (макс. 3 итерации).


Фаза 6: Создание итогового отчёта

Заполните investigation-report.md, используя шаблон из forensic-report.md. Обязательные разделы : * Краткое резюме: вердикт в один абзац (Скомпрометирован / Чист / Неубедительно) с уровнем уверенности * Временная шкала: хронологическая реконструкция всех значимых событий со ссылками на доказательства * Подтверждённые гипотезы: каждая со статусом и подтверждающими идентификаторами доказательств * Реестр доказательств: таблица всех записей EV-XXXX с источником, типом и статусом проверки * Список IOC: все извлечённые и обогащённые индикаторы компрометации * Цепочка хранения: как собирались доказательства, из каких источников, в какое время * Рекомендации: немедленные меры по смягчению, если компрометация обнаружена; рекомендации по мониторингу

Правила отчёта : * Каждое фактическое утверждение должно содержать как минимум одну ссылку [EV-XXXX] * Краткое резюме должно указывать уровень уверенности (Высокий / Средний / Низкий) * Все секреты/учётные данные должны быть заменены на [REDACTED]


Фаза 7: Завершение

  1. Выполните финальный подсчёт доказательств: python3 SKILL_DIR/scripts/evidence-store.py --store evidence.json list
  2. Архивируйте полную директорию расследования.
  3. Если компрометация подтверждена:
    • Перечислите немедленные меры по смягчению (ротация учётных данных, фиксация хешей зависимостей, уведомление пострадавших пользователей)
    • Определите затронутые версии/пакеты
    • Отметьте обязательства по раскрытию информации (если публичный пакет: скоординироваться с реестром пакетов)
  4. Представьте пользователю итоговый investigation-report.md.

Рекомендации по этичному использованию

Этот навык предназначен для оборонительных расследований безопасности — защиты открытого программного обеспечения от атак на цепочки поставок. Его нельзя использовать для: * Преследования или слежки за контрибьюторами или мейнтейнерами * Доксина — связывания активности на GitHub с реальными личностями в злонамеренных целях * Конкурентной разведки — расследования проприетарных или внутренних репозиториев без авторизации * Ложных обвинений — публикации результатов расследования без проверенных доказательств (см. защитные ограничения против галлюцинаций)

Расследования следует проводить с принципом минимального вмешательства : собирать только те доказательства, которые необходимы для подтверждения или опровержения гипотезы. При публикации результатов следуйте практике ответственного раскрытия информации и координируйте действия с затронутыми мейнтейнерами до публичного разглашения. Если расследование выявило реальную компрометацию, следуйте процессу координированного раскрытия уязвимостей: 1. Сначала уведомите мейнтейнеров репозитория приватно 2. Дайте разумное время на исправление (обычно 90 дней) 3. Скоординируйтесь с реестрами пакетов (npm, PyPI и др.), если затронуты опубликованные пакеты 4. Подайте CVE, если это уместно


Ограничения скорости API

GitHub REST API налагает лимиты на количество запросов, которые прервут крупные расследования, если ими не управлять. Аутентифицированные запросы : 5 000/час (требуется GITHUB_TOKEN env var или аутентификация gh CLI) Неаутентифицированные запросы : 60/час (непригодны для расследований) Лучшие практики : * Всегда аутентифицируйтесь: export GITHUB_TOKEN=ghp_... или используйте gh CLI (автоаутентификация) * Используйте условные запросы (заголовки If-None-Match / If-Modified-Since), чтобы не расходовать квоту на неизменённые данные * Для конечных точек с пагинацией получайте все страницы последовательно — не распараллеливайте запросы к одной конечной точке * Проверяйте заголовок X-RateLimit-Remaining; если ниже 100, приостановите работу до временной метки X-RateLimit-Reset * У BigQuery свои квоты (10 ТиБ/день бесплатного уровня) — всегда сначала выполняйте dry-run * CDX API Wayback Machine: формального лимита нет, но будьте вежливы (макс. 1-2 запроса/сек)

Если лимит превышен в середине расследования, запишите частичные результаты в хранилище доказательств и отметьте ограничение в отчёте.


Справочные материалы