Java表达式注入
OGNL表达式注入已经分析过了:https://xz.aliyun.com/t/10482,另外分析下MVEL和SPEL Java表达式注入就算收尾了。
MVEL
MVEL2 exp
1 | public void exp(){ |
MVEL2执行表达式通过org.mvel2.ast.ASTNode.getReducedValueAccelerated()处理表达式结果

通过optimize()最终会调用org.mvel2.optimizers.impl.refl.ReflectiveAccessorOptimizer().compileGetChain处理,当chain是method时,调用getMethod()

getMethod()最终会调用method.invoke()实现表达式中方法的调用,调用前,mevl没有检查类或方法的防护措施来防止危险方法的执行,因此可以完成命令执行。

Apache Unomi CVE-2020-13942
通过 org.apache.unomi.persistence.elasticsearch.conditions.ConditionContextHelper.getContextualCondition()解析传进来的参数

当以script::开始时,获取后面的内容作为脚本执行。

处理脚本的执行,会被当作mvel脚本执行并调用MVEL.executeExpression()处理

MVEL并没有限制类或方法的执行因此可以导致RCE。

SpEL
1 | // 1.创建解析器:SpEL 使用 ExpressionParser 接口表示解析器,提供 SpelExpressionParser 默认实现; |
org.springframework.expression.spel.standard.SpelExpression.getValue()首先会解析生成三个AST节点,java.lang.Runtime的TypeReference和2个MethodReference分别是getRuntime和exec。

通过SpelNodeImpl.getValue()调用CompoundExpression.getValueInternal()处理,首先通过getValueRef获取ref,再调用ref.getValue计算最后的结果。

跟进getValueRef()看下,循环计算除前n-1个node的结果,然后调用nextNode.getValueRef(state)获取最终的ref

这里nextNode就是MethodReference,调用MethodReference.getValueRef()返回MethodReference$MethodValueRef实例

跟进ref.getValue会调用getValueInternal,getValueInternal调用ReflectiveMethodExecutor.execute()通过执行方法


下图,ReflectiveMethodExecutor.execute()通过反射执行方法调用method.invoke。

另外EL推荐阅读:https://xz.aliyun.com/t/7692
总结
表达式语言主要是解析表达式为AST语法树计算每个树节点,当用户可以控制输入的表达式时,并且绕过黑名单限制则可达到RCE。
java审计时需要注意以下导入及相关流
1 | org.mvel2.MVEL |
参考链接:
1 | https://www.freebuf.com/vuls/197008.html |