目录导航
Weblogic CVE-2023-21931漏洞探索技术:反序列化后利用
概述
近年来,Weblogic反序列化漏洞不断被发现,并集中在反序列化的触发点上。但是,有很多涉及到反序列化但不能被实时利用的点,在常规的漏洞研究中很容易被忽视。业界对“反序列化后”漏洞有进一步的讨论,看似无法利用的漏洞实际上可以通过后续技术加以利用。比如执行bind()orrebind()操作后没有触发漏洞,可以尝试lookup()or等其他方式 lookupLink()触发漏洞。
通过这种方式,我们发现了两个Weblogic后反序列化漏洞(CVE-2023-21931、CVE-2023-21839),已经得到Oracle官方确认。在本文中,我们将以这两个Weblogic漏洞为例,分享利用后反序列化漏洞背后的思考过程。我们相信未来还有很多类似的漏洞会逐渐被发现,希望本文能为研究人员提供一些启发。
反序列化漏洞

利用 Weblogic 反序列化漏洞的方法涉及使用readObject()、readResolve()、readExternal()等反序列化方法来操纵恶意制作的序列化数据,以达到攻击者的目的。传统的漏洞研究侧重于在反序列化过程中利用 Weblogic,而忽略了反序列化后阶段。反序列化后漏洞研究的重点是识别反序列化过程完成后由某些操作或事件触发的漏洞。
bind()在Weblogic中,如果操作后没有触发漏洞,可以尝试通过和rebind()等其他方式触发漏洞。lookup()lookupLink()
本文将分析攻击过程并提供Weblogic中反序列化后漏洞的示例,重点介绍lookup()作为漏洞触发器的方法。
lookup
通过跟踪调用栈,我们发现该lookup()方法的流程如下:
- 收到请求后,Weblogic 使用类
invoke()中的方法解析传入的数据BasicServerRef。 - 使用该
_invoke()方法,Weblogicresolve_any()根据传入的方法名执行该方法resolve_any。 - 在
resolve_any()方法中,使用方法解析传入的绑定名称resolveObject()。 - 在
resolveObject()方法中,lookup()根据上下文信息调用方法。 - 根据上下文信息,在、、、、 等
lookup()类中进行一系列的方法调用,从而产生类中的方法调用。WLContextImplWLEventContextImplRootNamingNodeServerNamingNodeBasicNamingNoderesolveObject()BasicNamingNode - 由于
obj传入resolveObject()方法的不是NamingNode类的实例,并且mode值默认为1,所以调用了类getObjectInstance()中的方法。WLNamingManager
最后可以看出,类getObjectInstance()中的方法是根据对象接口类型调用传入对象中的方法,完成漏洞触发点中方法的调用。事实上,这两个 CVE 漏洞都是通过.WLNamingManagergetReferent()lookup()getObjectInstance()
CVE-2023-21931
CVE-2023-21931的漏洞触发点在类getObjectInstance()的方法中WLNamingManager。当传入的boundObject对象是 的实现类时LinkRef,调用getLinkName()传入对象的方法,该方法用于对该方法返回的地址进行远程JNDI加载。在实例化类时,可以通过类的构造函数将 JNDI 地址传递给。这样我们就可以调用远程加载自定义JNDI地址的方法,达到攻击的目的。boundObjectlookup()linkAddrTypegetLinkName()LinkReflinkAddrTypelookup()
package weblogic.jndi.internal;
public final class WLNamingManager {
public static Object getObjectInstance(Object boundObject, Name name, Context ctx, Hashtable env) throws NamingException {
if (boundObject instanceof ClassTypeOpaqueReference) {
......
} else if (boundObject instanceof LinkRef) {
String linkName = ((LinkRef)boundObject).getLinkName();
InitialContext ic = null;
try {
ic = new InitialContext(env);
boundObject = ic.lookup(linkName); // vulnerability trigger point
} catch (NamingException var15) {
......
} finally {......}
}
}
}
该漏洞存在于类内构造 JNDI 地址LinkRef,该类是原生 Java 类。通过使用类的构造函数LinkRef,我们可以控制变量的值linkAddrType,然后使用该方法将其作为字符串getLinkName()返回。linkAddrType
package javax.naming;
public class LinkRef extends Reference {
static final String linkClassName = LinkRef.class.getName();
static final String linkAddrType = "LinkAddress";
public LinkRef(Name linkName) {
super(linkClassName, new StringRefAddr(linkAddrType, linkName.toString()));
}
public LinkRef(String linkName) {
super(linkClassName, new StringRefAddr(linkAddrType, linkName));
}
public String getLinkName() throws NamingException {
if (className != null && className.equals(linkClassName)) {
RefAddr addr = get(linkAddrType);
if (addr != null && addr instanceof StringRefAddr) {
return (String)((StringRefAddr)addr).getContent();
}
}
throw new MalformedLinkException();
}
}

在上述过程中,方法的反序列化过程rebind()并lookup()没有执行恶意操作。而是在完成反序列化过程后,通过调用类中lookup()方法的方法触发漏洞,对JNDI地址进行远程恶意加载。getObjectInstance()WLNamingManager
我们在 GOBY 中集成了 CVE-2023-21931 漏洞,并添加了命令执行和 shell 访问的功能。该漏洞的演示如下所示:

CVE-2023-21839
ForeignOpaqueReference是接口的实现类OpaqueReference。类中声明了两个私有变量jndiEnvironment和,还声明了两个构造函数。在参数化构造函数中,和分别被接收并赋值给上述两个私有类变量。remoteJNDINameForeignOpaqueReferenceenvremoteJNDIName
getReferent()类中的方法是接口ForeignOpaqueReference的实现方法OpaqueReference。方法中getReferent(),retVal = context.lookup(this.remoteJNDIName);远程加载remoteJNDIName该类变量中的JNDI地址,导致反序列化漏洞。
package weblogic.jndi.internal;
public class ForeignOpaqueReference implements OpaqueReference, Serializable {
private Hashtable jndiEnvironment;
private String remoteJNDIName;
......
public ForeignOpaqueReference(String remoteJNDIName, Hashtable env) {
this.remoteJNDIName = remoteJNDIName;
this.jndiEnvironment = env;
}
public Object getReferent(Name name, Context ctx) throws NamingException {
InitialContext context;
if (this.jndiEnvironment == null) {
context = new InitialContext();
} else {
Hashtable properties = this.decrypt();
context = new InitialContext(properties);
}
Object retVal;
try {
retVal = context.lookup(this.remoteJNDIName); // vulnerability point
} finally {
context.close();
}
return retVal;
}
......
}
getReferent()方法调用分析
package weblogic.jndi;
public interface OpaqueReference {
Object getReferent(Name var1, Context var2) throws NamingException;
String toString();
}
该OpaqueReference接口有两个抽象方法:getReferent()和toString()。
getReferent()类中的方法在类ForeignOpaqueReference中被调用WLNamingManager。
在类getObjectInstance()的方法中WLNamingManager,如果传入的boundObject对象实现了OpaqueReference接口,那么调用对象的getReferent()方法如下:boundObject = ((OpaqueReference)boundObject).getReferent(name, ctx);.
如前所述,ForeignOpaqueReference类实现了OpaqueReference接口,所以getReferent()调用了它的方法,导致反序列化漏洞。
package weblogic.jndi.internal;
public final class WLNamingManager {
public static Object getObjectInstance(Object boundObject, Name name, Context ctx, Hashtable env) throws NamingException {
if (boundObject instanceof ClassTypeOpaqueReference) {
......
} else if (boundObject instanceof OpaqueReference) {
boundObject = ((OpaqueReference)boundObject).getReferent(name, ctx);
} else if (boundObject instanceof LinkRef) {
...
}
}
}

与CVE-2023-21931漏洞类似,CVE-2023-21839在反序列化过程中不会执行任何恶意操作。相反,该漏洞是在反序列化过程完成后通过调用类的方法lookup()中的方法来触发的。getReferent()ForeignOpaqueReference
我们在 GOBY 中集成了 CVE-2023-21839 漏洞,并添加了命令执行和 shell 访问的功能。以下是该漏洞利用的演示:

时间线
CVE-2023-21931:
- 2022 年 8 月 12 日:向官方渠道报告漏洞
- 2022 年 8 月 19 日:漏洞正式确认
- 2023 年 4 月 18 日:漏洞正式修复
CVE-2023-21839:
- 2022 年 7 月 31 日:向官方渠道报告漏洞
- 2022 年 8 月 5 日:漏洞正式确认
- 2023年1月16日:漏洞正式修复
研究环境
Vulfocus WebLogic 环境
docker pull vulfocus/vcpe-1.0-a-oracle-weblogic:12.2.1.2.0-jdk-release docker pull vulfocus/vcpe-1.0-a-oracle-weblogic:12.2.1.1.0-jdk-release docker pull vulfocus/vcpe-1.0-a-oracle-weblogic:12.2.1.3.0-jdk-release docker pull vulfocus/vcpe-1.0-a-oracle-weblogic:12.2.1.4.0-jdk-release docker pull vulfocus/vcpe-1.0-a-oracle-weblogic:12.2.1.0.0-jdk-release docker pull vulfocus/vcpe-1.0-a-oracle-weblogic:14.1.1.0.0-jdk-release docker pull vulfocus/vcpe-1.0-a-oracle-weblogic:12.1.2.0.0-jdk-release docker pull vulfocus/vcpe-1.0-a-oracle-weblogic:12.1.3.0.0-jdk-release docker pull vulfocus/vcpe-1.0-a-oracle-weblogic:10.3.6.0-jdk-release
参考
Java“后序列表化漏洞”利用思路 – 瑞林(rui0.cn)
Ruil1n/after-deserialization-attack:Java 反序列化后攻击 (github.com)
本文演示的漏洞和特性兼容Goby版本:Beta 2.4.7,已经支持Goby Red Team和Missed Scan版本的扫描验证。最新版本下载体验: gobysec.net
作者:14m3ta7k
如果您有功能类型的问题,可以在 GitHub 或下面的讨论组中提出问题:
GitHub issue: https: //github.com/gobysec/Goby/issues
转载请注明出处及链接