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 |