Struts2 高危漏洞修復方案 (S2-016/S2-017)

近期Struts2被曝重要漏洞,此漏洞影響struts2.0-struts2.3所有版本,可直接導致服務器被遠程控制從而引起數據泄漏,影響巨大,受影響站點以電商、銀行、門戶、政府居多.

官方描述:
S2-016:https://cwiki.apache.org/confluence/display/WW/S2-016
S2-017:https://cwiki.apache.org/confluence/display/WW/S2-017

官方建議修復方案:升級到最新版本 struts-2.3.15.1


但通常現有系統升級,可能導致不穩定及與其他框架比如spring等的不兼容,成本較高。
鑑於此本人整理了一種既可以不用升級現有struts版本,有能完美解決這兩個漏洞的方案,

分享如下:

-------------------------

第1步.下載http://jskfs.googlecode.com/files/struts2_(016_017)_bug_repair.rar

第2步.解壓,將src目錄中的所有文件,複製到自己項目的src目錄中,編譯通過
  (本例struts是2.0.9版本,實際項目需要根據struts版本做適當調整).
  應用服務器會優先加載class目錄中的類,自動覆蓋jar包中的類.
  
第3步.web.xml中配置com.htht.commonweb.listener.MyServletContextListener
 

 <listener> 
  <listener-class>org.hdht.commonweb.listener.MyServletContextListener</listener-class> 
 </listener> 

第4步.重啓服務,修復完畢.

@版權所有,轉載請標明出處. http://blog.csdn.net/jzshmyt


附:JavaEEbugRepair.java,完整包參見struts2_(016_017)_bug_repair.rar解壓目錄
-------------------------

package com.htht.commonweb; 

import java.util.Map; 

import ognl.MethodAccessor; 
import ognl.MethodFailedException; 
import ognl.OgnlRuntime; 


/** 
 * @author yanjianzhong([email protected]) 2013/08/08 
 * @版權所有,轉載請標明出處. http://blog.csdn.net/jzshmyt 
 * download : http://jskfs.googlecode.com/files/struts2_(016_017)_bug_repair.rar 
 */ 
public class JavaEEbugRepair{ 
    /* 
     * 官方描述: 
     * S2-016:https://cwiki.apache.org/confluence/display/WW/S2-016 
     * S2_016 bug repair 
     */ 
    private static S2_0XX s2_016 = new S2_0XX(); 
     

    /* 
     *  修改 ognl.Ognl#parseExpression,調用 check_s2_016 方法 
     *  public static Object parseExpression(String expression)throws OgnlException 
     *    { 
     *          //modify point begin 
     *          if(JavaEEBug.check_s2_016(expression)){  
     *                return null  
     *          } 
     *          //modify point end 
     *          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); 
     *          } 
     *      } 
     */ 
    public static boolean repair_s2_016(String expression){ 
        return s2_016.check(expression); 
    } 
    /* 
    * 在servlet/struts/spring 任何一個框架的listener中調用 
    */ 
    public static void initRepair_S2_016(){ 
        OgnlRuntime.setMethodAccessor(Runtime.class, new NoMethodAccessor()); 
        OgnlRuntime.setMethodAccessor(System.class, new NoMethodAccessor()); 
        OgnlRuntime.setMethodAccessor(ProcessBuilder.class,new NoMethodAccessor()); 
        OgnlRuntime.setMethodAccessor(OgnlRuntime.class, new NoMethodAccessor()); 
         
        s2_016 = new S2_0XX(){ 
            public boolean check(String expression){ 
                String evalMethod[] = {"Runtime", "ProcessBuilder","new File" }; 
                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 true; 
                    } 
                } 
                return false; 
            } 
        }; 
         
    } 
     
    /* 
     * S2-017:https://cwiki.apache.org/confluence/display/WW/S2-017 
     * S2_017 bug repair 
     */ 
    private static S2_0XX s2_017 = new S2_0XX(); 
     
    /* 
    * Call by org.apache.struts2.dispatcher.mapper.DefaultActionMapper#handleSpecialParameters  
    * Repair Example : 
    * public void handleSpecialParameters(HttpServletRequest request, ActionMapping mapping) 
    * { 
    *        Set uniqueParameters = new HashSet(); 
    *        Map parameterMap = request.getParameterMap(); 
    *        Iterator iterator = parameterMap.keySet().iterator(); 
    *        while (iterator.hasNext()) { 
    *          String key = (String)iterator.next(); 
    *     
    *          if ((key.endsWith(".x")) || (key.endsWith(".y"))) { 
    *            key = key.substring(0, key.length() - 2); 
    *          } 
    *          //modify point begin 
    *          if (JavaEEBug.check_s2_017(key)) { 
    *              return; 
    *          } 
    *          //modify point end 
    *          if (!uniqueParameters.contains(key)) { 
    *            ParameterAction parameterAction = (ParameterAction)this.prefixTrie.get(key); 
    *     
    *            if (parameterAction != null) { 
    *              parameterAction.execute(key, mapping); 
    *              uniqueParameters.add(key); 
    *              break; 
    *            } 
    *          } 
    *        } 
    *      } 
    */ 
    public static boolean repair_s2_017(String key){ 
        return s2_017.check(key); 
    } 
     
    /* 
    * 在servlet/struts/spring 任何一個框架的listener中調用 
    */ 
    public static void initRepair_S2_017(){ 
        s2_017 = new S2_0XX(){ 
            public boolean check(String key){ 
                return (key.contains("redirect:")) || (key.contains("redirectAction:")) || (key.contains("action:")); 
            } 
        }; 
    } 


/** 
 *  漏洞驗證修復之基類 
 *  說明: 
 *  漏洞修復代碼的實現邏輯,非侵入式設計。 
 *  當listener中未調用initRepair_S2_016、initRepair_S2_017進行漏洞調用初始化時, 
 *  保持Ognl和DefaultActionMapper修復前源碼等價邏輯. 
 *  
 */ 
class S2_0XX { 
    public boolean check(String key){ 
        return false; 
    } 



class NoMethodAccessor implements MethodAccessor { 
    public NoMethodAccessor() { 
    } 

    @Override 
    public Object callStaticMethod(Map context, Class targetClass, 
            String methodName, Object[] args) throws MethodFailedException { 
        throw new MethodFailedException("do not run", methodName, null); 
    } 

    @Override 
    public Object callMethod(Map context, Object target, String methodName, 
            Object[] args) throws MethodFailedException { 
        // TODO Auto-generated method stub 
        throw new MethodFailedException("do not run", methodName,null); 
    } 
}
發佈了154 篇原創文章 · 獲贊 33 · 訪問量 85萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章