Oss Forensics

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

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

ИсточникОпциональный (устанавливается по запросу) — установка: hermes skills install official/security/oss-forensics
Путьoptional-skills/security/oss-forensics
Платформыlinux, macos, windows

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

инфо

Ниже приведено полное определение навыка, которое Hermes Agent загружает при его активации. Именно эти инструкции видит агент во время работы.

OSS Security Forensics Skill

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


⚠️ Защита от галлюцинаций

Прочти перед каждым шагом расследования. Нарушение этих правил делает отчёт недействительным.

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

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

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

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

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

  1. Создай рабочую директорию расследования:
    mkdir investigation_$(echo "REPO_NAME" | tr '/' '_')
    cd investigation_$(echo "REPO_NAME" | tr '/' '_')
  2. Инициализируй хранилище доказательств:
    python3 SKILL_DIR/scripts/evidence-store.py --store evidence.json list
  3. Скопируй шаблон форензического отчёта:
    cp SKILL_DIR/templates/forensic-report.md ./investigation-report.md
  4. Создай файл iocs.md для отслеживания индикаторов компрометации по мере их обнаружения.
  5. Зафикси время начала расследования, целевой репозиторий и формулировку задачи.

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

Цель: извлечь все структурированные объекты расследования из запроса пользователя.

Действия:

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

Инструменты: только логический вывод, либо execute_code для regex-извлечения из больших текстовых блоков.

Результат: заполнить 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 не вызывай.

Действия:

# Клонировать репозиторий
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

# Список ВСЕХ веток, включая удалённые remote-refs
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

Что собирать (добавлять через 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-команды не запускай.

Действия:

# Коммиты (с пагинацией)
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

Цели для перекрёстной проверки (расхождения фиксируй как доказательства):

  • PR присутствует в архиве, но отсутствует в API → свидетельство удаления
  • Контрибьютор есть в архивных событиях, но не в списке контрибьюторов → свидетельство отзыва прав
  • Коммит есть в PushEvents архива, но отсутствует в API-списке коммитов → свидетельство force-push/удаления

Справка: см. evidence-types.md — типы событий GH.


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

ГРАНИЦА РОЛИ: работаешь только с WAYBACK MACHINE CDX API. GitHub API не используй.

Цель: восстановить удалённые GitHub-страницы (README, issues, PR, релизы, страницы wiki).

Действия:

# Поиск архивных снимков главной страницы репозитория
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

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

Что собирать:

  • Архивные снимки удалённых 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, если не выполняешь агрегацию.
# Шаблон: безопасный 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
"

Что собирать:

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

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


Следователь 5: IOC-обогатитель

ГРАНИЦА РОЛИ: обогащаешь СУЩЕСТВУЮЩИЕ IOC из Фазы 1, используя только пассивные публичные источники. Не выполняй никакой код из целевого репозитория.

Действия:

  • Для каждого SHA коммита: попытаться восстановить через прямой GitHub URL (github.com/OWNER/REPO/commit/SHA.patch)
  • Для каждого домена/IP: проверить passive DNS, записи WHOIS (через web_extract на публичных WHOIS-сервисах)
  • Для каждого имени пакета: проверить npm/PyPI на наличие отчётов о соответствующем вредоносном пакете
  • Для каждого хэндла: проверить профиль GitHub, историю вклада, возраст аккаунта
  • Восстановить force-push коммиты тремя методами (см. recovery-techniques.md)

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

После завершения работы всех следователей:

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

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

Гипотеза должна:

  • Формулировать конкретное утверждение (например, «Актор X сделал force-push в BRANCH DATE, чтобы удалить коммит SHA»)
  • Ссылаться не менее чем на 2 идентификатора доказательств (EV-XXXX, EV-YYYY)
  • Указывать, какие доказательства могут её опровергнуть
  • Иметь метку [HYPOTHESIS] до проверки

Стандартные шаблоны гипотез (см. investigation-templates.md):

  • Компрометация мейнтейнера: легитимный аккаунт используется после захвата для внедрения вредоносного кода
  • Dependency Confusion: занятие пространства имён пакета для перехвата установок
  • CI/CD-инъекция: вредоносные изменения в workflow для выполнения кода во время сборки
  • Тайпосквоттинг: почти идентичное имя пакета, нацеленное на опечатки
  • Утечка учётных данных: токен/ключ случайно закоммичен, затем force-push для скрытия

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


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

Субагент-валидатор ОБЯЗАН механически проверить:

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

Результаты:

  • VALIDATED: все доказательства процитированы, верифицированы, логически согласованы, правдоподобных альтернативных объяснений нет.
  • INCONCLUSIVE: доказательства поддерживают гипотезу, но альтернативные объяснения существуют или доказательств недостаточно.
  • REJECTED: отсутствующие ID доказательств, непроверенные доказательства приводятся как факт, обнаружена логическая несогласованность.

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


Фаза 6: Генерация итогового отчёта

Заполни investigation-report.md по шаблону из forensic-report.md.

Обязательные разделы:

  • Краткое резюме: абзац с вердиктом (Compromised / Clean / Inconclusive) и уровнем достоверности
  • Временна́я шкала: хронологическая реконструкция всех значимых событий со ссылками на доказательства
  • Подтверждённые гипотезы: статус каждой и поддерживающие ID доказательств
  • Реестр доказательств: таблица всех записей EV-XXXX с источником, типом и статусом верификации
  • Список IOC: все извлечённые и обогащённые индикаторы компрометации
  • Цепочка хранения улик: как собирались доказательства, из каких источников, в какое время
  • Рекомендации: немедленные меры при подтверждении компрометации; рекомендации по мониторингу

Правила составления отчёта:

  • Каждое фактическое утверждение должно содержать хотя бы одну ссылку [EV-XXXX]
  • Краткое резюме должно содержать уровень достоверности (High / Medium / Low)
  • Все секреты и учётные данные должны быть заменены на [REDACTED]

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

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

Этические принципы использования

Этот навык предназначен для оборонительных расследований безопасности — защиты open-source программного обеспечения от атак на цепочки поставок. Он не должен использоваться для:

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

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

При обнаружении реальной компрометации следуй процессу координированного раскрытия уязвимостей:

  1. Сначала уведоми мейнтейнеров репозитория в частном порядке
  2. Дай разумное время на устранение (как правило, 90 дней)
  3. Координируй с реестрами пакетов (npm, PyPI и др.), если затронуты опубликованные пакеты
  4. При необходимости заведи CVE

Ограничения API по частоте запросов

GitHub REST API применяет лимиты, которые могут прервать масштабное расследование при их несоблюдении.

Аутентифицированные запросы: 5 000/час (требуется переменная окружения GITHUB_TOKEN или авторизация через 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 запроса/сек)

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


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

  • github-archive-guide.md — запросы BigQuery, CDX API, 12 типов событий
  • evidence-types.md — таксономия IOC, типы источников доказательств, типы наблюдений
  • recovery-techniques.md — восстановление удалённых коммитов, PR, issues
  • investigation-templates.md — готовые шаблоны гипотез по типам атак
  • evidence-store.py — CLI-инструмент для управления JSON-хранилищем доказательств
  • forensic-report.md — структурированный шаблон отчёта
ESC