mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['', 'src/pentesting-web/dependency-confusion.md'] to ja
This commit is contained in:
parent
1e8e6b8997
commit
2e1c757e75
@ -2,44 +2,264 @@
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
## 基本情報
|
||||
|
||||
要約すると、依存関係の混乱脆弱性は、プロジェクトが**スペルミス**のあるライブラリ、**存在しない**ライブラリ、または**バージョンが指定されていない**ライブラリを使用しており、使用される依存関係リポジトリが**公開リポジトリから更新されたバージョンを取得することを許可している**場合に発生します。
|
||||
依存関係の混乱(別名:置換攻撃)は、パッケージマネージャーが意図しない、信頼性の低いレジストリ/ソース(通常は公開レジストリ)から依存関係名を解決する際に発生します。これは通常、攻撃者が制御するパッケージのインストールにつながります。
|
||||
|
||||
- **スペルミス**: **`reqests`**をインポートする代わりに`requests`
|
||||
- **存在しない**: `company-logging`をインポートする、もはや**存在しない**内部ライブラリ
|
||||
- **バージョンが指定されていない**: **内部**の**存在する**`company-requests`ライブラリをインポートするが、リポジトリは**公開リポジトリ**をチェックして**より新しいバージョン**があるかどうかを確認します。
|
||||
一般的な根本原因:
|
||||
- タイポスカッティング/スペルミス:`reqests`をインポートする代わりに`requests`(公開レジストリから解決)。
|
||||
- 存在しない/放棄された内部パッケージ:もはや内部に存在しない`company-logging`をインポートすると、リゾルバーは公開レジストリを探し、攻撃者のパッケージを見つけます。
|
||||
- 複数のレジストリ間でのバージョンの優先:内部の`company-requests`をインポートする際、リゾルバーが公開レジストリもクエリでき、攻撃者によって公開された「最良の」/新しいバージョンを優先する場合。
|
||||
|
||||
重要なアイデア:リゾルバーが同じパッケージ名の複数のレジストリを確認でき、「最良」の候補をグローバルに選択できる場合、解決を制約しない限り、あなたは脆弱です。
|
||||
|
||||
## 悪用
|
||||
|
||||
> [!WARNING]
|
||||
> すべてのケースにおいて、攻撃者は被害者企業が使用しているライブラリの**名前を持つ悪意のあるパッケージを公開する**だけで済みます。
|
||||
> すべてのケースにおいて、攻撃者は公開レジストリからビルドが解決する依存関係と同じ名前の悪意のあるパッケージを公開するだけで済みます。インストール時のフック(例:npmスクリプト)やインポート時のコードパスは、しばしばコード実行を提供します。
|
||||
|
||||
### スペルミスと存在しない
|
||||
### スペルミスと存在しないもの
|
||||
|
||||
あなたの会社が**内部でないライブラリをインポートしようとしている**場合、ライブラリのリポジトリは**公開リポジトリ**でそれを探す可能性が非常に高いです。攻撃者がそれを作成している場合、あなたのコードと実行中のマシンは非常に高い確率で侵害されるでしょう。
|
||||
プロジェクトがプライベートレジストリに存在しないライブラリを参照している場合、ツールが公開レジストリにフォールバックすると、攻撃者はその名前の悪意のあるパッケージを公開レジストリに仕込むことができます。あなたのランナー/CI/開発マシンはそれを取得して実行します。
|
||||
|
||||
### バージョンが指定されていない
|
||||
### 未指定のバージョン / インデックス間の「最良バージョン」選択
|
||||
|
||||
開発者が使用するライブラリの**バージョンを指定しない**、または**メジャーバージョン**だけを指定することは非常に一般的です。その場合、インタープリターはその要件に合った**最新バージョン**をダウンロードしようとします。\
|
||||
ライブラリが**既知の外部ライブラリ**(例えば、pythonの`requests`)である場合、**攻撃者はあまりできることがありません**。なぜなら、彼は`requests`という名前のライブラリを作成できないからです(彼が元の著者でない限り)。\
|
||||
しかし、ライブラリが**内部**のもので、例えばこの例の`requests-company`のように、**ライブラリリポジトリ**が**新しいバージョンを外部でもチェックすることを許可している**場合、公開されている新しいバージョンを探します。\
|
||||
したがって、**攻撃者が**会社が`requests-company`ライブラリの**バージョン1.0.1**(マイナーアップデートを許可)を使用していることを知っている場合、彼は**バージョン1.0.2**のライブラリ`requests-company`を**公開**し、会社は内部のものの代わりにそのライブラリを**使用する**ことになります。
|
||||
開発者はしばしばバージョンを固定せず、広範囲を許可します。リゾルバーが内部と公開のインデックスの両方で構成されている場合、ソースに関係なく最新のバージョンを選択する可能性があります。内部名の`requests-company`の場合、内部インデックスに`1.0.1`があるが、攻撃者が公開レジストリに`1.0.2`を公開し、リゾルバーが両方を考慮する場合、公開パッケージが勝つ可能性があります。
|
||||
|
||||
## AWSの修正
|
||||
|
||||
この脆弱性はAWSの**CodeArtifact**で発見されました([**このブログ記事の詳細を読む**](https://zego.engineering/dependency-confusion-in-aws-codeartifact-86b9ff68963d))。\
|
||||
AWSは、ライブラリが内部か外部かを指定できるようにすることで、外部リポジトリから内部依存関係をダウンロードするのを避けるように修正しました。
|
||||
この脆弱性はAWS CodeArtifactで発見されました(詳細はこのブログ投稿を参照)。AWSは依存関係/フィードを内部と外部としてマークする制御を追加し、クライアントが上流の公開レジストリから「内部」名を取得しないようにしました。
|
||||
|
||||
## 脆弱なライブラリの発見
|
||||
|
||||
[**依存関係の混乱に関する元の投稿**](https://medium.com/@alex.birsan/dependency-confusion-4a5d60fec610)で、著者はJavaScriptプロジェクトの依存関係を含む何千もの公開されたpackage.jsonファイルを検索しました。
|
||||
依存関係の混乱に関する元の投稿では、著者は内部パッケージ名を推測するために何千もの公開されたマニフェスト(例:`package.json`、`requirements.txt`、ロックファイル)を探し、その後、公開レジストリに高バージョンのパッケージを公開しました。
|
||||
|
||||
## 実践的な攻撃者プレイブック(認可されたテストのためのレッドチーム向け)
|
||||
|
||||
- 名前を列挙:
|
||||
- マニフェスト/ロックファイルと内部ネームスペースのためにリポジトリとCI設定をgrepします。
|
||||
- 組織特有のプレフィックス(例:`@company/*`、`company-*`、内部groupIds、NuGet IDパターン、Goのプライベートモジュールパスなど)を探します。
|
||||
- 公開レジストリでの可用性を確認:
|
||||
- 名前が公開で未登録の場合は登録し、存在する場合は内部の遷移名をターゲットにしてサブ依存関係のハイジャックを試みます。
|
||||
- 優先順位をつけて公開:
|
||||
- 「勝つ」セマンティックバージョン(例:非常に高いバージョン)を選択するか、リゾルバーのルールに一致させます。
|
||||
- 適用可能な場合は最小限のインストール時実行を含めます(例:npmの`preinstall`/`install`/`postinstall`スクリプト)。Pythonの場合、ホイールは通常インストール時に任意のコードを実行しないため、インポート時の実行パスを優先します。
|
||||
- コントロールの外部流出:
|
||||
- CIから制御されたエンドポイントへのアウトバウンドが許可されていることを確認します。そうでない場合は、DNSクエリやエラーメッセージをサイドチャネルとして使用してコード実行を証明します。
|
||||
|
||||
> [!CAUTION]
|
||||
> 常に書面による承認を取得し、エンゲージメントのためにユニークなパッケージ名/バージョンを使用し、テストが終了したら直ちに公開を取り消すか、クリーンアップを調整してください。
|
||||
|
||||
## ディフェンダープレイブック(実際に混乱を防ぐもの)
|
||||
|
||||
エコシステム全体で機能する高レベルの戦略:
|
||||
- ユニークな内部ネームスペースを使用し、それを単一のレジストリにバインドします。
|
||||
- 解決時に信頼レベルを混合しないようにします。承認された公開パッケージをプロキシする単一の内部レジストリを優先し、パッケージマネージャーに内部と公開のエンドポイントの両方を与えないでください。
|
||||
- サポートされているマネージャーの場合、パッケージを特定のソースにマッピングします(レジストリ間でのグローバルな「最良バージョン」はなし)。
|
||||
- 固定とロック:
|
||||
- 解決されたレジストリのURLを記録するロックファイル(npm/yarn/pnpm)を使用するか、ハッシュ/証明書のピン留め(pip `--require-hashes`、Gradle依存関係の検証)を使用します。
|
||||
- レジストリ/ネットワーク層で内部名の公開フォールバックをブロックします。
|
||||
- 将来のスカッティングを防ぐために、可能な場合は公開レジストリで内部名を予約します。
|
||||
|
||||
## エコシステムノートとセキュアな設定スニペット
|
||||
|
||||
以下は、依存関係の混乱を減少または排除するための実用的で最小限の設定です。これらをCIおよび開発者環境で強制することを優先してください。
|
||||
|
||||
### JavaScript/TypeScript(npm、Yarn、pnpm)
|
||||
|
||||
- すべての内部コードにスコープ付きパッケージを使用し、スコープをプライベートレジストリに固定します。
|
||||
- CIでのインストールを不変に保ちます(npmロックファイル、`yarn install --immutable`)。
|
||||
|
||||
.npmrc(プロジェクトレベル)
|
||||
```
|
||||
# Bind internal scope to private registry; do not allow public fallback for @company/*
|
||||
@company:registry=https://registry.corp.example/npm/
|
||||
# Always authenticate to the private registry
|
||||
//registry.corp.example/npm/:_authToken=${NPM_TOKEN}
|
||||
strict-ssl=true
|
||||
```
|
||||
package.json (内部パッケージ用)
|
||||
```
|
||||
{
|
||||
"name": "@company/api-client",
|
||||
"version": "1.2.3",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"registry": "https://registry.corp.example/npm/",
|
||||
"access": "restricted"
|
||||
}
|
||||
}
|
||||
```
|
||||
Yarn Berry (.yarnrc.yml)
|
||||
```
|
||||
npmScopes:
|
||||
company:
|
||||
npmRegistryServer: "https://registry.corp.example/npm/"
|
||||
npmAlwaysAuth: true
|
||||
# CI should fail if lockfile would change
|
||||
enableImmutableInstalls: true
|
||||
```
|
||||
運用のヒント:
|
||||
- `@company` スコープ内でのみ内部パッケージを公開してください。
|
||||
- サードパーティのパッケージについては、クライアントから直接ではなく、プライベートプロキシ/ミラーを介して公開レジストリを許可してください。
|
||||
- 公開パッケージに対して npm パッケージの出所を有効にすることを検討してください。これにより追跡可能性が向上します(混乱を防ぐわけではありません)。
|
||||
|
||||
### Python (pip / Poetry)
|
||||
|
||||
コアルール: 信頼レベルを混合するために `--extra-index-url` を使用しないでください。次のいずれかを行ってください:
|
||||
- 承認された PyPI パッケージをプロキシおよびキャッシュする単一の内部インデックスを公開するか、
|
||||
- 明示的なインデックス選択とハッシュピンニングを使用してください。
|
||||
|
||||
pip.conf
|
||||
```
|
||||
[global]
|
||||
index-url = https://pypi.corp.example/simple
|
||||
# Disallow source distributions when possible
|
||||
only-binary = :all:
|
||||
# Lock with hashes generated via pip-tools
|
||||
require-hashes = true
|
||||
```
|
||||
pip-toolsを使用してハッシュ化された要件を生成する:
|
||||
```
|
||||
# From pyproject.toml or requirements.in
|
||||
pip-compile --generate-hashes -o requirements.txt
|
||||
pip install --require-hashes -r requirements.txt
|
||||
```
|
||||
もし公開のPyPIにアクセスする必要がある場合は、内部プロキシを介して行い、明示的な許可リストを維持してください。CIで`--extra-index-url`を避けてください。
|
||||
|
||||
### .NET (NuGet)
|
||||
|
||||
パッケージIDパターンを明示的なソースに結び付け、予期しないフィードからの解決を防ぐために、パッケージソースマッピングを使用してください。
|
||||
|
||||
nuget.config
|
||||
```
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<packageSources>
|
||||
<clear />
|
||||
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
|
||||
<add key="corp" value="https://nuget.corp.example/v3/index.json" />
|
||||
</packageSources>
|
||||
<packageSourceMapping>
|
||||
<packageSource key="nuget.org">
|
||||
<package pattern="*" />
|
||||
</packageSource>
|
||||
<packageSource key="corp">
|
||||
<package pattern="Company.*" />
|
||||
<package pattern="Internal.Utilities" />
|
||||
</packageSource>
|
||||
</packageSourceMapping>
|
||||
</configuration>
|
||||
```
|
||||
### Java (Maven/Gradle)
|
||||
|
||||
Maven settings.xml (内部にすべてをミラー; Enforcerを介してPOM内のアドホックリポジトリを禁止):
|
||||
```
|
||||
<settings>
|
||||
<mirrors>
|
||||
<mirror>
|
||||
<id>internal-mirror</id>
|
||||
<mirrorOf>*</mirrorOf>
|
||||
<url>https://maven.corp.example/repository/group</url>
|
||||
</mirror>
|
||||
</mirrors>
|
||||
</settings>
|
||||
```
|
||||
POMに宣言されたリポジトリを禁止し、あなたのミラーの使用を強制するためにEnforcerを追加します:
|
||||
```
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>enforce-no-repositories</id>
|
||||
<goals><goal>enforce</goal></goals>
|
||||
<configuration>
|
||||
<rules>
|
||||
<requireNoRepositories />
|
||||
</rules>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
```
|
||||
Gradle: 依存関係を集中管理し、ロックします。
|
||||
- `settings.gradle(.kts)` のみでリポジトリを強制します:
|
||||
```
|
||||
dependencyResolutionManagement {
|
||||
repositoriesMode = RepositoriesMode.FAIL_ON_PROJECT_REPOS
|
||||
repositories {
|
||||
maven { url = uri("https://maven.corp.example/repository/group") }
|
||||
}
|
||||
}
|
||||
```
|
||||
- 依存関係の検証(チェックサム/署名)を有効にし、`gradle/verification-metadata.xml`をコミットします。
|
||||
|
||||
### Go Modules
|
||||
|
||||
プライベートモジュールを設定して、パブリックプロキシとチェックサムDBが使用されないようにします。
|
||||
```
|
||||
# Use corporate proxy first, then public proxy as fallback
|
||||
export GOPROXY=https://goproxy.corp.example,https://proxy.golang.org
|
||||
# Mark private paths to skip proxy and checksum db
|
||||
export GOPRIVATE=*.corp.example.com,github.com/your-org/*
|
||||
export GONOSUMDB=*.corp.example.com,github.com/your-org/*
|
||||
```
|
||||
### Rust (Cargo)
|
||||
|
||||
承認された内部ミラーまたはベンダーディレクトリでビルドするために crates.io を置き換えます。任意の公開フォールバックを許可しないでください。
|
||||
|
||||
.cargo/config.toml
|
||||
```
|
||||
[source.crates-io]
|
||||
replace-with = "corp-mirror"
|
||||
|
||||
[source.corp-mirror]
|
||||
registry = "https://crates-mirror.corp.example/index"
|
||||
```
|
||||
公開する際は、`--registry`を明示的に指定し、認証情報はターゲットレジストリに限定してください。
|
||||
|
||||
### Ruby (Bundler)
|
||||
|
||||
ソースブロックを使用し、マルチソースGemfileを無効にして、gemが意図したリポジトリからのみ取得されるようにします。
|
||||
|
||||
Gemfile
|
||||
```
|
||||
source "https://gems.corp.example"
|
||||
|
||||
source "https://rubygems.org" do
|
||||
gem "rails"
|
||||
gem "pg"
|
||||
end
|
||||
|
||||
source "https://gems.corp.example" do
|
||||
gem "company-logging"
|
||||
end
|
||||
```
|
||||
設定レベルで強制する:
|
||||
```
|
||||
bundle config set disable_multisource true
|
||||
```
|
||||
## CI/CDとレジストリ制御の助け
|
||||
|
||||
- プライベートレジストリを単一の入口として使用:
|
||||
- 開発者/CIが到達できる唯一のエンドポイントとしてArtifactory/Nexus/CodeArtifact/GitHub Packages/Azure Artifactsを使用します。
|
||||
- 内部ネームスペースが上流の公開ソースから解決されないように、ブロック/許可ルールを実装します。
|
||||
- CIにおけるロックファイルは不変です:
|
||||
- npm: `package-lock.json`をコミットし、`npm ci`を使用します。
|
||||
- Yarn: `yarn.lock`をコミットし、`yarn install --immutable`を使用します。
|
||||
- Python: ハッシュ化された`requirements.txt`をコミットし、`--require-hashes`を強制します。
|
||||
- Gradle: `verification-metadata.xml`をコミットし、未知のアーティファクトで失敗します。
|
||||
- アウトバウンドエグレス制御: 承認されたプロキシを介さずにCIから公開レジストリへの直接アクセスをブロックします。
|
||||
- 名前予約: サポートされている公開レジストリに内部の名前/ネームスペースを事前登録します。
|
||||
- パッケージの出所/証明: 公開パッケージを公開する際には、改ざんを下流でより検出しやすくするために出所/証明を有効にします。
|
||||
|
||||
## 参考文献
|
||||
|
||||
- [https://medium.com/@alex.birsan/dependency-confusion-4a5d60fec610](https://medium.com/@alex.birsan/dependency-confusion-4a5d60fec610)
|
||||
- [https://zego.engineering/dependency-confusion-in-aws-codeartifact-86b9ff68963d](https://zego.engineering/dependency-confusion-in-aws-codeartifact-86b9ff68963d)
|
||||
|
||||
- [https://learn.microsoft.com/en-us/nuget/consume-packages/package-source-mapping](https://learn.microsoft.com/en-us/nuget/consume-packages/package-source-mapping)
|
||||
- [https://yarnpkg.com/configuration/yarnrc/](https://yarnpkg.com/configuration/yarnrc/)
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user