关于XEE
漏洞原理
  Java中XML内容的解析主要依赖于其丰富的库。XML 的解析过程中若允许加载外部实体,若不添加安全的XML解析配置,则XML文档将包含来自外部 URI 的数据,将会导致XEE。
Java中的XXE支持以下协议:http,https,file,ftp,mailto,jar,netdoc。
可以利用file协议读取文件,利用http协议探测内网,没有回显时可组合利用file协议和ftp协议来读取文件。如果存在报错的情况下还可以尝试使用报错XXE进行敏感信息的获取。甚至是尝试递归调用造成拒绝服务攻击。
XML解析涉及的业务功能点
- WebServices接口
- RESTful接口
- Excel文件解析
- Soap协议
- ......
凡是可以解析XML数据的地方都可能存在XXE。
挖掘思路
若相关解析接口的解析内容用户可控,需检查使用XML解析器时是否设置了相关的安全属性,禁用DTDs或者禁止使用外部实体。还有是否使用了不安全的漏洞组件。
常见的XML解析库
- javax.xml.stream.XMLStreamReader
- javax.xml.parsers.DocumentBuilderFactory
- org.dom4j.io.SAXReader
- org.xml.sax.helpers.XMLReaderFactory
- javax.xml.parsers.SAXParser
- javax.xml.parsers.DocumentBuilder
- org.jdom.input.SAXBuilder
- org.dom4j.DocumentHelper
- org.jdom.output.XMLOutputter
- ......
常见漏洞组件
- xlsx-streamer.jar-2.0.0及以下版本
- poi-ooxml-3.10-FINAL.及以下版本(CVE-2014-3529)
- poi-ooxml-3.13-FINAL.及以下版本(CVE-2016-5000)
- poi-ooxml-3.15.jar 及以下版本(CVE-2017-5644(拒绝服务))
- ......
漏洞示例
以解析如下内容为例,根据常用的XML解析器,列举几个未做任何措施的case:
(1)JAXP:
java
import java.io.File;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/*
*JAXP DOM解析
*/
public class Demo1 {
public static void main(String[] args) throws Exception {
//调用DocumentBuilderFactory.newInstance()方法得到创建DOM解析器的工厂
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
//调用工厂对象的newDocumentBuilder方法得到DOM解析器对象
DocumentBuilder builder = builderFactory.newDocumentBuilder();
//解析指定的文件
File file =new File("./src/test.xml");
Document doc = builder.parse(file);
//获取根节点的元素对象
Element root = doc.getDocumentElement();
//遍历子节点
ListNodes(root);
}
}
(2)JDOM:
java
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import org.jdom2.Attribute;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
/*
* Jdom解析XML
*/
public class Demo2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
//1.创建一个SAXBuilder的对象
SAXBuilder builder =new SAXBuilder();
try {
// 2.创建一个输入流,将xml文件加载到输入流中
InputStream in = new FileInputStream("./src/test.xml");
// 3.通过saxBuilder的build方法,将输入流加载到saxBuilder中
Document document = builder.build(in);
// 4.通过document对象获取xml文件的根节点
Element rootElement = document.getRootElement();
// 5.获取根节点下的子节点的List集合
List<Element> List = rootElement.getChildren();
for (Element test : List) {
......
......
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JDOMException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
(3)Dom4j:
java
import java.io.File;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;
import org.xml.sax.SAXException;
public class Demo3 {
public static void main(String[] args) throws SAXException {
try {
SAXReader reader = new SAXReader();
Document doc = reader.read(new File("./src/test.xml"));
System.out.println(doc.asXML());
} catch (DocumentException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
(4)SAX:
java
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
public class Demo4 {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
// 获取SAX解析工厂
SAXParserFactory factory = SAXParserFactory.newInstance();
// 通过工厂获取SAX解析器
SAXParser parser = factory.newSAXParser();
// 获取XML阅读器
XMLReader reader = parser.getXMLReader();
// 关联事件解析器
reader.setContentHandler(new MyContentHandler());
// 解析XML文件
reader.parse("./src/test.xml");
}
}
上述case由于没有设置相关的安全属性,禁用DTDs或者禁止使用外部实体,所以可以通过file协议读取/etc/passwd内容,具体效果:
相关案例
以CVE-2014-3529为例:
xlsx文件其实是一个压缩包,其中包含一些xml文件:
在进行xlsx文件解析时,主要是通过ZipContentTypeManager进行解析的。其继承了ContentTypeManager,实例化方法如下:
```java
public class ZipContentTypeManager extends ContentTypeManager
{
private static POILogger logger = POILogFactory.getLogger(ZipContentTypeManager.class);
public ZipContentTypeManager(InputStream in, OPCPackage pkg)
throws InvalidFormatException
{
super(in, pkg);
}
......
}
```
因为继承了ContentTypeManager类,所以查看其实例化方法:
```java
public abstract class ContentTypeManager
{
public static final String CONTENT_TYPES_PART_NAME = "[Content_Types].xml";
public static final String TYPES_NAMESPACE_URI = "http://schemas.openxmlformats.org/package/2006/content-types";
private static final String TYPES_TAG_NAME = "Types";
private static final String DEFAULT_TAG_NAME = "Default";
private static final String EXTENSION_ATTRIBUTE_NAME = "Extension";
private static final String CONTENT_TYPE_ATTRIBUTE_NAME = "ContentType";
private static final String OVERRIDE_TAG_NAME = "Override";
private static final String PART_NAME_ATTRIBUTE_NAME = "PartName";
protected OPCPackage container;
private TreeMap defaultContentType;
private TreeMap overrideContentType;
public ContentTypeManager(InputStream in, OPCPackage pkg)
throws InvalidFormatException
{
this.container = pkg;
this.defaultContentType = new TreeMap();
if (in != null) {
try
{
parseContentTypesFile(in);
}
catch (InvalidFormatException e)
{
throw new InvalidFormatException("Can't read content types part !");
}
}
}
......
}
```
其中调用了parseContentTypesFile方法,将相关xlsx文件的InputStream对象传入进行解析:
```java
......
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Namespace;
import org.dom4j.QName;
import org.dom4j.io.SAXReader;
private void parseContentTypesFile(InputStream in)
throws InvalidFormatException
{
try
{
SAXReader xmlReader = new SAXReader();
Document xmlContentTypetDoc = xmlReader.read(in);
List defaultTypes = xmlContentTypetDoc.getRootElement().elements("Default");
Iterator elementIteratorDefault = defaultTypes.iterator();
while (elementIteratorDefault.hasNext())
{
Element element = (Element)elementIteratorDefault.next();
String extension = element.attribute("Extension").getValue();
String contentType = element.attribute("ContentType").getValue();
addDefaultContentType(extension, contentType);
}
List overrideTypes = xmlContentTypetDoc.getRootElement().elements("Override");
Iterator elementIteratorOverride = overrideTypes.iterator();
while (elementIteratorOverride.hasNext())
{
Element element = (Element)elementIteratorOverride.next();
URI uri = new URI(element.attribute("PartName").getValue());
PackagePartName partName = PackagingURIHelper.createPartName(uri);
String contentType = element.attribute("ContentType").getValue();
addOverrideContentType(partName, contentType);
}
}
catch (URISyntaxException urie)
{
throw new InvalidFormatException(urie.getMessage());
}
catch (DocumentException e)
{
throw new InvalidFormatException(e.getMessage());
}
}
```
可以看到使用SAXReader 来解析xml文档,由于没有设置相关的安全属性,存在XXE风险。
修复建议
关于XML Reader修复可参考:
以DocumentBuilderFactory举例:
禁止DTDS解析:
java
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
使用安全处理模式避免ssrf和文件读取:
java
dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
不包括外部通用实体:
java
dbf.setFeature("http://xml.org/sax/features/external- general-entities", false);
不包括外部实体或外部DTD子集:
java
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
忽略外部DTD:
java
factory.setFeature("http://apache.org/xml/features/nonvalidati ng/load-external-dtd", false);
关于相关的漏洞漏洞组件:
- 如果系统使用了低版本POI库,导致处理Excel文件时存在XXE和SSRF漏洞,升级该库,必须大于3.14版本
- 如果系统使用了Excel Streaming Reader <= 2.0.0 XXE 中,升级该库,必须大于2.0.0版本
相关推荐: 如何优雅的在Linux上使用Powershell]
译文声明 本文是翻译文章,文章原作者 TJ Null,文章来源:https://www.offensive-security.com 原文地址:https://www.offensive-security.com/offsec/kali-linux-power…
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论