Spring框架標籤EL表示式執行漏洞分析(CVE-2011-2730)

wyzsk發表於2020-08-19
作者: lupin · 2015/04/23 10:30

0x00 前言


這個漏洞已經出來很久了,以前簡單分析過,但是由於時間關係,沒能深入研究原理,網上對這個漏洞的分析也不太多,最近由於工作原因,深入分析了一下這個漏洞的原理,這裡重點將漏洞除錯過程,以及一些之前遇到的一些奇怪問題的原因記錄下來。

首先來看一下官方對這個漏洞的描述,如下圖:

enter image description here

可以看到,這個漏洞的形成,是因為在早於JSP2.0的版本上,由於沒有EL表示式的支援,Spring標籤為了相容這部分版本,Spring的一部分標籤獨立於Servlet/JSP容器新增了對EL表示式的支援。但這樣做引起了一個問題,就是當這部分標籤在支援EL表示式的容器中執行的時候,Spring標籤的屬性會被當做EL表示式執行兩次,第一次是被容器當做EL執行,第二次是被Spring標籤自身執行。所以,如果攻擊者可以控制標籤屬性的內容,就可以執行自己提交的EL表示式,會造成資訊洩露、程式碼執行等風險。

0x01 漏洞原理


首先編寫一段測試JSP程式碼,並且引入存在漏洞的Spring標籤,我這裡使用的是Tomcat 7.0.57和Spring 3.0.5

#!html
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<spring:message  text="${param.a}"></spring:message>

這裡使用message標籤,text屬性用el表示式從請求引數中取值,這樣當訪問

http://localhost/tag.jsp?a=${applicationScope}

${applicationScope}這個字串,就會被當做EL表示式執行,如下圖

enter image description here

下面我們就從程式碼中,研究一下這個漏洞的原理。

首先,${param.a}這個EL表示式要在JSP裡面執行,這裡有必要簡單說一下JSP的執行原理,tag.jsp在執行的時候,會先透過規則變成tag_jsp.java,這個檔案可以在tomcatRoot/ work/Catalina/localhost/專案名稱/org/apache/jsp/路徑下找到,這個類其實是一個servlet,透過檢視這個檔案的程式碼,我們可以發現${param.a}這個EL表示式,其實是被轉化成了這樣的程式碼org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate("${param.a }", .......),這行程式碼呼叫了Tomcat的一個專用方法來執行EL表示式,這段程式碼執行了之後,我們透過請求引數提交的${applicationScope}就被容器獲取,並且傳入了Spring標籤,如下圖:

enter image description here

還需要說一下關於標籤的一些內容,標籤都有一個tld檔案,這個檔案裡面有標籤的各種資訊,包括標籤實現類、屬性資訊等等,這個標籤對應的spring.tld檔案可以在Spring的jar包中找到,開啟這個檔案搜尋message,就可以定位到如下圖的位置:

enter image description here

從上面可以看到org.springframework.web.servlet.tags.MessageTag就是這個標籤的實現類,關於標籤的規範,我就不多說了,有興趣的朋友可以去翻翻相關的規範。

Debug程式,在doStartTagInternal方法下斷點,如下圖:

enter image description here

然後跟進resolveMessage方法,因為程式執行到這裡,容器已經第一次執行了EL表示式${parm.a},將引數值${applicationScope}取了出來,可以看到text變數,這時候就是我們傳入的${applicationScope},如下圖:

enter image description here

最後跟蹤到org.springframework.web.util.ExpressionEvaluationUtils類的evaluateExpression方法,在這裡可以看到Spring的程式碼呼叫了getExpressionEvaluator方法獲取了容器執行El表示式求值物件,並執行了EL表示式,到這裡可以看到我們透過請求引數提交的字串,被當做EL表示式執行了,如下圖:

enter image description here

從上面的過程可以看到,容器第一次執行EL表示式${param.a}獲得了我們輸入的${applicationScope},然後Spring標籤獲取容器的EL表示式求值物件,把${applicationScope}再次執行掉,形成了漏洞。

0x02 Tomcat不能遠端程式碼執行研究


這個漏洞既然能執行攻擊者提交的EL表示式,那麼獲取敏感資訊、XSS等攻擊自然不是問題,我這裡主要說一下程式碼執行的一些問題。 這個漏洞之所以能造成遠端程式碼執行,是因為從JEE6開始,EL(EL2.2)表示式不僅支援獲取物件屬性,還加入了對方法呼叫的支援,而Tomcat、Resin等容器都加入了EL表示式對方法呼叫的支援,之前知識庫裡面已經有大牛公佈的針對Resin和GlassFish的程式碼執行POC,雖然由於容器對EL表示式的執行實現上有差異,每個容器POC有所差異,但是都可以成功實現方法呼叫,我這裡就不多說了,而我在最初測試這個漏洞的時候,發現Tomcat始終沒法呼叫方法,當時沒有深入研究,透過前面的分析,其實原因已經可以看出來了,這裡還是測試一下,先寫一段JSP測試程式碼:

#!html
<body>
${“aaa”.replace(‘a’,’b’)}
</body>

開啟這個頁面,發現a都已經被b替換,說明replace方法被成功呼叫:

enter image description here

但是當我們透過之前的tag.jsp嘗試提交http://localhost/tag.jsp?a=${“aaaa”.replace(‘a’,’b’)}的時候卻爆出了錯誤,如下圖:

enter image description here

從Tomcat 7開始已經支援EL表示式方法呼叫,為什麼第二次會失敗呢?

其實前面的分析中已經看到,在JSP中直接寫EL表示式,Tomcat呼叫了org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate方法,這個方法已經加入了對EL表示式方法呼叫的支援,而透過Spring標籤執行EL表示式,前面已經看到是透過pageContext的getExpressionEvaluator方法,而在EL表示式的新標準中這個方法已經“廢棄”,Tomcat並沒有在這個方法的實現中加入對方法呼叫的支援,所以造成執行失敗,這也讓這個漏洞在Tomcat上顯得有點雞肋了,誰能保證Tomcat哪天不會抽風,改變程式碼呢?說不定到時候,這個漏洞,就可以在Tomcat上造成程式碼執行了。

參考

http://support.springsource.com/security/cve-2011-2730

/tips/?id=2892

本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章