
PyYAMLにおけるCVE-2020-14343の制御された脆弱性研究および再現ラボ
このプロジェクトは、CVE-2020-14343 を制御された隔離された Docker 環境で実演するものです。
このラボには 2 つの環境が含まれています:
yaml.safe_load() を使用した修正済み環境このラボでは、脆弱性のライフサイクル全体を実演します:
このラボで使用される再現ペイロードは意図的に無害であり、テストマーカーを出力するだけです。
| プロパティ | 詳細 |
|---|---|
| CVE | CVE-2020-14343 |
| 製品 | PyYAML |
| 影響を受けるバージョン | 5.4 より前のバージョン |
| 修正済みバージョン | 5.4 |
| 脆弱性の種類 | 不適切な入力検証 (CWE-20) |
| 深刻度 | 重大 |
| 攻撃対象領域 | 脆弱な読み込み機能を使用して処理される YAML 入力 |
| CVSS | 9.3 (CVSS v4、GitHub Advisory) |
この脆弱性は、信頼できない YAML 入力が脆弱な PyYAML の読み込み機能を使用して処理される場合に発生します。
5.4 より前の PyYAML バージョンでは、以下のような Python 固有のタグを含む、特別に細工された YAML タグが許可されていました:
!!python/object/new
FullLoader が使用された際にオブジェクト構築機能に到達する可能性がありました。
したがって、悪意のある YAML ドキュメントは意図しない Python コード実行を引き起こす可能性があります。
この問題は、以前の PyYAML 脆弱性に対する不完全な修正に関連していました。
PyYAML 5.4 は、任意の Python タグを UnsafeLoader に移動することで CVE-2020-14343 を修正しました。
信頼できない YAML を処理するアプリケーション向けに、このラボでは安全な読み込み方法として yaml.safe_load() も使用しています。
このラボには、2 つの分離された Docker サービスが含まれています:
Host Machine
|
+------------+------------+
| |
v v
Vulnerable App Patched App
localhost:5000 localhost:5001
| |
PyYAML 5.3.1 PyYAML 5.4
FullLoader SafeLoader
| |
v v
Payload executes Payload rejected
| サービス | ホストポート | コンテナポート | PyYAML | 目的 |
|---|---|---|---|---|
| vulnerable | 5000 | 5000 | 5.3.1 | 脆弱な環境 |
| patched | 5001 | 5000 | 5.4 | 修正済み環境 |
cve-2020-14343-lab/
├── vulnerable/
│ ├── app.py
│ ├── Dockerfile
│ └── requirements.txt
├── patched/
│ ├── app.py
│ ├── Dockerfile
│ └── requirements.txt
├── exploit/
│ └── reproduce.py
├── detection/
│ └── detect.py
├── screenshots/
│ ├── 01-docker-compose-running.png
│ ├── 02-vulnerable-detection.png
│ ├── 03-patched-detection.png
│ ├── 04a-vulnerable-request.png
│ ├── 04b-vulnerable-execution-log.png
│ └── 05-patched-exploit-blocked.png
├── blog/
│ └── CVE-2020-14343-Technical-Blog.pdf
├── docker-compose.yml
├── README.md
└── .gitignore
| ファイル/ディレクトリ | 目的 |
|---|---|
vulnerable/app.py | 脆弱な YAML 読み込みを使用する Flask アプリケーション |
vulnerable/Dockerfile | 脆弱な Docker イメージをビルドする |
vulnerable/requirements.txt | PyYAML を 5.3.1 に固定する |
patched/app.py | 安全な YAML 読み込みを使用する Flask アプリケーション |
patched/Dockerfile | パッチ適用済みの Docker イメージをビルドする |
patched/requirements.txt | PyYAML を 5.4 に固定する |
exploit/reproduce.py | 制御されたペイロードを使用して脆弱性を再現する |
detection/detect.py | Docker コンテナ内の PyYAML バージョンを確認する |
docker-compose.yml | 両方の環境をビルドして実行する |
screenshots/ | ラボ中に取得した証拠を格納する |
blog/ | 800~1200 語の技術ブログ PDF を格納する |
以下のソフトウェアが必要です:
ラボを開始する前に Docker Desktop が実行されている必要があります。
脆弱なアプリケーションは、Docker のポートマッピングを通じてローカルマシン上でのみ意図的に公開されています。
プロジェクトのルートディレクトリから、以下を実行します:
docker compose up --build -d
実行:
docker compose ps
両方のサービスが Up と表示されるはずです。
開く:
http://127.0.0.1:5000
No input content was provided to translate. Please send the Markdown chunk you would like translated into Japanese.
{
"message": "CVE-2020-14343 vulnerable YAML parser"
}
開く:
http://127.0.0.1:5001
No input content was provided to translate. Please send the Markdown chunk you would like translated into Japanese.
{
"message": "CVE-2020-14343 patched YAML parser"
}
docker compose up -d
docker compose down
docker compose up --build -d
docker compose ps
docker logs cve-vulnerable
docker logs cve-patched
脆弱なアプリケーションは、YAML 入力を受け付ける /parse エンドポイントを公開しています。
脆弱な環境では以下を使用しています:
yaml.FullLoader再現スクリプトの場所:
exploit/reproduce.py
脆弱なアプリケーションは以下で利用可能です:
http://127.0.0.1:5000/parse
実行:
python exploit/reproduce.py
スクリプトは、Python固有のYAMLタグを含む制御されたYAMLペイロードを送信します。
脆弱な環境では、ペイロードが受け入れられ、アプリケーションはHTTP 200レスポンスを返します。
制御されたテストマーカー:
CVE-2020-14343-TEST
脆弱なアプリケーションコンテナ内で実行されます。
実行は以下を使用して確認できます:
docker logs cve-vulnerable
期待されるログ出力には以下が含まれます:
CVE-2020-14343-TEST
これは、脆弱な YAML 読み込み動作を通じたコード実行を実証するものです。
再現用ペイロードは意図的に無害なものです。テスト用マーカーを出力するだけで、ホストシステムの変更、認証情報へのアクセス、機密データへのアクセス、外部システムとのやり取り、破壊的な操作は一切行いません。
検出スクリプトの場所は次のとおりです:
detection/detect.py
スクリプトは、指定された Docker コンテナ内にインストールされている PyYAML のバージョンを確認します。
修正後のバージョンは次のとおりです:
5.4
実行:
python detection/detect.py cve-vulnerable
期待される結果:
PyYAML installed version: 5.3.1
Fixed version: 5.4
STATUS: VULNERABLE
Reason: PyYAML version is older than 5.4.
実行:
python detection/detect.py cve-patched
期待される結果:
PyYAML installed version: 5.4
Fixed version: 5.4
STATUS: PATCHED
Reason: PyYAML version is 5.4 or newer.
Docker Container
|
v
docker exec
|
v
Import PyYAML
|
v
Read yaml.__version__
|
v
Compare with 5.4
|
+----------------------+
| |
< 5.4 >= 5.4
| |
v v
VULNERABLE PATCHED
スクリプトは、ターゲットコンテナからインストール済みの PyYAML バージョンを照会します。
脆弱な環境では以下を使用しています:
PyYAML==5.3.1
パッチ適用済みの環境では次を使用します:
PyYAML==5.4
パッチ適用済みのアプリケーションは次も使用しています:
yaml.safe_load(yaml_input)
の代わりに:
yaml.load(yaml_input, Loader=yaml.FullLoader)
yaml.safe_load() を使用します。同じエクスプロイトペイロードをパッチ適用済みのアプリケーションに対してテストします。
パッチ適用済みのアプリケーションは以下で実行されます:
http://127.0.0.1:5001/parse
実行:
python exploit/reproduce.py http://127.0.0.1:5001/parse
このラボで観察された結果:
HTTP Status: 400
Server Response:
{"message":"could not determine a constructor for the tag 'tag:yaml.org,2002:python/object/new:tuple' ...","status":"error"}
Python固有のYAMLタグは、パッチ適用済みアプリケーションでは拒否されます。
制御されたテストマーカーは、パッチ適用済みアプリケーションでは実行されません。
| テスト | 脆弱な環境 | パッチ適用済み環境 |
|---|---|---|
| PyYAMLバージョン | 5.3.1 | 5.4 |
| 検出結果 | VULNERABLE | PATCHED |
| エクスプロイトリクエスト | HTTP 200 | HTTP 400 |
| Python固有のYAMLタグ | 受け入れ | 拒否 |
| テストマーカーの実行 | コンテナログで確認 | 実行されず |
Docker Desktopが実行中であることを確認し、次を検証してください:
docker version
確認:
docker ps -a
必要に応じて古いコンテナを削除します:
docker rm cve-vulnerable cve-patched
次に:
docker compose up --build -d
docker compose ps
docker logs cve-vulnerable
docker logs cve-patched
docker compose up --build -d
クリーンビルドの場合: