| 
                         类类型表达式:使用”T(Type)”来表示 java.lang.Class  实例,”Type”必须是类全限定名,”java.lang”包除外,即该包下的类可以不指定包名;使用类类型表达式还可以进行访问类静态方法及类静态字段。 
具体使用方法: 
- ExpressionParser parser = new SpelExpressionParser(); 
 -         // java.lang 包类访问 
 - Class<String> result1 = parser.parseExpression("T(String)").getValue(Class.class); 
 - System.out.println(result1); 
 -         //其他包类访问 
 - String expression2 = "T(java.lang.Runtime).getRuntime().exec('open /Applications/Calculator.app')"; 
 - Class<Object> result2 = parser.parseExpression(expression2).getValue(Class.class); 
 - System.out.println(result2); 
 -         //类静态字段访问 
 - int result3 = parser.parseExpression("T(Integer).MAX_VALUE").getValue(int.class); 
 - System.out.println(result3); 
 -         //类静态方法调用 
 - int result4 = parser.parseExpression("T(Integer).parseInt('1')").getValue(int.class); 
 - System.out.println(result4); 
 
  
    - 类实例化:类实例化同样使用 java 关键字「new」,类名必须是全限定名,但  java.lang 包内的类型除外,如 String、Integer。
 
    - instanceof 表达式:SpEL 支持 instanceof  运算符,跟 Java 内使用同义;如”‘haha’ instanceof T(String)”将返回 true。
 
    - 变量定义以及引用:变量定义通过  EvaluationContext 接口的 setVariable(variableName, value)  方法定义;在表达式中使用”#variableName”引用;除了引用自定义变量,SpE  还允许引用根对象及当前上下文对象,使用”#root”引用根对象,使用”#this”引用当前上下文对象;
 
    - 自定义函数:目前只支持类静态方法注册为自定义函数;SpEL 使用 StandardEvaluationContext 的 registerFunction  方法进行注册自定义函数,其实完全可以使用 setVariable 代替,两者其实本质是一样的
 
 
四、审计过程 
这里拿 Spring  Message 远程命令执行漏洞来作为例子 
1. 环境搭建 
- git clone https://github.com/spring-guides/gs-messaging-stomp-websocket 
 - git checkout 6958af0b02bf05282673826b73cd7a85e84c12d3 
 
  
拿到项目代码,全局搜索一下  org.springframework.expression.spel.standard,发现 DefaultSubscriptionRegistry.java  文件处有导入。 
  
再搜索一下  SpelExpressionParser 
往下跟进发现如下关键代码,具体分析看代码注释 
- @Override 
 - protected void addSubscriptionInternal( 
 - String sessionId, String subsId, String destination, Message<?> message) { 
 - Expression expression = null; 
 - MessageHeaders headers = message.getHeaders(); 
 -         // 这里可以看出 SpEL 表达式 expression 是从 headers 中的 selector 字段中取出来 
 - String selector = SimpMessageHeaderAccessor.getFirstNativeHeader(getSelectorHeaderName(), headers); 
 - if (selector != null) { 
 - try { 
 -                 //生成 expression 对象 
 - expression = this.expressionParser.parseExpression(selector); 
 - this.selectorHeaderInUse = true; 
 - if (logger.isTraceEnabled()) { 
 - logger.trace("Subscription selector: [" + selector + "]"); 
 - } 
 - } 
 - catch (Throwable ex) { 
 - if (logger.isDebugEnabled()) { 
 - logger.debug("Failed to parse selector: " + selector, ex); 
 - } 
 - } 
 - } 
 -         // expression 传入 addSubscription 这个函数里面,即存放在 this.subscriptionRegistry 
 - this.subscriptionRegistry.addSubscription(sessionId, subsId, destination, expression); 
 - this.destinationCache.updateAfterNewSubscription(destination, sessionId, subsId); 
 - } 
 
  
再搜索一下 this.subscriptionRegistry,,看看有没有调用传进去的  expression。                         (编辑:泰州站长网) 
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! 
                     |