FlawOpen

flawopen.com/Teardowns/cve-2026-63277-libreoffice-calc-jdbc-classpath-rce

● CVE-2026-63277 · CVSS v4 8.5 · 高
セキュリティ研究 · FlawOpen

CVE-2026-63277:Calc文書を開いた際のJava実行

細工されたCalc文書は外部データマッピングを利用し、利用者が表計算を開いた際に、LibreOfficeがローカル以外のJava class pathからJDBCドライバーのクラスを解決する可能性がありました。LibreOffice 26.2.5と26.8.0では、この項目にfileスキームのみを許可します。文書を開く操作が必要であり、ゼロクリックのネットワーク脆弱性ではありません。[1], [2], [3]

💡 わかりやすい解説 (ELI5)

表計算には、データベースドライバーをどこから探すかというメモを保存できます。修正前は、そのメモがリモートアドレスを指す場合があり、ファイルを開いたときにそこからJavaコードが読み込まれる可能性がありました。修正後はfile:スキームのアドレスだけを受け入れます。経路は限定されますが、このラベルだけで各対象が物理的にローカルにあるとは証明できません。[1], [4], [5]

主要な概念と専門用語

外部データマッピング
Calc文書で、シートが外部データソースへ接続する方法を示す設定。[1]
JDBCドライバー
アプリケーションがデータベースと通信するためのJavaソフトウェア。[1]
Class path
Javaがクラスや関連リソースを読み込める場所の集合。[4], [5]
CWE-829
信頼できない制御領域の機能を取り込む弱点。この経路では想定されたローカルファイル以外のスキームもclass path URLとして受け入れていました。[6], [1]

フレームワーク対応

  • このガイドで説明する弱点の CWE 参照: CWE-829

根本原因の分析 (Root Cause)

脆弱な jvmaccess::ClassPath::translateToUrls 経路は、各Java class path項目を展開し、スキームを先に制限せずJava URLコンストラクターへ渡していました。26.2.5.2のソースではURI解析を追加し、Java URLを作る前にスキームがfile以外の項目を拒否します。ベンダー勧告は、この経路をCalcの外部データマッピングとJDBCドライバーの読み込みに結び付けています。細工された文書を人が開く必要があります。引用した資料はゼロクリックでの到達性や実環境での悪用を示していません。チェック対象はスキームです。一般的な認可方針と説明したり、すべてのリモート共有を拒否すると主張したりしないでください。[1], [4], [5]

CVE-2026-63277:CalcからJava読み込みに至る条件

確認項目影響条件または確認済みの動作防御策
文書からの入力文書内の外部データマッピングがJDBCドライバー用class pathを指定できます。信頼できない文書やリンクを未信頼入力として扱い、修正版を導入します。
ユーザー操作ベンダーが説明する読み込み経路に到達するには、人が文書を開く必要があります。ゼロクリックと呼ばず、文書の受領と開封の管理を確認します。
修正の限界スキーム検査は、すべてのfile:対象が物理的にローカルにあることやネットワーク共有が拒否されることまでは示しません。変更をスキーム検証として説明し、認可や場所について広い保証を主張しません。

ステップ・バイ・ステップの攻撃フロー

ステップ 1

文書に外部データマッピングが含まれる

対象文書は外部データソースとJavaデータベースドライバークラスのclass pathを指定します。[1], [4]

ステップ 2

人が文書を開く

ユーザー操作が必要です。任意の表計算を開くことは、リモートからのゼロクリック実行と同じではありません。[1], [2]

ステップ 3

Java class pathをURLへ変換する

修正前はtranslateToUrlsが展開済みの項目をJava URLコンストラクターに渡し、スキームがローカルファイルか確認していませんでした。[4]

ステップ 4

指定されたドライバーが読み込まれる可能性がある

ベンダー勧告はこのJava読み込み経路を説明しています。影響は文書、設定、Java連携に左右されるため、すべてのCalc文書や環境が同じように悪用可能とは限りません。[1], [2]

ステップ 5

修正版は別のスキームを拒否する

LibreOffice 26.2.5.2はURIを解析し、スキームがfileでなければURL作成前に例外を発生させます。ベンダーまたはディストリビューションの修正版を導入してください。[5], [1]

ソースコード比較:脆弱 vs 堅牢化

これらの抜粋は、バージョンを固定したupstreamのtranslateToUrls実装から採っています。26.2.4.2は項目を展開した後、そのままJava URLを作成します。26.2.5.2ではURI解析を追加し、URL作成前にfile以外のスキームを拒否します。差分はスキーム検証を示し、ベンダー勧告はCalc/JDBC文書経路を裏付けます。これはソース分析であり、実行可能な概念実証ではありません。[4], [5], [1]

ソース抜粋: jvmaccess/source/classpath.cxx — translateToUrls関数

脆弱な実装
// LibreOffice 26.2.4.2 — jvmaccess/source/classpath.cxx(脆弱なバージョン)
if (!url.isEmpty()) {
    css::uno::Reference< css::uri::XVndSunStarExpandUrlReference >
        expUrl(
            css::uri::UriReferenceFactory::create(context)->parse(url),
            css::uno::UNO_QUERY);
    if (expUrl.is()) {
        css::uno::Reference< css::util::XMacroExpander > expander =
            css::util::theMacroExpander::get(context);
        try {
            url = expUrl->expand( expander );
        } catch (const css::lang::IllegalArgumentException & e) {
            css::uno::Any anyEx = cppu::getCaughtException();
            throw css::lang::WrappedTargetRuntimeException(
                "com.sun.star.lang.IllegalArgumentException: "
                 + e.Message,
                 nullptr, anyEx );
        }
    }
    jvalue arg;
    arg.l = environment->NewString(
        reinterpret_cast< jchar const * >(url.getStr()),
        static_cast< jsize >(url.getLength()));
    if (arg.l == nullptr) {
        return nullptr;
    }
    jobject o(environment->NewObjectA(classUrl, ctorUrl, &arg));
    if (o == nullptr) {
        return nullptr;
    }
    urls.push_back(o);
}
堅牢化されたセキュアパッチ
// LibreOffice 26.2.5.2 — jvmaccess/source/classpath.cxx(修正済みバージョン)
if (!url.isEmpty()) {
    css::uno::Reference< css::uri::XVndSunStarExpandUrlReference >
        expUrl(
            css::uri::UriReferenceFactory::create(context)->parse(url),
            css::uno::UNO_QUERY);
    if (expUrl.is()) {
        css::uno::Reference< css::util::XMacroExpander > expander =
            css::util::theMacroExpander::get(context);
        try {
            url = expUrl->expand( expander );
        } catch (const css::lang::IllegalArgumentException & e) {
            css::uno::Any anyEx = cppu::getCaughtException();
            throw css::lang::WrappedTargetRuntimeException(
                "com.sun.star.lang.IllegalArgumentException: "
                 + e.Message,
                 nullptr, anyEx );
        }
    }
    css::uno::Reference< css::uri::XUriReference > uriRef(
        css::uri::UriReferenceFactory::create(context)->parse(url));
    if (!uriRef.is() || !uriRef->getScheme().equalsIgnoreAsciiCase("file"))
    {
        throw css::lang::IllegalArgumentException(
            "non-local Java class path entry: " + url,
            css::uno::Reference< css::uno::XInterface >(), 0);
    }
    jvalue arg;
    arg.l = environment->NewString(
        reinterpret_cast< jchar const * >(url.getStr()),
        static_cast< jsize >(url.getLength()));
    if (arg.l == nullptr) {
        return nullptr;
    }
    jobject o(environment->NewObjectA(classUrl, ctorUrl, &arg));
    if (o == nullptr) {
        return nullptr;
    }
    urls.push_back(o);
}

エンジニアリング&システム堅牢化チェックリスト

参考資料