Struts2 高危漏洞修复方案 (S2 您所在的位置:网站首页 struts2-016 Struts2 高危漏洞修复方案 (S2

Struts2 高危漏洞修复方案 (S2

2023-03-09 08:49| 来源: 网络整理| 查看: 265

近期Struts2被曝重要漏洞,此漏洞影响struts2.0-struts2.3所有版本,可直接导致服务器被远程控制从而引起数据泄漏,影响巨大,受影响站点以电商、银行、门户、政府居多.

 

引发的威胁:

取得网站服务器主机管理权限。

CVSS:(AV:R/AC:L/Au:NR/C:C/A:C/I:C/B:N)score:10.00(最高10分,高危)

即:远程攻击、攻击难度低、不需要用户认证,对机密性、完整性、可用性均构成完全影响。

 

验证情况:

Struts2漏洞利用工具下载:右键保存图片,重命名为后缀.zip,解压打开。

 

(右键保存图片,重命名为后缀.zip)

 

验证如下:

图1 网站目录

图2 成功执行ipconfig命令

图3成功硬盘目录

 

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

官方建议修复方案:升级到最新版本 struts-2.3.15.1

但通常现有系统升级,可能导致不稳定及与其他框架比如spring等的不兼容,成本较高。鉴于此csdn网友jzshmyt整理了一种既可以不用升级现有struts版本,有能完美解决这两个漏洞的方案,

分享如下:

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

第1步.右键保存图片,重命名为后缀.zip,解压打开。

 

(右键保存图片,重命名为后缀.zip)

第2步.解压,将src目录中的所有文件,复制到自己项目的src目录中,编译通过,形成class文件  (本例struts是Struts-core-2.1.6版本_对2.0-2.3版本都有效,实际项目需要根据struts版本做适当调整).

  应用服务器会优先加载class目录中的类,自动覆盖jar包中的类.  第3步.web.xml中配置com.htht.commonweb.listener.MyServletContextListener 

[html] view plaincopy在CODE上查看代码片派生到我的代码片       org.hdht.commonweb.listener.MyServletContextListener     

  第4步.重启服务,修复完毕.

 

附:com.htht.commonweb.listener.MyServletContextListener.java,完整包参见struts2_S016_S017_repair.rar解压目录

启动漏洞监听

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

[java] view plaincopy在CODE上查看代码片派生到我的代码片   package com.htht.commonweb.listener;      import javax.servlet.ServletContextEvent;   import javax.servlet.ServletContextListener;      import com.htht.commonweb.JavaEEbugRepair;      /**   * WEB应用程序初始化监听器   */   public class MyServletContextListener implements ServletContextListener {       public void contextDestroyed(ServletContextEvent arg0) {               }          public void contextInitialized(ServletContextEvent arg0) {           try {               JavaEEbugRepair.initRepair_S2_016();               JavaEEbugRepair.initRepair_S2_017();                          } catch (Exception e) {               e.printStackTrace();           }       }   }  

附:ognl.Ognl.java,完整包参见struts2_S016_S017_repair.rar解压目录

ognl调用解决漏洞

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

 

[java] view plaincopy在CODE上查看代码片派生到我的代码片   package ognl;      import java.io.StringReader;   import java.util.Map;      import com.htht.commonweb.JavaEEbugRepair;      public abstract class Ognl   {     public static Object parseExpression(String expression)       throws OgnlException     {         if(JavaEEbugRepair.repair_s2_016(expression)){             return null;         }         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 Map createDefaultContext(Object root)     {       return addDefaultContext(root, null, null, null, new OgnlContext());     }        public static Map createDefaultContext(Object root, ClassResolver classResolver)     {       return addDefaultContext(root, classResolver, null, null, new OgnlContext());     }        public static Map createDefaultContext(Object root, ClassResolver classResolver, TypeConverter converter)     {       return addDefaultContext(root, classResolver, converter, null, new OgnlContext());     }        public static Map createDefaultContext(Object root, ClassResolver classResolver, TypeConverter converter, MemberAccess memberAccess)     {       return addDefaultContext(root, classResolver, converter, memberAccess, new OgnlContext());     }        public static Map addDefaultContext(Object root, Map context)     {       return addDefaultContext(root, null, null, null, context);     }        public static Map addDefaultContext(Object root, ClassResolver classResolver, Map context)     {       return addDefaultContext(root, classResolver, null, null, context);     }        public static Map addDefaultContext(Object root, ClassResolver classResolver, TypeConverter converter, Map context)     {       return addDefaultContext(root, classResolver, converter, null, context);     }        public static Map addDefaultContext(Object root, ClassResolver classResolver, TypeConverter converter, MemberAccess memberAccess, Map context)     {       OgnlContext result;       if (!(context instanceof OgnlContext)) {          result = new OgnlContext();         result.setValues(context);       } else {         result = (OgnlContext)context;       }       if (classResolver != null) {         result.setClassResolver(classResolver);       }       if (converter != null) {         result.setTypeConverter(converter);       }       if (memberAccess != null) {         result.setMemberAccess(memberAccess);       }       result.setRoot(root);       return result;     }        public static void setClassResolver(Map context, ClassResolver classResolver)     {       context.put("_classResolver", classResolver);     }        public static ClassResolver getClassResolver(Map context)     {       return (ClassResolver)context.get("_classResolver");     }        public static void setTypeConverter(Map context, TypeConverter converter)     {       context.put("_typeConverter", converter);     }        public static TypeConverter getTypeConverter(Map context)     {       return (TypeConverter)context.get("_typeConverter");     }        public static void setMemberAccess(Map context, MemberAccess memberAccess)     {       context.put("_memberAccess", memberAccess);     }        public static MemberAccess getMemberAccess(Map context)     {       return (MemberAccess)context.get("_memberAccess");     }        public static void setRoot(Map context, Object root)     {       context.put("root", root);     }        public static Object getRoot(Map context)     {       return context.get("root");     }        public static Evaluation getLastEvaluation(Map context)     {       return (Evaluation)context.get("_lastEvaluation");     }        public static Object getValue(Object tree, Map context, Object root)       throws OgnlException     {       return getValue(tree, context, root, null);     }        public static Object getValue(Object tree, Map context, Object root, Class resultType)       throws OgnlException     {       OgnlContext ognlContext = (OgnlContext)addDefaultContext(root, context);          Object result = ((Node)tree).getValue(ognlContext, root);       if (resultType != null) {         result = getTypeConverter(context).convertValue(context, root, null, null, result, resultType);       }       return result;     }        public static Object getValue(String expression, Map context, Object root)       throws OgnlException     {       return getValue(expression, context, root, null);     }        public static Object getValue(String expression, Map context, Object root, Class resultType)       throws OgnlException     {       return getValue(parseExpression(expression), context, root, resultType);     }        public static Object getValue(Object tree, Object root)       throws OgnlException     {       return getValue(tree, root, null);     }        public static Object getValue(Object tree, Object root, Class resultType)       throws OgnlException     {       return getValue(tree, createDefaultContext(root), root, resultType);     }        public static Object getValue(String expression, Object root)       throws OgnlException     {       return getValue(expression, root, null);     }        public static Object getValue(String expression, Object root, Class resultType)       throws OgnlException     {       return getValue(parseExpression(expression), root, resultType);     }        public static void setValue(Object tree, Map context, Object root, Object value)       throws OgnlException     {       OgnlContext ognlContext = (OgnlContext)addDefaultContext(root, context);       Node n = (Node)tree;          n.setValue(ognlContext, root, value);     }        public static void setValue(String expression, Map context, Object root, Object value)       throws OgnlException     {       setValue(parseExpression(expression), context, root, value);     }        public static void setValue(Object tree, Object root, Object value)       throws OgnlException     {       setValue(tree, createDefaultContext(root), root, value);     }        public static void setValue(String expression, Object root, Object value)       throws OgnlException     {       setValue(parseExpression(expression), root, value);     }        public static boolean isConstant(Object tree, Map context) throws OgnlException     {       return ((SimpleNode)tree).isConstant((OgnlContext)addDefaultContext(null, context));     }        public static boolean isConstant(String expression, Map context) throws OgnlException     {       return isConstant(parseExpression(expression), context);     }        public static boolean isConstant(Object tree) throws OgnlException     {       return isConstant(tree, createDefaultContext(null));     }        public static boolean isConstant(String expression) throws OgnlException     {       return isConstant(parseExpression(expression), createDefaultContext(null));     }        public static boolean isSimpleProperty(Object tree, Map context) throws OgnlException     {       return ((SimpleNode)tree).isSimpleProperty((OgnlContext)addDefaultContext(null, context));     }        public static boolean isSimpleProperty(String expression, Map context) throws OgnlException     {       return isSimpleProperty(parseExpression(expression), context);     }        public static boolean isSimpleProperty(Object tree) throws OgnlException     {       return isSimpleProperty(tree, createDefaultContext(null));     }        public static boolean isSimpleProperty(String expression) throws OgnlException     {       return isSimpleProperty(parseExpression(expression), createDefaultContext(null));     }        public static boolean isSimpleNavigationChain(Object tree, Map context) throws OgnlException     {       return ((SimpleNode)tree).isSimpleNavigationChain((OgnlContext)addDefaultContext(null, context));     }        public static boolean isSimpleNavigationChain(String expression, Map context) throws OgnlException     {       return isSimpleNavigationChain(parseExpression(expression), context);     }        public static boolean isSimpleNavigationChain(Object tree) throws OgnlException     {       return isSimpleNavigationChain(tree, createDefaultContext(null));     }        public static boolean isSimpleNavigationChain(String expression) throws OgnlException     {       return isSimpleNavigationChain(parseExpression(expression), createDefaultContext(null));     }   }  

 

 

附:com.htht.commonweb.JavaEEbugRepair.java,完整包参见struts2_S016_S017_repair.rar解压目录

拦截攻击关键代码

 

[java] view plaincopy在CODE上查看代码片派生到我的代码片   OgnlRuntime.setMethodAccessor(Runtime.class, new NoMethodAccessor());   OgnlRuntime.setMethodAccessor(System.class, new NoMethodAccessor());   OgnlRuntime.setMethodAccessor(ProcessBuilder.class,new NoMethodAccessor());   OgnlRuntime.setMethodAccessor(OgnlRuntime.class, new NoMethodAccessor());              //io敏感操作     OgnlRuntime.setMethodAccessor(OutputStream.class, new NoMethodAccessor());     OgnlRuntime.setMethodAccessor(InputStream.class, new NoMethodAccessor());     OgnlRuntime.setMethodAccessor(File.class, new NoMethodAccessor());     OgnlRuntime.setMethodAccessor(DataOutput.class, new NoMethodAccessor());     OgnlRuntime.setMethodAccessor(DataInput.class, new NoMethodAccessor());     OgnlRuntime.setMethodAccessor(Reader.class, new NoMethodAccessor());     OgnlRuntime.setMethodAccessor(Writer.class, new NoMethodAccessor());   

 

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

 

[java] view plaincopy在CODE上查看代码片派生到我的代码片   package com.htht.commonweb;      import java.io.DataInput;   import java.io.DataOutput;   import java.io.File;   import java.io.InputStream;   import java.io.OutputStream;   import java.io.Reader;   import java.io.Writer;   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());                      //io敏感操作             OgnlRuntime.setMethodAccessor(OutputStream.class, new NoMethodAccessor());             OgnlRuntime.setMethodAccessor(InputStream.class, new NoMethodAccessor());             OgnlRuntime.setMethodAccessor(File.class, new NoMethodAccessor());             OgnlRuntime.setMethodAccessor(DataOutput.class, new NoMethodAccessor());             OgnlRuntime.setMethodAccessor(DataInput.class, new NoMethodAccessor());             OgnlRuntime.setMethodAccessor(Reader.class, new NoMethodAccessor());             OgnlRuntime.setMethodAccessor(Writer.class, new NoMethodAccessor());                       s2_016 = new S2_0XX(){               public boolean check(String expression){                   String evalMethod[] = {"Runtime", "ProcessBuilder","java.io.File","new File","OutputStream","InputStream"};                   String methodString = null;                   methodString = expression.toLowerCase();                   for (int i = 0; i  -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 {           if(targetClass!=null){                 System.out.println("拦截并拒绝敏感操作: static "+targetClass.getName()+"#"+methodName);             }             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           if(target!=null){                 System.out.println("拦截并拒绝敏感操作:"+target.getClass().getName()+"#"+methodName);             }             throw new MethodFailedException("do not run", methodName,null);       }   }  

 

 

附:org.apache.struts2.dispatcher.mapper.DefaultActionMapper.java,完整包参见struts2_S016_S017_repair.rar解压目录

重写Struts2核心包的DefaultActionMapper类。

每个版本的DefaultActionMapper类不一样,可以用反编译工具

取出org.apache.struts2.dispatcher.mapper.DefaultActionMapper.java的全部代码重写编译

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

修改地方handleSpecialParameters方法上的while循环体里添加:

if (JavaEEbugRepair.repair_s2_017(key)) {          return;      }

这样受攻击就会判断返回,返回的显示是一串html静态代码,漏洞解决成功!

 

 

[java] view plaincopy在CODE上查看代码片派生到我的代码片   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);         }                  if (JavaEEbugRepair.repair_s2_017(key)) {             return;         }            if (!uniqueParameters.contains(key)) {           ParameterAction parameterAction = (ParameterAction)this.prefixTrie.get(key);              if (parameterAction != null) {             parameterAction.execute(key, mapping);             uniqueParameters.add(key);             break;           }         }       }     }  

 

 

参考:

http://blog.csdn.net/mydwr/article/details/18727627

http://blog.csdn.net/jzshmyt/article/details/9842501

http://software.intel.com/zh-cn/blogs/2013/08/08/struts2-s2-016s2-017/?utm_campaign=CSDN&utm_source=intel.csdn.net&utm_medium=Link&utm_content=others-%20Struts2

网上的多种方案:http://star.baidu.com/forum/forum.php?mod=viewthread&tid=1945



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有