在学习各种内存马的过程中,关注到了观星实验室的一篇文章,较为全面的列举了在Spring环境下的有关内存马的实现技巧
这里我们深入进行学习学习一下
网上常见的内存马方式是通过RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0)
的方式得到的WebApplicationContext
对象的
那么存在有几个问题
具体怎么得到该对象的
我们跟进RequestContextHolder#currentRequestAttributes
方法
这个方法主要是返回了当前线程中的所有存在的请求属性值动态调试一下有些什么
首先,很明显的是,我们可以通过这种方法来获取到Request / Response
域,进而能够做到在构造内存马webshell的交互式回显
同样对于在前面创建一个Controller的步骤中,需要找到一个Context对象来操控bean来进行动态添加一个Controller
幸运的是在对象的request
域中存在的属性中
存在有本次请求的各种信息,比如说访问路由等等属性,特别的,其中存在有一个属性值为org.springframework.web.servlet.DispatcherServlet.CONTEXT
对于DispatcherServlet
这个类,是在常见的Spring项目中的web.xml
配置文件中都会指定的一个用来进行路由分发的一个类
对于他的CONTEXT
属性
居然还是一个Child Context对象
这个对象有着怎么样的作用
通过这个Context
对象,我们可以成功操控bean对象,即这里我们需要的RequestMappingHandlerMapping
类对象
通过调用他的registerMapping
方法来动态创建一个Controller
使得在访问我们定义的路由的时候执行我们自定义的恶意代码
具体的代码实现可以参见前面的Spring Controller类型的内存马实现
难道在Spring这个伟大的框架中,只存在这样一种方式能够找到Context
对象嘛,当然还有这各种各样的sao姿势
(WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0)
这个方法就是前面使用的方法,不重复阐述了
ContextLoader.getCurrentWebApplicationContext()
对于ContextLoader
类,我们可以看看大概的用途
实际上就是通过ContextLoaderListener
调用执行Root Application Context的初始化工作
也即是在web.xml
配置文件中的<context-param>
标签的配置
如果没有配置这个标签,默认为XmlWebApplicationContext
类对象
在该类的getCurrentWebApplicationContext
方法中
从注释中,我们知道这个方法的作用主要是通过中当前线程中获取Spring的Root Application Context对象
同样可以进行前面类似的操作,操控bean对象来动态创建一个Controller
对于所有的映射都实现了HandlerMapping
这个接口
RequestMappingHandlerMapping#registerMapping
对于这种方法添加Controller,前面也已经提到了,也不重复说了
但是这种方式存在有一定的版本限制,即是在spring 4.0
之后才能够调用进行路由的注册
AbstractUrlHandlerMapping#registerHandler
对于这个类名就是极其的可疑,果不其然
了解一下AbstractUrlHandlerMapping
的作用
是一个URL映射的HandlerMapping实现的抽象基类
看看类似于前面的registerMapping
方法的实现
为提供的URL路径注册一个特定的handler
对象
我们具体看看该方法中的逻辑
首先在第一个if语句中判断传入的handler
值是否是String类型,如果是,将会进入if语句内部,首先通过调用obtainApplicationContext
方法获取上下文环境
之后将会通过调用isSingleton
方法判断传入的handlerNmame
是否是一个单例,如果是将会取出对应的Bean对象
之后,首先会从handlerMap
这个映射中取出我们传入的路由,如果存在对应的handler对象,且不为我们前面获取的Bean对象,则将会抛出一个异常,如果不存在对应路由的handler对象,将会将其添加进入handlerMap
这个映射中去
AbstractHandlerMethodMapping#detectHandlerMethods
对于这种方法的利用,我觉得其灵感应该来自于第一种方式
直接来看看这个方法实现
这里传入的参数不同于前面传入的参数,这里只有一个handler对象
同样是从获取的上下文环境中取出传入的handler
这个bean,之后将会注册为了一个Controller bean对象
在Get Context部分,存在着相对简单的两种分别获取了child Context和Root Context的方式,我们需要知道的是,对于一个Child Context来说是能够获取到Root Context中的Bean对象的,但是一个Root Context是不能够获取到Child Context中的bean对象的