本文作者: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应该不会有问题了。