1. 程式人生 > >S2-052 遠端程式碼執行漏洞檢測與利用

S2-052 遠端程式碼執行漏洞檢測與利用

除錯環境搭建

使用官方的rest-sample即可,下載2.5.12版本的原始碼https://github.com/apache/struts/archive/STRUTS_2_5_12.zip,然後將apps下面的rest-showcase原始碼脫下來。

Eclipse中新建一個maven工程,web.xml,pom.xml和struts.xml如下:

pom.xml

<!-- struts2依賴包 -->
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-core</artifactId>
<version>2.5.12</version>
</dependency>
<!-- struts restful 依賴包 -->
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-convention-plugin</artifactId>
<version>2.5.12</version>
</dependency>
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-rest-plugin</artifactId>
<version>2.5.12</version>
</dependency>

struts.xml(src/main/resources/下)


<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<!-- Overwrite Convention -->
<constant name="struts.convention.action.suffix" value="Controller"/>
<constant name="struts.convention.action.mapAllMatches" value="true"/>
<constant name="struts.convention.default.parent.package" value="rest-default"/>
<constant name="struts.convention.package.locators" value="action"/>
<constant name="struts.convention.result.path" value="/WEB-INF/"/>
</struts>

其他的action檔案、jsp檔案複製過來到maven工程的對應目錄即可,右鍵啟動專案,然後瀏覽器可以訪問到:http://127.0.0.1:8080/struts2-052/orders,說明除錯環境搭建成功。

漏洞分析

根據該漏洞發現者文章https://lgtm.com/blog/apache_struts_CVE-2017-9805所述,是一個叫ContentHandler的東西有問題。

在2.5.12原始碼中搜索這個字串:

在struts-plugin.xml配置了很多的bean,這些bean按照content-type進行分類,並唯一指定一個具體的Handler。這些Handler都實現了ContentTypeHandler介面。

從API DOC上描述

Handles transferring content to and from objects for a specific content type

來看,這個ContentTypeHandler實際上是按照Content-type的不同,將請求的資料丟給指定的子類進行處理,具體是怎麼處理的呢,以XStreamHandler為例:

這裡實際上就是把XML和java物件之間進行轉化,比較專業的詞彙叫“marshal“和”“unmarshal”。從以往的例子看,這種情況導致的命令執行也不是一次兩次了,json轉換庫如fastjson,jackson都有過漏洞,

這次換成了Struts2裡的XML的物件轉換。其實就是XStreamHandler的toObject方法中觸發了漏洞,我們就先在這行程式碼下斷點,執行poc之後,會發現斷點生效了。

我們來看看呼叫函式流程資訊:

在Restful模式下,對Action的路由處理是使用Rest系列的程式碼,這裡是ContentTypeInterceptor類呼叫的XStreamHandler方法。我們來看看上層程式碼中的intercept方法:

首先是從HttpServletRequest裡判斷ContentType,可以很清晰的看到,通過ContentType將request的位元組流分發給對應的Handler進行處理。當ContentType為application/xml的時候,

很自然的就分發給了XStreamHandler這個類來處理,這個類沒有進行任何校驗,直接進行了轉換。我們可以用marsshalsec工具來生成payload。

(1)下載原始碼https://github.com/mbechler/marshalsec

(2)maven編譯 mvn clean package -DskipTests

(3)去target目錄下找到jar檔案,執行:
 

java -cp marshalsec-0.0.1-SNAPSHOT-all.jar marshalsec.XStream ImageIO "calc" > 1.txt

然後將這段XML用POST發給struts2-rest,當然,ContentType要設定為xml的,然後就可以觸發了。當命令中有空格時,提交多個<string>節點即可。

後話

關於如何從XML到命令執行的過程,實際上是Moritz Bechler大神的一個paper,https://github.com/mbechler/marshalsec/blob/master/marshalsec.pdf,這個paper隨著marshalsec工具釋出。

這裡只分析Struts2的漏洞原因,關於XML->RCE過程,大家可以仔細閱讀這個paper進行深入瞭解。
 

參考

https://lgtm.com/blog/apache_struts_CVE-2017-9805