OSS 取證
針對 GitHub 倉庫的供應鏈調查、證據恢復和取證分析。 涵蓋刪除的提交恢復、強制推送檢測、IOC(入侵指標)提取、多源證據 收集、假設形成/驗證以及結構化取證報告。 靈感來源於 RAPTOR 的 1800+ 行 OSS 取證系統。
技能元數據
| 來源 | 可選 — 使用 hermes skills install official/security/oss-forensics 安裝 |
| 路徑 | optional-skills/security/oss-forensics |
參考:完整 SKILL.md
以下是觸發此技能時 Hermes 加載的完整技能定義。這是技能激活時代理看到的指令。
OSS 安全取證技能
一個用於研究開源供應鏈攻擊的 7 階段多代理調查框架。 改編自 RAPTOR 的取證系統。涵蓋 GitHub Archive、Wayback Machine、GitHub API、 本地 git 分析、IOC 提取、基於證據的假設形成和驗證, 以及最終取證報告生成。
⚠️ 防幻覺護欄
在執行每個調查步驟之前請閱讀這些內容。違反這些規定將使報告無效。
- 證據優先規則:任何報告、假設或摘要中的每個主張必須引用至少一個證據 ID (
EV-XXXX)。禁止沒有引用的斷言。 - 各司其職:每個子代理(調查員)只有一個數據源。不要混合來源。GH Archive 調查員不查詢 GitHub API,反之亦然。角色邊界是硬性的。
- 事實與假設分離:用
[HYPOTHESIS]標記所有未經驗證的推論。只有針對原始來源驗證過的陳述才能作為事實陳述。 - 禁止偽造證據:假設驗證器必須在接受假設之前,機械地檢查每個引用的證據 ID 是否確實存在於證據存儲中。
- 證偽需舉證:如果沒有具體的、有證據支持的反駁論點,就不能駁回假設。“未發現證據”不足以證偽——它只能使假設成為非結論性的。
- SHA/URL 雙重驗證:任何作為證據引用的提交 SHA、URL 或外部標識符,在標記為已驗證之前,必須從至少兩個來源獨立確認。
- 可疑代碼規則:切勿在本地運行在被調查倉庫中發現的代碼。僅進行靜態分析,或在沙箱環境中使用
execute_code。 - 秘密信息脫敏:調查過程中發現的任何 API 密鑰、令牌或憑據必須在最終報告中脫敏。僅在內部記錄它們。
示例場景
- 場景 A:依賴混淆:惡意包
internal-lib-v2以高於內部版本的版本號上傳到 NPM。調查員必須追蹤首次發現此包的時間,以及目標倉庫中的任何 PushEvents 是否將package.json更新為此版本。 - 場景 B:維護者接管:長期貢獻者的賬戶被用來推送後門的
.github/workflows/build.yml。調查員尋找該用戶在長時間不活動後或來自新 IP/位置(如果可通過 BigQuery 檢測)的 PushEvents。 - 場景 C:強制推送隱藏:開發人員意外提交了生產環境秘密,然後強制推送以“修復”它。調查員使用
git fsck和 GH Archive 恢復原始提交 SHA 並驗證洩露的內容。
路徑約定:在整個技能中,
SKILL_DIR指的是此技能安裝目錄的根目錄(包含此SKILL.md的文件夾)。當技能加載時, 將SKILL_DIR解析為實際路徑 — 例如~/.hermes/skills/security/oss-forensics/或等效的optional-skills/路徑。所有腳本和模板引用均相對於此路徑。
階段 0:初始化
- 創建調查工作目錄:
mkdir investigation_$(echo "REPO_NAME" | tr '/' '_')
cd investigation_$(echo "REPO_NAME" | tr '/' '_') - 初始化證據存儲:
python3 SKILL_DIR/scripts/evidence-store.py --store evidence.json list - 複製取證報告模板:
cp SKILL_DIR/templates/forensic-report.md ./investigation-report.md - 創建一個
iocs.md文件,以跟蹤發現的入侵指標 (Indicators of Compromise)。 - 記錄調查開始時間、目標倉庫和聲明的調查目標。
階段 1:提示解析和 IOC 提取
目標:從用戶請求中提取所有結構化的調查目標。
操作:
- 解析用戶提示並提取:
- 目標倉庫 (
owner/repo) - 目標參與者(GitHub 用戶名、電子郵件地址)
- 感興趣的時間窗口(提交日期範圍、PR 時間戳)
- 提供的入侵指標:提交 SHA、文件路徑、包名稱、IP 地址、域名、API 密鑰/令牌、惡意 URL
- 任何鏈接的供應商安全報告或博客文章
- 目標倉庫 (
工具:僅推理,或使用 execute_code 從大文本塊中進行正則表達式提取。
輸出:將提取的 IOC 填充到 iocs.md 中。每個 IOC 必須包含:
- 類型(來自:COMMIT_SHA、FILE_PATH、API_KEY、SECRET、IP_ADDRESS、DOMAIN、PACKAGE_NAME、ACTOR_USERNAME、MALICIOUS_URL、OTHER)
- 值
- 來源(用戶提供、推斷)
參考:參見 evidence-types.md 瞭解 IOC 分類法。
階段 2:並行證據收集
使用 delegate_task(批處理模式,最多 3 個併發)啟動最多 5 個專業調查員子代理。每個調查員擁有單一數據源,不得混合來源。
編排器注意:在每個委託任務的
context字段中傳遞階段 1 的 IOC 列表和調查時間窗口。
調查員 1:本地 Git 調查員
角色邊界:你僅查詢本地 GIT 倉庫。不要調用任何外部 API。
操作:
# Clone repository
git clone https://github.com/OWNER/REPO.git target_repo && cd target_repo
# Full commit log with stats
git log --all --full-history --stat --format="%H|%ae|%an|%ai|%s" > ../git_log.txt
# Detect force-push evidence (orphaned/dangling commits)
git fsck --lost-found --unreachable 2>&1 | grep commit > ../dangling_commits.txt
# Check reflog for rewritten history
git reflog --all > ../reflog.txt
# List ALL branches including deleted remote refs
git branch -a -v > ../branches.txt
# Find suspicious large binary additions
git log --all --diff-filter=A --name-only --format="%H %ai" -- "*.so" "*.dll" "*.exe" "*.bin" > ../binary_additions.txt
# Check for GPG signature anomalies
git log --show-signature --format="%H %ai %aN" > ../signature_check.txt 2>&1
要收集的證據(通過 python3 SKILL_DIR/scripts/evidence-store.py add 添加):
- 每個懸空提交 SHA → 類型:
git - 強制推送證據(顯示歷史重寫的 reflog)→ 類型:
git - 來自已驗證貢獻者的未簽名提交 → 類型:
git - 可疑的二進制文件添加 → 類型:
git
參考:參見 recovery-techniques.md 瞭解如何訪問被強制推送的提交。
調查員 2:GitHub API 調查員
角色邊界:你僅查詢 GITHUB REST API。不要在本地運行 git 命令。
操作:
# Commits (paginated)
curl -s "https://api.github.com/repos/OWNER/REPO/commits?per_page=100" > api_commits.json
# Pull Requests including closed/deleted
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
# Contributors and collaborator changes
curl -s "https://api.github.com/repos/OWNER/REPO/contributors" > api_contributors.json
# Repository events (last 300)
curl -s "https://api.github.com/repos/OWNER/REPO/events?per_page=100" > api_events.json
# Check specific suspicious commit SHA details
curl -s "https://api.github.com/repos/OWNER/REPO/git/commits/SHA" > commit_detail.json
# Releases
curl -s "https://api.github.com/repos/OWNER/REPO/releases?per_page=100" > api_releases.json
# Check if a specific commit exists (force-pushed commits may 404 on commits/ but succeed on git/commits/)
curl -s "https://api.github.com/repos/OWNER/REPO/commits/SHA" | jq .sha
交叉引用目標(將差異標記為證據):
- PR 存在於歸檔中但 API 中缺失 → 刪除證據
- 貢獻者出現在歸檔事件中但不在貢獻者列表中 → 權限撤銷證據
- 提交出現在歸檔 PushEvents 中但不在 API 提交列表中 → 強制推送/刪除證據
參考:參見 evidence-types.md 瞭解 GH 事件類型。
調查員 3:Wayback Machine 調查員
角色邊界:你僅查詢 WAYBACK MACHINE CDX API。不要使用 GitHub API。
目標:恢復已刪除的 GitHub 頁面(README、issues、PR、發佈版本、wiki 頁面)。
操作:
# Search for archived snapshots of the repo main page
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
# Search for a specific deleted 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
# Search for a specific deleted 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
# Fetch the best snapshot of a page
# Use the Wayback Machine URL: https://web.archive.org/web/TIMESTAMP/ORIGINAL_URL
# Example: https://web.archive.org/web/20240101000000*/github.com/OWNER/REPO
# Advanced: Search for deleted releases/tags
curl -s "https://web.archive.org/cdx/search/cdx?url=github.com/OWNER/REPO/releases/tag/*&output=json" > wayback_tags.json
# Advanced: Search for historical wiki changes
curl -s "https://web.archive.org/cdx/search/cdx?url=github.com/OWNER/REPO/wiki/*&output=json" > wayback_wiki.json
要收集的證據:
- 已刪除 issue/PR 的歸檔快照及其內容
- 顯示變更的歷史 README 版本
- 存在於歸檔中但當前 GitHub 狀態中缺失的內容證據
參考:參見 github-archive-guide.md 瞭解 CDX API 參數。
調查員 4:GH Archive / BigQuery 調查員
角色邊界:你僅通過 BIGQUERY 查詢 GITHUB ARCHIVE。這是所有公共 GitHub 事件的防篡改記錄。
前提條件:需要具有 BigQuery 訪問權限的 Google Cloud 憑據(
gcloud auth application-default login)。如果不可用,請跳過此調查員並在報告中註明。
成本優化規則(強制):
- 在每次查詢前始終運行
--dry_run以估算成本。 - 使用
_TABLE_SUFFIX按日期範圍過濾並最小化掃描的數據。 - 僅 SELECT 你需要的列。
- 除非進行聚合,否則添加 LIMIT。
# Template: safe BigQuery query for PushEvents to 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
"
# If cost is acceptable, re-run without --dry_run
# Detect force-pushes: zero-distinct_size PushEvents mean commits were force-erased
# payload.distinct_size = 0 AND payload.size > 0 → force push indicator
# Check for deleted branch events
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
"
要收集的證據:
- 強制推送事件(payload.size > 0, payload.distinct_size = 0)
- 分支/標籤的 DeleteEvents
- 可疑 CI/CD 自動化的 WorkflowRunEvents
- 在 git 日誌“間隙”之前的 PushEvents(重寫證據)
參考:參見 github-archive-guide.md 瞭解所有 12 種事件類型和查詢模式。
調查員 5:IOC 豐富調查員
角色邊界:你僅使用被動公共來源豐富階段 1 中的現有 IOC。不要執行目標倉庫中的任何代碼。
操作:
- 對於每個提交 SHA:嘗試通過直接 GitHub URL(
github.com/OWNER/REPO/commit/SHA.patch)進行恢復 - 對於每個域名/IP:檢查被動 DNS、WHOIS 記錄(通過對公共 WHOIS 服務使用
web_extract) - 對於每個包名稱:檢查 npm/PyPI 是否有匹配的惡意包報告
- 對於每個行為者用戶名:檢查 GitHub 個人資料、貢獻歷史、賬戶年齡
- 使用 3 種方法恢復被強制推送的提交(參見 recovery-techniques.md)
階段 3:證據整合
在所有調查員完成後:
- 運行
python3 SKILL_DIR/scripts/evidence-store.py --store evidence.json list以查看所有已收集的證據。 - 對於每條證據,驗證
content_sha256哈希值是否與原始來源匹配。 - 按以下方式對證據進行分組:
- 時間線:按時間順序對所有帶時間戳的證據進行排序
- 行為者:按 GitHub 用戶名或電子郵件分組
- IOC(入侵指標):將證據與其相關的 IOC 關聯
- 識別差異:即存在於一個來源但缺失於另一個來源的項目(關鍵刪除指示器)。
- 將證據標記為
[VERIFIED](經 2 個或更多獨立來源確認)或[UNVERIFIED](僅來自單一來源)。
第 4 階段:假設形成
假設必須:
- 陳述一個具體的主張(例如,“行為者 X 於 DATE 強制推送到 BRANCH 以擦除提交 SHA”)
- 引用至少 2 個支持該假設的證據 ID(
EV-XXXX、EV-YYYY) - 指出哪些證據可以反駁該假設
- 在驗證之前標記為
[HYPOTHESIS]
常見假設模板(參見 investigation-templates.md):
- 維護者賬戶失陷:合法賬戶在接管後被用於注入惡意代碼
- 依賴混淆:搶注包名以攔截安裝
- CI/CD 注入:惡意更改工作流以在構建期間運行代碼
- typo 搶注(Typosquatting):使用近乎相同的包名針對拼寫錯誤用戶
- 憑據洩露:令牌/密鑰被意外提交,隨後通過強制推送擦除
對於每個假設,啟動一個 delegate_task 子代理,在確認之前嘗試尋找反駁證據。
第 5 階段:假設驗證
驗證子代理必須機械地檢查:
- 對於每個假設,提取所有引用的證據 ID。
- 驗證每個 ID 是否存在於
evidence.json中(如果任何 ID 缺失則硬性失敗 → 假設因可能偽造而被拒絕)。 - 驗證每條
[VERIFIED]證據是否經 2 個或更多來源確認。 - 檢查邏輯一致性:證據描繪的時間線是否支持該假設?
- 檢查替代解釋:相同的證據模式是否可能由良性原因引起?
輸出:
VALIDATED:所有引用的證據均已驗證,邏輯一致,無合理的替代解釋。INCONCLUSIVE:證據支持假設,但存在替代解釋或證據不足。REJECTED:缺少證據 ID、引用未驗證的證據作為事實、檢測到邏輯不一致。
被拒絕的假設反饋回第 4 階段進行細化(最多 3 次迭代)。
第 6 階段:最終報告生成
使用 forensic-report.md 中的模板填充 investigation-report.md。
必填部分:
- 執行摘要:一段話的結論(失陷 / 乾淨 / 不確定)及置信度級別
- 時間線:按時間順序重建所有重大事件並引用證據
- 已驗證的假設:每個假設的狀態及支持的證據 ID
- 證據註冊表:所有
EV-XXXX條目的表格,包含來源、類型和驗證狀態 - IOC 列表:所有提取和豐富的入侵指標
- 監管鏈:證據如何收集、來自哪些來源、在什麼時間戳
- 建議:如果檢測到失陷,立即採取的緩解措施;監控建議
報告規則:
- 每個事實性主張必須至少有一個
[EV-XXXX]引用 - 執行摘要必須聲明置信度級別(高 / 中 / 低)
- 所有秘密/憑據必須脫敏為
[REDACTED]
第 7 階段:完成
- 運行最終證據計數:
python3 SKILL_DIR/scripts/evidence-store.py --store evidence.json list - 歸檔整個調查目錄。
- 如果確認失陷:
- 列出立即緩解措施(輪換憑據、固定依賴哈希、通知受影響的用戶)
- 識別受影響的版本/包
- 註明披露義務(如果是公共包:與包註冊表協調)
- 向用戶展示最終的
investigation-report.md。
道德使用指南
此技能專為防禦性安全調查設計——保護開源軟件免受供應鏈攻擊。不得用於:
- 騷擾或跟蹤貢獻者或維護者
- 人肉搜索——出於惡意目的將 GitHub 活動關聯到真實身份
- 競爭情報——未經授權調查專有或內部倉庫
- 虛假指控——發佈未經過驗證證據的調查結果是(參見反幻覺防護措施)
調查應遵循最小侵入原則:僅收集驗證或反駁假設所需的證據。發佈結果時,請遵循負責任的披露實踐,並在公開披露前與受影響的維護者協調。
如果調查確認存在真實的安全入侵,請遵循協調漏洞披露流程:
- 首先私下通知倉庫維護者
- 留出合理的修復時間(通常為 90 天)
- 如果已發佈的包受到影響,請與包註冊表(npm、PyPI 等)協調
- 如適用,申請 CVE 編號
API 速率限制
GitHub REST API 實施了速率限制,如果不加以管理,將會中斷大規模調查。
經過身份驗證的請求:5,000 次/小時(需要 GITHUB_TOKEN 環境變量或 gh CLI 認證)
未經身份驗證的請求:60 次/小時(不適用於調查工作)
最佳實踐:
- 始終進行身份驗證:
export GITHUB_TOKEN=ghp_...或使用ghCLI(自動認證) - 使用條件請求(
If-None-Match/If-Modified-Since頭信息),以避免在未更改的數據上消耗配額 - 對於分頁端點,按順序獲取所有頁面——不要對同一端點進行並行請求
- 檢查
X-RateLimit-Remaining頭信息;如果低於 100,請暫停至X-RateLimit-Reset時間戳 - BigQuery 有其自身的配額(免費層級為 10 TiB/天)——務必先執行幹跑(dry-run)
- Wayback Machine CDX API:沒有正式的速率限制,但請保持禮貌(最多 1-2 次請求/秒)
如果在調查過程中受到速率限制,請在證據存儲中記錄部分結果,並在報告中註明該限制。
參考資料
- github-archive-guide.md — BigQuery 查詢、CDX API、12 種事件類型
- evidence-types.md — IOC 分類法、證據源類型、觀察類型
- recovery-techniques.md — 恢復已刪除的提交、PR、Issue
- investigation-templates.md — 針對每種攻擊類型的預建假設模板
- evidence-store.py — 用於管理證據 JSON 存儲的 CLI 工具
- forensic-report.md — 結構化報告模板