Struts2-001代碼執行漏洞分析
先知安全技術社區獨家發文,如需轉載,請先聯繫社區授權;未經授權請勿轉載。
前言
最近學習java安全,在分析s2-001的時候發現了一些問題和心得。
一方面網上關於s2-001的漏洞分析很少,基本上都是poc+利用而已。
另一方面在調試過程中感覺apache官方通告有不準確的地方,這點見後面的部分。
有不準確的地方望各位師傅指出,謝謝。
漏洞信息
漏洞信息頁面: https://cwiki.apache.org/confluence/display/WW/S2-001
漏洞成因官方概述:Remote code exploit on form validation error
漏洞影響:
WebWork 2.1 (with altSyntax enabled), WebWork 2.2.0 - WebWork 2.2.5, Struts 2.0.0 - Struts 2.0.8
環境搭建
源碼結構:
幾個主要文件(待會用到):
index.jsp
struts.xml:
web.xml:
完整源碼見附件。
漏洞利用
最簡單poc:
任意命令執行:
將中的替換為對應的命令,即可執行。
漏洞分析
在經過tomcat容器的處理後,http請求會到達struts2,從這裡開始調試吧。
在 /com/opensymphony/xwork2/interceptor/ParametersInterceptor.java:158 接受我們輸入的參數值,之後會調用對應的set方法(這個省略):
繼續執行,執行完interceptor部分,也即對進行step over,到達/com/opensymphony/xwork2/DefaultActionInvocation.java:252
跟進,到達 /com/opensymphony/xwork2/DefaultActionInvocation.java:343
跟進,到達 /org/apache/struts2/dispatcher/StrutsResultSupport.java:175:
此後在跟進,此處省略一些過程,相關調用棧如下:
進入 /org/apache/struts2/views/jsp/ComponentTagSupport.java:47,
這裡會對jsp標籤進行解析,但這時的標籤並不包含我們的payload,我們可以在這裡step over,直到解析到對應的標籤:
如上圖,我們提交的password值為,因此著重關注對解析。回到,執行完後會再次回到,此時遇到了相應的閉合標籤,會跳轉到:
跟進,到達 /org/apache/struts2/components/UIBean.java:486:
跟入後一直執行到如下圖
由於開啟了,expr變為為
跟入中的,來到 /org/apache/struts2/components/Component.java:318
開啟了且為,跟入,在/com/opensymphony/xwork2/util/TextParseUtil.java:
繼續跟入,源碼如下:
此時為
經過while循環,確定start和end定位後,此時為,到達:
會返回password的值,這個就是我們傳入的payload:
此後為,再對進行了一番處理後,payload經過變數,最終成為的值:
在完成後,進入下一個循環:
並且在中完成了對payload的執行
因此究其原因,在於在中,遞歸解析了表達式,在處理完後將的值直接取出並繼續在循環中解析,若用戶輸入的password是惡意的ognl表達式,比如,則得以解析執行。
漏洞修復
XWork 2.0.4中,改變了ognl表達式的解析方法從而不會產生遞歸解析,用戶的輸入也不會再解析執行。
對應源碼如下:
當解析完一層表達式後,如圖,此時,從而執行break,不再繼續解析:
diff的結果如下:
一個說明
回到漏洞信息和開頭環境搭建部分,漏洞信息中的圖有畫上了幾個紅圈。基於此問一個問題:表單驗證錯誤是在哪裡觸發的?
查閱apache2官方文檔(https://struts.apache.org/core-developers/validation.html)提到%E6%8F%90%E5%88%B0)
就本次測試源碼而言,並沒有相應的或其他validation方法。為更直觀起見,我們修改源碼:
當submit時,會執行相應的set方法,直接設置username和password分別為與。修改後的源碼中的方法中若為則返回,根據struts.xml配置文件,當返回時,會返回,即這裡不算存在邏輯上的驗證錯誤,因為username被硬編碼為了,恆成立。
所以這裡沒有涉及到我們傳入的參數,不存在表單驗證失敗,也不存在邏輯上的驗證失敗。執行poc如下:
GIF
所以可以說表單驗證錯誤並不是該漏洞的產生的原因,但表單驗證錯誤是這個漏洞出現的場景之一。在struts2框架中,配置了Validation,倘若驗證出錯會往往會原樣返回用戶輸入的值而且不會跳轉到新的頁面,而在最後解析頁面時區解析了用戶輸入的值,從而執行payload。在實際場景中,比如登陸等處,往往會配置了Validation,比如限制用戶名長度,數字的範圍等等,從而成為了該漏洞的高發區。
以struts2的showcase為例:
GIF
在本測試環境的源碼中,沒有表單驗證,但同樣把用戶的輸入留在了頁面里,從而在解析的時候執行了。


TAG:先知安全技術社區 |