前世
漏洞的最终利用方式和 CVE-2024-20931
、CVE-2023-21839
一致,都是利用 IIOP -> JNDI 去造成远程代码执行,不过在整个触发的过程中有所不同。
这两次利用都是以weblogic.jndi.internal.BasicNamingNode#lookupSharable
为入口,在resolveObject
里触发jndi注入,具体的调用这里就不细讲了。
今生
这里我把目光放在下面的方法里,当restOfName
长度不为0,并且object
类型不为BasicNamingNode
,就会走到else判断里
这里的name
是lookup
传入的name
值,object
是lookup
的对象
这里需要看一下restOfName
如何赋值,getRest
方法如下
private String getRest(String name) throws NamingException {
int nameLength = name.length();
if (nameLength == 0) {
return name;
} else {
char firstChar = name.charAt(0);
int i;
if (firstChar == '"') {
i = name.indexOf(34, 1);
this.checkQuoteClose(i, name);
++i;
if (i < nameLength && this.isSeparator(name.charAt(i))) {
++i;
}
return name.substring(i);
} else if (firstChar == '\'') {
i = name.indexOf(39, 1);
this.checkQuoteClose(i, name);
++i;
if (i < nameLength && this.isSeparator(name.charAt(i))) {
++i;
}
return name.substring(i);
} else {
for(i = 0; i < nameLength; ++i) {
char currentChar = name.charAt(i);
switch (currentChar) {
case '"':
case '\'':
throw new InvalidNameException("Unescaped quote in a component");
case '\\':
++i;
if (i == nameLength) {
throw new InvalidNameException("An escape at the end of a name must be escaped");
}
break;
default:
if (this.isSeparator(currentChar)) {
return name.substring(i + 1);
}
}
}
return "";
}
}
}
当name
的第一个字符是'
、"
或者name
里存在.
和/
就能解析出rest
,于是我们跟进getContinuationCtx
方法,这里先调用了JNDIUtils.isValidReferenceObject
跟进isValidReferenceObject
,继续调用isValidJndiScheme
通过调用processURLAddrs
方法提取出ref对象里的classFactoryLocation
属性,然后判断classFactoryLocation
允许的协议-jndiAllowScheme
,允许的协议默认为空,也就是说不允许利用远程http协议地址让jndi去加载远程class。
回到getContinuationCtx
方法,继续调用 javax.naming.spi.NamingManager#getContinuationContext
,走到原生的jndi
流程里。
一直跟到javax.naming.spi.NamingManager#getObjectInstance
寻找本地ObjectFactory
跟进getObjectFactoryFromReference
,首先进行factory
本地加载,如果加载不到,去加载远程class
,但是前面已经提到,无法加载远程class
,因为classFactoryLocation
不被允许使用任何协议
于是,只能去考虑本地ObjectFactory
,如果这里返回的ObjectFactory
,在后续调用factory.getObjectInsatce
方法里,存在恶意调用,那么也可以进行利用。最终,寻找到了一个可以利用的ObjectFactory
,weblogic.application.naming.MessageDestinationObjectFactory
来看下他的getObjectInstance
方法,obj
就是lookup
的对象
调用对象的lookupMessageDestination
并且这里的jndiName
是实例里的属性,可控,所以最终造成jndi
注入。
时间线
- 2024-03-29 漏洞提交至Oracle
- 2024-04-16 Oracle发布补丁通告