Apache-Poi-XXE-Analysis

2019-12-28 约 506 字 预计阅读 3 分钟

声明:本文 【Apache-Poi-XXE-Analysis】 由作者 l1nk3r 于 2019-12-28 11:46:07 首发 先知社区 曾经 浏览数 332 次

感谢 l1nk3r 的辛苦付出!

0x01 概述

apache poi 这个组件实际上在 java 应用中蛮常见的,这个组件主要用在 word 文档或者 excel 文件导入的业务场景下使用。众所周知,这些文档实际上也是一个类似压缩包一类的存在,所以今天就看看这个东西。

0x02 漏洞分析

CVE-2014-3529

apache poi 在3.10.1之前存在XXE漏洞

漏洞场景搭建

测试代码

import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import java.io.FileInputStream;
import java.io.IOException;
public class CVE20143529 {
    public static void main(String[] args) throws IOException, EncryptedDocumentException, InvalidFormatException {
        Workbook wb1 = WorkbookFactory.create(new FileInputStream("test.xlsx"));
        Sheet sheet = wb1.getSheetAt(0);
        System.out.println(sheet.getLastRowNum());
    }
}
//pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.apache.poi</groupId>
    <artifactId>xxe</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.10-FINAL</version>
        </dependency>
    </dependencies>

</project>

漏洞复现

修改 excel 文件中的 [Content_Types].xml/xl/workbook.xml/xl/worksheets/shee1.xml 中均可添加 xxepayload 触发漏洞,我选择在 [Content_Types].xml 文件中添加。

漏洞分析

选择在WorkbookFactory.create处下一个断点,一步步跟入,来到了 OPCPackage 这个类中。

public static OPCPackage open(InputStream in) throws InvalidFormatException, IOException {
        OPCPackage pack = new ZipPackage(in, PackageAccess.READ_WRITE);
        if (pack.partList == null) {
            pack.getParts();
        }
        return pack;
    }

在这个累里,首先new了一个 ZipPackage 类来解析输入,跟进来很明显是个处理 zip 这类型压缩包的东西。

ZipPackage(InputStream in, PackageAccess access) throws IOException {
        super(access);
        this.zipArchive = new ZipInputStreamZipEntrySource(new ZipInputStream(in));
    }

继续往下走,看到了一个if里面调用了pack.getParts();方法,跟进 getParts

public ArrayList<PackagePart> getParts() throws InvalidFormatException {
        this.throwExceptionIfWriteOnly();
        if (this.partList == null) {
            boolean hasCorePropertiesPart = false;
            boolean needCorePropertiesPart = true;
            PackagePart[] parts = this.getPartsImpl();

这里不知道漏洞触发点在哪,自然就一步步跟了,首先看到了一个this.getPartsImpl(),跟进这个方法,在这个方法里面看到了一个很眼熟的东西,我们刚刚是在 [Content_Types].xml 文件中添加的payload,这里出现了这个文件。

继续跟进 ZipContentTypeManager 这个类,跟进之后才发现,它调用的是它的父类 ContentTypeManager 来进行处理。

public ZipContentTypeManager(InputStream in, OPCPackage pkg) throws InvalidFormatException {
        super(in, pkg);
    }

跟进 ContentTypeManager ,下图中 parseContentTypesFile 处理了我们的输入。

跟进 parseContentTypesFile 终于找到了XXE的触发点。

贴一个调用栈

parseContentTypesFile:377, ContentTypeManager (org.apache.poi.openxml4j.opc.internal)
<init>:105, ContentTypeManager (org.apache.poi.openxml4j.opc.internal)
<init>:56, ZipContentTypeManager (org.apache.poi.openxml4j.opc.internal)
getPartsImpl:188, ZipPackage (org.apache.poi.openxml4j.opc)
getParts:665, OPCPackage (org.apache.poi.openxml4j.opc)
open:274, OPCPackage (org.apache.poi.openxml4j.opc)
create:79, WorkbookFactory (org.apache.poi.ss.usermodel)
main:12, CVE20143529

漏洞修复

可以看到修复方式将 xmlReader.read(in) 变成了 SAXHelper.readSAXDocument(in)

private void parseContentTypesFile(InputStream in) throws InvalidFormatException {
        try {
            Document xmlContentTypetDoc = SAXHelper.readSAXDocument(in);

然后在 org.apache.poi.util.SAXHelper 中做了一些 xxe 的限制。

CVE-2019-12415

In Apache POI up to 4.1.0, when using the tool XSSFExportToXml to convert user-provided Microsoft Excel documents, a specially crafted document can allow an attacker to read files from the local filesystem or from internal network resources via XML External Entity (XXE) Processing.

漏洞场景搭建

测试代码:

import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.xssf.extractor.XSSFExportToXml;
import org.apache.poi.xssf.usermodel.XSSFMap;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.xml.sax.SAXException;

import javax.xml.transform.TransformerException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class PoiXxe {
    public static void main(String[] args) throws IOException, EncryptedDocumentException, InvalidFormatException, TransformerException, SAXException {
        XSSFWorkbook wb = new XSSFWorkbook(new FileInputStream(new File("/Users/l1nk3r/Desktop/CustomXMLMappings.xlsx")));
        for (XSSFMap map : wb.getCustomXMLMappings()) {
            XSSFExportToXml exporter = new XSSFExportToXml(map); // 使用 XSSFExportToXml 将 xlsx 转成 xml
            exporter.exportToXML(System.out, true);//第一个参数是输出流无所谓,第二个参数要为 true
        }
    }
}
//pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.apache.poi</groupId>
    <artifactId>xxe</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>4.1.0</version>
        </dependency>
    </dependencies>
</project>

漏洞复现

下载这个excel文件,在 CustomXMLMappings/xl/xmlMaps.xml 文件中增加下面这个代码

<xsd:redefine schemaLocation="http://127.0.0.1:8080/"></xsd:redefine>


漏洞分析

调用栈太繁琐了,只列几个关键点,程序进行到 XSDHandler#constructTrees 这个方法的时候,抓出来我们poc中的外带地址。

下一步在 XSDHandler#resolveSchema 中,把外带地址交给了 getSchemaDocument 处理。

最后代码继续往下走,在 XMLEntityManager#setupCurrentEntity 找到了http的请求发起,所以想知道一个XXE漏洞的调用栈,绝大多数情况下,你可以选择在JDK自身的 XMLEntityManager#setupCurrentEntity 中HTTP请求下个断点,然后利用OOB方式利用,很多找到触发过程的调用栈。

setupCurrentEntity:619, XMLEntityManager (com.sun.org.apache.xerces.internal.impl)
determineDocVersion:189, XMLVersionDetector (com.sun.org.apache.xerces.internal.impl)
parse:582, SchemaParsingConfig (com.sun.org.apache.xerces.internal.impl.xs.opti)
parse:685, SchemaParsingConfig (com.sun.org.apache.xerces.internal.impl.xs.opti)
parse:530, SchemaDOMParser (com.sun.org.apache.xerces.internal.impl.xs.opti)
getSchemaDocument:2175, XSDHandler (com.sun.org.apache.xerces.internal.impl.xs.traversers)
resolveSchema:2096, XSDHandler (com.sun.org.apache.xerces.internal.impl.xs.traversers)
constructTrees:1100, XSDHandler (com.sun.org.apache.xerces.internal.impl.xs.traversers)
parseSchema:620, XSDHandler (com.sun.org.apache.xerces.internal.impl.xs.traversers)
loadSchema:617, XMLSchemaLoader (com.sun.org.apache.xerces.internal.impl.xs)
loadGrammar:575, XMLSchemaLoader (com.sun.org.apache.xerces.internal.impl.xs)
loadGrammar:541, XMLSchemaLoader (com.sun.org.apache.xerces.internal.impl.xs)
newSchema:255, XMLSchemaFactory (com.sun.org.apache.xerces.internal.jaxp.validation)
newSchema:638, SchemaFactory (javax.xml.validation)
isValid:249, XSSFExportToXml (org.apache.poi.xssf.extractor)
exportToXML:211, XSSFExportToXml (org.apache.poi.xssf.extractor)
exportToXML:105, XSSFExportToXml (org.apache.poi.xssf.extractor)
main:20, PoiXxe

漏洞修复

修复的方式增加了一行。

trySetFeature(factory, "http://javax.xml.XMLConstants/feature/secure-processing", true);


然后问题关键点就来到了 SecuritySupport#checkAccess ,可以看到未修复代码 allowedProtocols 是all,而 acessAny 也是all,所以 checkAccess 结果返回的是null。

已修复代码中的 SecuritySupport#checkAccess 方法,可以看到未修复代码 allowedProtocols 是"",而 acessAny 也是all,所以 checkAccess 结果返回的是 http

回到 XSDHandler#getSchemaDocument 中,由于不允许http方式外带数据,因此我们的错误信息自然会出现下图报错里面的部分。


最后在简单bb一下,这个洞没啥用,外带也没办法利用FTP client换行那个洞外带数据,所以是个弟中弟的洞。

Rerfence

Apache POI <= 4.1.0 XXE 漏洞 (CVE-2019-12415)

关键词:[‘安全技术’, ‘WEB安全’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now