本文作者:r00t4dm@Cloud-Penetrating Arrow Lab & Longofo@知道创宇404实验室
OFBiz PMC针对CVE-2021-26295漏洞修复的commit如下:
@Override protected Class<?> resolveClass(ObjectStreamClass classDesc) throws IOException, ClassNotFoundException { String className = classDesc.getName(); // BlackList exploits; eg: don't allow RMI here if (className.contains("java.rmi.server")) { Debug.logWarning("***Incompatible class***: " + classDesc.getName() + ". java.rmi.server classes are not allowed for security reason", "SafeObjectInputStream"); return null; } if (!whitelistPattern.matcher(className).find()) { // DiskFileItem, FileItemHeadersImpl are not serializable. if (className.contains("org.apache.commons.fileupload")) { return null; } Debug.logWarning("***Incompatible class***: "
我提交给OFBiz社区的利用方式是RemoteObjectInvocationHandler作为JRMPClient,这个补丁代码也刚好解决了RemoteObjectInvocationHandler作为JRMPClient的利用方式,并分配了CVE-2021-26295。
令我感兴趣的是当检测到敏感对象时它并不是抛出异常,而是返回null,我询问了PMC并得到这样的答复
That's purely syntactic (proof it works as is). I used null for a reason and I have to check what it entails to replace null by an exception. Else I'd be happy to replace it
这种返回null的修复方式本身是没有问题的,只是检测边界需要扩大,如果检测边界不变那必须抛出异常。
所以这个补丁的代码是存在问题的,通过使用java.下的代码可以绕过白名单。
private static final String[]DEFAULT_WHITELIST_PATTERN= { "byte\\[\\]", "foo", "SerializationInjector", "\\[Z", "\\[B", "\\[S", "\\[I", "\\[J", "\\[F", "\\[D", "\\[C", "java..*", "sun.util.calendar..*", "org.apache.ofbiz..*", "org.codehaus.groovy.runtime.GStringImpl", "groovy.lang.GString"};
接着需要找一个符合白名单并且是远程对象的类,通过使用LiveRef打开通道,值得注意的是sun.rmi.server.UnicastRef是连接的抽象或者封装,所以这里可以直接使用sun.rmi.server.UnicastRef即可。
我第二次交给OFBiz社区的利用对象是javax.management.remote.rmi.RMIConnectionImpl_Stub,因为javax.management.remote.rmi.RMIConnectionImpl_Stub符合白名单正则表达式,又由于反序列化的递归性质,父类反序列化为空不影响子类反序列化流程,所以使用javax.management.remote.rmi.RMIConnectionImpl_Stub可以绕过这个补丁。
后续我针对这个问题给官方提供的补丁代码是
if (className.contains("java.rmi.server")) { Debug.logWarning("***Incompatible class***: " + classDesc.getName() + ". java.rmi.server classes are not allowed for security reason", "SafeObjectInputStream"); // return null; throw new InvalidObjectException("no safe!!" + className); }
并要求OFBiz社区关闭SOAP和HTTPEngine的入口,我想这个Endpoint应该不会有问题了。