Java安全之Tomcat6 Filter内存马

Java安全之Tomcat6 Filter内存马回顾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

Java安全之Tomcat6 Filter内存马

文章插图
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
Java安全之Tomcat6 Filter内存马

文章插图
主要代码如下:
所以这里构造filterDef的时候filterClass为evilfilter的全类名即可
Java安全之Tomcat6 Filter内存马

文章插图
再来看下FilterDef 可以发现确实在Tomcat6下面没有filter这个属性了
Java安全之Tomcat6 Filter内存马

文章插图
所以一个很大的区别就是在getFilter方法 , 也就是获取filter实例对象的逻辑:
Tomcat8中是通过filterDef的属性filter值来拿到 恶意filter实例
Tomcat6中是通过filterDef的属性filterClass属性作为类名,通过ClassLoader去实例化
Java安全之Tomcat6 Filter内存马

文章插图
这里当我们调用有参构造实例化ApplicationFilterConfig时,会进入getFilter方法逻辑内
Java安全之Tomcat6 Filter内存马

文章插图
重点看loadClass方法是否可以加载到我们的恶意filter,因为这个filter并不是真实存在,且我们也只是通过了当前线程去defineClass的
Java安全之Tomcat6 Filter内存马

文章插图
跟进WebappClassLoader#loadClass

推荐阅读