WebLogic RCE(CVE-2019-2725)漏洞之旅

释放双眼,带上耳机,听听看~!
4172019年4月17日,CNVD发布《关于OracleWebLogicwls9-async组件存在反序列化远程命令执行漏洞的安全公告》,公告指出部分版本WebLogic中默认包含的wls9_async_response包,为WebLogicServer提供异步通讯服务。由于该WAR包在反

417

2019年4月17日,CNVD 发布《关于Oracle WebLogic wls9-async组件存在反序列化远程命令执行漏洞的安全公告》,公告指出部分版本WebLogic中默认包含的wls9_async_response包,为WebLogic Server提供异步通讯服务。由于该WAR包在反序列化处理输入信息时存在缺陷,攻击者可以发送精心构造的恶意 HTTP 请求,获得目标服务器的权限,在未授权的情况下远程执行命令。

418

2019年4月18日,开始应急。因为这个漏洞当时属于0day,也没有补丁可以参考,只能参考公告内容一步一步来看了。首先看到公告里提到的wls9_async_response.war包,看下web.xml里的url。

看到/AsyncResponseService,尝试访问一下,404。之后看到weblogic.xmlweblogic-webservices.xml

访问下_async/AsyncResponseService

可以正常访问,再结合公告中的漏洞处置建议,禁止 /_async/* 路径的URL访问,可以大概率猜测,漏洞入口在这里。

weblogic-webservices.xml中有一个类,weblogic.wsee.async.AsyncResponseBean,跟进去这个类,发现在wseeclient.jar里面

而后我在这个类里面的方法下断点,然后构造一个普通的SOAP消息,发送。

断点没有debug到。最后我把wsee/async所有类的所有方法都下了断点,重新发送消息,成功在AsyncResponseHandler类中的handleRequest拦截到了。

继续流程,String var2 = (String)var1.getProperty("weblogic.wsee.addressing.RelatesTo");这个步骤一直取不到值,导致流程结束。为了解决这个问题,翻了不少资料,最后找到一个类似的例子,可以使用<ads:RelatesTo>test</ads:RelatesTo>weblogic.wsee.addressing.RelatesTo赋值。

<?xml version="1.0" encoding="UTF-8" ?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ads="http://www.w3.org/2005/08/addressing">
  <soapenv:Header>
    <ads:Action>demo</ads:Action>
    <ads:RelatesTo>test</ads:RelatesTo>
</soapenv:Header>
  <soapenv:Body></soapenv:Body>
</soapenv:Envelope>

之后流程就能够继续下去了,我一直以为漏洞的关键点在这里,因为这个wsee.async下面的几个类中有readObject方法,我一直尝试着通过AsyncResponseHandler跳到readObject方法,而后就卡在这里,后面的流程就不写了,对这个漏洞来说是错的,上面写的这些猜测和流程都是正确的。

419

2019年4月19日,和我一起应急的师傅给我发了一张截图。

看到这截图里面的RelatesTo,我还以为之前的推测没有错,只是没有构造好。

全局搜索UnitOfWorkChangeSet这个类,之后在这个类中下断点。

根据截图,构造一个类似的,然后发送

在这个类中debug到了。

看到了日思夜想的readObject,有了反序列的点,自然要找利用链了,目前 WebLogic 下面 commoncollections 相关的利用链已经是无法使用了,WebLoigc 依赖的common-collections版本已经升级了,先找个Jdk7u21测试一下,将生成的 payload 转换成 byte,发送。

可以看到,成功地执行了命令。但是这个利用链限制太大了,基本没啥用。我想起去年应急过的一个WebLogic 反序列漏洞,CVE-2018-3191,既然jdk7u21都不受黑名单限制,想来CVE-2018-3191也是一样可以利用的。

猜测没有错误,CVE-2018-3191也是能够利用的,这个漏洞也终于有点"危害"了。和 pyn3rd 师傅讨论一下有没有其他利用链,仔细翻下黑名单,除了CVE-2018-3191,就只有新的jython利用链(CVE-2019-2645)了,由 Matthias Kaiser大佬提交的,但是目前这个还有没有公开,所以这个利用链也没法使用。

有了正确答案,就可以看下之前的猜测哪里出了问题。

回到AsyncResponseHandler类中的handleRequesthandleRequest的上一步,HandlerIterator类中的handleRequest方法

    public boolean handleRequest(MessageContext var1, int var2) {
        this.closureEnabled = false;
        this.status = 1;
        WlMessageContext var3 = WlMessageContext.narrow(var1);
        if (verboseHistory) {
            updateHandlerHistory("...REQUEST...", var3);
        }

        for(this.index = var2; this.index < this.handlers.size(); ++this.index) {
            Handler var4 = this.handlers.get(this.index);
            if (verbose) {
                Verbose.log("Processing " + var4.getClass().getSimpleName() + "...  ");
            }

            if (verboseHistory) {
                updateHandlerHistory(var4.getClass().getSimpleName(), var3);
            }

            HandlerStats var5 = this.handlers.getStats(this.index);

            try {
                var3.setProperty("weblogic.wsee.handler.index", new Integer(this.index));
                String var6;
                if (!var4.handleRequest(var3)) {
                    if (verboseHistory) {
                        var6 = var4.getClass().getSimpleName() + ".handleRequest=false";
                        updateHandlerHistory(var6, var3);
                    }

                    if (var5 != null) {
                        var5.reportRequestTermination();
                    }

                    return false;
                }

会遍历this.handlers,然后调用每个handlerhandleRequest去处理用户传入的SOAP Message。

可以看到,AsyncResponseHandler仅仅只是21个handler之中的一个,而weblogic.wsee.addressing.RelatesTo的赋值就是在ServerAddressingHandler中完成的,有兴趣的可以去跟一下。这里面有一个非常重要的handlerWorkAreaServerHandler,看名字可能觉得眼熟,看到里面的handleRequest方法可能就不淡定了。

之后的流程就和CVE-2017-10271是一样的了,关于这个漏洞的分析可以参考廖师傅的文章

跟到这里就可以看出来了,这个url只是CVE-2017-10271漏洞的另外一个入口而已。这也是后期导致假PoC泛滥的一个原因。整个流程大概如下:

那么问题来了,这个PoC是如何绕过CVE-2017-10271的黑名单的呢?

首先来看一下CVE-2017-10271的补丁,会将传入的数据先调用validate校验,通过之后才交给XMLDecoder

public WorkContextXmlInputAdapter(InputStream var1) {
        ByteArrayOutputStream var2 = new ByteArrayOutputStream();

        try {
            boolean var3 = false;

            for(int var5 = var1.read(); var5 != -1; var5 = var1.read()) {
                var2.write(var5);
            }
        } catch (Exception var4) {
            throw new IllegalStateException("Failed to get data from input stream", var4);
        }

        this.validate(new ByteArrayInputStream(var2.toByteArray()));
        this.xmlDecoder = new XMLDecoder(new ByteArrayInputStream(var2.toByteArray()));
    }

    private void validate(InputStream var1) {
        WebLogicSAXParserFactory var2 = new WebLogicSAXParserFactory();

        try {
            SAXParser var3 = var2.newSAXParser();
            var3.parse(var1, new DefaultHandler() {
                private int overallarraylength = 0;

                public void startElement(String var1, String var2, String var3, Attributes var4) throws SAXException {
                    if (var3.equalsIgnoreCase("object")) {
                        throw new IllegalStateException("Invalid element qName:object");
                    } else if (var3.equalsIgnoreCase("new")) {
                        throw new IllegalStateException("Invalid element qName:new");
                    } else if (var3.equalsIgnoreCase("method")) {
                        throw new IllegalStateException("Invalid element qName:method");
                    } else {
                        if (var3.equalsIgnoreCase("void")) {
                            for(int var5 = 0; var5 < var4.getLength(); ++var5) {
                                if (!"index".equalsIgnoreCase(var4.getQName(var5))) {
                                    throw new IllegalStateException("Invalid attribute for element void:" + var4.getQName(var5));
                                }
                            }
                        }

                        if (var3.equalsIgnoreCase("array")) {
                            String var9 = var4.getValue("class");
                            if (var9 != null && !var9.equalsIgnoreCase("byte")) {
                                throw new IllegalStateException("The value of class attribute is not valid for array element.");
                            }

                            String var6 = var4.getValue("length");
                            if (var6 != null) {
                                try {
                                    int var7 = Integer.valueOf(var6);
                                    if (var7 >= WorkContextXmlInputAdapter.MAXARRAYLENGTH) {
                                        throw new IllegalStateException("Exceed array length limitation");
                                    }

                                    this.overallarraylength += var7;
                                    if (this.overallarraylength >= WorkContextXmlInputAdapter.OVERALLMAXARRAYLENGTH) {
                                        throw new IllegalStateException("Exceed over all array limitation.");
                                    }
                             &a

给TA买糖
共{{data.count}}人
人已赞赏
HackerNews

2050大会:360安全基因助力科技青年“天马行空”

2019-5-2 9:37:10

HackerNews

浅谈RASP技术攻防之实战[环境配置篇]

2019-5-6 5:13:42

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索