Java agent技术的注入利用与避坑点

打印 上一主题 下一主题

主题 923|帖子 923|积分 2769

什么是Java agent技术?

Java署理(Java agent)是一种Java技术,它允许开辟人员在运行时以某种方式修改或增强Java应用程序的举动。Java署理通过在Java假造机(JVM)启动时以"署理"(agent)的形式加载到JVM中,以监视、修改或甚至完全改变目标应用程序的举动。
Java agent 可以做什么?


  • 安全监控和审计:
    通过Java署理,可以在应用程序中注入代码以监视其举动并记载关键事件。这可以用于安全审计目的,以确保应用程序不受到恶意举动或违规操作的影响。

  • 安全验证和授权:
    Java署理可以拦截对受保护资源的访问,并执行安全验证和授权操作。通过署理,可以实现访问控制计谋,确保只有经过授权的用户或系统可以访问特定资源。

  • 安全加固:
    通过Java署理,可以对应用程序进行安全加固,例如及时检测和防御攻击,包罗代码注入、SQL注入、跨站点脚本攻击等。署理可以拦截哀求,并根据安全计谋进行处理,从而提高应用程序的安全性。

  • 加密和解密:
    Java署理可以用于实现端到端的数据加密和解密,保护敏感数据在传输过程中的安全性。署理可以拦截数据流,对数据进行加密或解密操作,以确保数据在传输过程中不会被盗取或窜改。

  • 安全日记记载:
    Java署理可以用于记载应用程序的安全日记,包罗用户操作、异常事件、安全警报等。通过署理,可以将安全日记发送到中央日记服务器进行集中管理和分析,以便及时发现和应对安全威胁。

静态Agent使用

创建Maven项目,写一个类PreMainTraceAgent,使用Maven编译并打成jar包。
  1. package com.example;
  2. import java.lang.instrument.ClassFileTransformer;
  3. import java.lang.instrument.IllegalClassFormatException;
  4. import java.lang.instrument.Instrumentation;
  5. import java.security.ProtectionDomain;
  6. public class PreMainTraceAgent {
  7. public static void premain(String agentArgs, Instrumentation inst) {
  8. System.out.println("agentArgs : " + agentArgs);
  9. inst.addTransformer(new DefineTransformer(), true);
  10. }
  11. static class DefineTransformer implements ClassFileTransformer {
  12. static int counts=0;
  13. @Override
  14. public byte[] transform(
  15. ClassLoader loader,
  16. String className,
  17. Class<?> classBeingRedefined,
  18. ProtectionDomain protectionDomain,
  19. byte[] classfileBuffer
  20. ) throws IllegalClassFormatException {
  21. System.out.println("premain load Class:" + className);
  22. System.out.println("filter "+(counts++)+" class");
  23. return classfileBuffer;
  24. }
  25. }
  26. }
复制代码
打成jar包之后我们要注意META-INF目录下的MSNIFEST.MF文件,MANIFEST.MF文件是 Java 归档文件(如 JAR文件)的一部分,用于描述归档文件的元数据信息和配置。它通常位于归档文件的根目录下。


一些常见的属性我们需要相识

  • Manifest-Version: 描述了 MANIFEST.MF 文件的版本。
  • Created-By: 描述了创建该归档文件的工具名称和版本。
  • Main-Class: 描述了可执行 JAR 文件的入口类(Main类),当您执行 JAR
    文件时,Java假造机会自动寻找并执行该类中的main方法。

  • Class-Path: 描述了归档文件中包含的依赖项 JAR 文件的路径,以便 Java
    假造机在运行时能够找到并加载这些依赖项。

在构建和部署 Java 应用程序时,MANIFEST.MF文件可以资助指定各种元数据信息,使得应用程序可以更好地被管理和执行。例如,当您创建一个可执行的JAR 文件时,通过指定 Main-Class 属性,可以告诉 Java 假造机该 JAR文件的入口点是哪个类。
另外创建一个项目,写一个主函数,内容随意,配置假造机选项。这里-javaagent:后面跟上上面项目jar包的绝对路径
[img=720,614.88]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403061541860.png[/img]

运行效果如图:
[img=720,347.04]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403061541861.png[/img]

可以看到premain方法中的代码成功的执行在了Main函数之前。这种使用premain方法在Main函数前执行的也被成为静态agent
【----资助网安学习,以下所有学习资料免费领!加vx:dctintin,备注 “博客园” 获取!】
 ① 网安学习成长路径头脑导图
 ② 60+网安经典常用工具包
 ③ 100+SRC漏洞分析报告
 ④ 150+网安攻防实战技术电子书
 ⑤ 最权威CISSP 认证考试指南+题库
 ⑥ 超1800页CTF实战本事手册
 ⑦ 最新网安大厂面试题合集(含答案)
 ⑧ APP客户端安全检测指南(安卓+IOS)
动态Agent使用

首先是被署理部分(单独的项目)
  1. package com.example;
  2. import java.lang.instrument.ClassFileTransformer;
  3. import java.lang.instrument.IllegalClassFormatException;
  4. import java.lang.instrument.Instrumentation;
  5. import java.security.ProtectionDomain;
  6. public class AgentMain {
  7. public static void agentmain(String agentArgs, Instrumentation
  8. instrumentation) {
  9. instrumentation.addTransformer(new MyTransformer(),true);
  10. }
  11. public static class MyTransformer implements ClassFileTransformer {
  12. static int count = 0;
  13. @Override
  14. public byte[] transform(
  15. ClassLoader loader,
  16. String className,
  17. Class<?> classBeingRedefined,
  18. ProtectionDomain protectionDomain,
  19. byte[] classfileBuffer) throws IllegalClassFormatException {
  20. System.out.println("hello world");//这里就是我们能看到的输出。
  21. return classfileBuffer;
  22. }
  23. }
  24. }
复制代码
接下来就是使用Maven打成jar包
默认情况下META-INFMANIFEST.MF文件中有这些内容
Manifest-Version: 1.0
Created-By: Maven JAR Plugin 3.3.0
Build-Jdk-Spec: 11
但是这些是不敷的,我们需要指出被署理的类。
Manifest-Version: 1.0
Agent-Class: com.example.AgentMain
Can-Redefine-Classes: true
Can-Retransform-Classes: true

  • Agent-Class:指定了署理的入口类。这个属性告诉 Java
    假造机署理应该从哪个类的 premain 或 agentmain方法开始执行。premain 方法用于静态署理(在 JVM启动时加载),而 agentmain 方法用于动态署理(在 JVM运行时加载)。署理的入口类必须包含其中一个方法。

  • Can-Redefine-Classes:指定了署理是否可以重新定义类。如果设置为
    true,署理将允许重新定义已经加载的类,这意味着你可以修改已经加载的类的字节码。这对于某些署理操作,如热代码替换,非常有用。

  • Can-Retransform-Classes:指定了署理是否可以重新转换类。如果设置为
    true,署理将允许重新转换已经加载的类,这意味着你可以多次修改已经加载的类的字节码。这对于一些特定的署理操作也黑白常有用的,如AOP(面向切面编程)。

因为是动态加载所以我们不需要在假造机启动选项中指定jar包的路径。
接下来写主程序的测试类
  1. package org.example;
  2. import com.sun.tools.attach.VirtualMachine;
  3. import java.io.File;
  4. import java.lang.management.ManagementFactory;
  5. public class TestMain {
  6. public static void main(String[] args) {
  7. String agentJarPath =
  8. "C:Users86186DesktopstudyJavauntitledtargetuntitled-1.0-SNAPSHOT.jar";
  9. File agentJarFile = new File(agentJarPath);
  10. if (!agentJarFile.exists()) {
  11. System.err.println("Agent JAR file not found.");
  12. return;
  13. }
  14. String name = ManagementFactory.getRuntimeMXBean().getName();
  15. String pid = name.split("@")[0];
  16. if (pid == null) {
  17. System.err.println("Unable to find process ID.");
  18. return;
  19. }
  20. String targetClassName = "AgentMain";
  21. try {
  22. VirtualMachine vm = VirtualMachine.attach(pid);
  23. vm.loadAgent(agentJarPath,targetClassName);
  24. vm.detach();
  25. } catch (Exception e) {
  26. e.printStackTrace();
  27. }
  28. }
  29. }
复制代码
这里在获取进程号的时间会因为版本的不同而出现错误,java9以下默认是正常的,java9以上会出现报错,我们需要在假造机启动参数中加上-Djdk.attach.allowAttachSelf=true。
[img=720,714.24]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403061541862.png[/img]

运行效果:
[img=720,303.12]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403061541863.png[/img]

为什么效果中有多个helloworld

这里有讲一下为什么我们在代码中之用了一次sout,但是在效果中却出现了多个helloworld。
MyTransformer类中的transform方法中的输出语句只会在类被加载时执行一次,但是它会对每个类文件调用一次。由于一个类可能会由多个ClassLoader加载,大概同一个ClassLoader可能会加载多次,因此会导致多次输出。
这种情况通常在Java应用程序中使用了多个ClassLoader时发生,例如Web应用程序中的热部署大概OSGi环境中。每次类被加载,transform方法都会被调用一次,因此会看到多次输出。
我们可以修改一下代码做测试,这里我在每个helloworld后添加了被加载类的名字
[img=720,165.6]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403061541864.png[/img]

修改后的输出效果:
[img=720,291.6]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403061541865.png[/img]

实战示例:修改目标假造机中执行的程序

第一步

首先我们写出我们正在执行的程序:循环打印helloworld。
  1. package org.example;
  2. import static java.lang.Thread.sleep;
  3. public class Main {
  4. public static void main(String[] args) throws InterruptedException {
  5. while(true) {
  6. hello();
  7. sleep(1500);
  8. }
  9. }
  10. public static void hello(){
  11. System.out.println("Hello World!");
  12. }
  13. }
复制代码
[img=720,536.4]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403061541866.png[/img]

第二步

准备我们的agentmain和ClassFileTransformer实现类。
  1. package com.example;
  2. import java.lang.instrument.ClassFileTransformer;
  3. import java.lang.instrument.IllegalClassFormatException;
  4. import java.lang.instrument.Instrumentation;
  5. import java.lang.instrument.UnmodifiableClassException;
  6. import java.security.ProtectionDomain;
  7. public class AgentMain {
  8. public static void agentmain(String agentArgs, Instrumentation
  9. instrumentation) throws UnmodifiableClassException {
  10. Class [] classes = instrumentation.getAllLoadedClasses();
  11. //获取目标JVM加载的全部类
  12. for(Class cls : classes){
  13. if (cls.getName().equals("org.example.Main")){
  14. instrumentation.addTransformer(new HackTransform(),true);
  15. instrumentation.retransformClasses(cls);
  16. }
  17. // System.out.println(cls.getName());
  18. }
  19. }
  20. }
  21. package com.example;
  22. import javassist.ClassClassPath;
  23. import javassist.ClassPool;
  24. import javassist.CtClass;
  25. import javassist.CtMethod;
  26. import java.io.IOException;
  27. import java.lang.instrument.ClassFileTransformer;
  28. import java.lang.instrument.IllegalClassFormatException;
  29. import java.security.ProtectionDomain;
  30. public class HackTransform implements ClassFileTransformer {
  31. @Override
  32. public byte[] transform(ClassLoader loader, String className,
  33. Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
  34. byte[] classfileBuffer) throws IllegalClassFormatException {
  35. if (className.equals("org/example/Main")) {
  36. try {
  37. System.out.println(className);
  38. ClassPool classPool = ClassPool.getDefault();
  39. if (classBeingRedefined != null) {
  40. ClassClassPath ccp = new ClassClassPath(classBeingRedefined);
  41. classPool.insertClassPath(ccp);
  42. }
  43. CtClass ctClass = classPool.get("org.example.Main");
  44. System.out.println(ctClass);
  45. CtMethod ctMethod = ctClass.getDeclaredMethod("hello");
  46. //设置方法体
  47. String body = "{System.out.println("[+]Hacker!!");}";
  48. ctMethod.setBody(body);
  49. ctClass.defrost();
  50. return ctClass.toBytecode();
  51. } catch (Exception e) {
  52. e.printStackTrace();
  53. }
  54. }
  55. return null;
  56. }
  57. }
复制代码
第三步

把第二步中的两个类打成jar包。并修改其中MANIFEST.MF中的内容。
[img=720,428.4]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403061541868.png[/img]

MANIFEST.MF中的内容
Manifest-Version: 1.0Agent-Class:com.example.AgentMainCan-Redefine-Classes: trueCan-Retransform-Classes:true
第四步

写我们的注入代码
  1. package org.example;
  2. import com.sun.tools.attach.*;
  3. import java.io.IOException;
  4. import java.util.List;
  5. public class inject {
  6. public static void main(String[] args) throws IOException,
  7. AttachNotSupportedException, AgentLoadException,
  8. AgentInitializationException {
  9. //调用VirtualMachine.list()获取正在运行的JVM列表
  10. List<VirtualMachineDescriptor> list = VirtualMachine.list();
  11. for (VirtualMachineDescriptor vmd : list) {
  12. System.out.println(vmd.displayName());
  13. if (vmd.displayName().equals("org.example.Main")) {
  14. //连接指定JVM
  15. VirtualMachine virtualMachine = VirtualMachine.attach(vmd.id());
  16. String agentJarPath =
  17. "C:Users86186DesktopstudyJavauntitledtargetuntitled-1.0-SNAPSHOT.jar";
  18. //加载Agent
  19. virtualMachine.loadAgent(agentJarPath,"com.example.AgentMain");
  20. //断开JVM连接
  21. virtualMachine.detach();
  22. }
  23. }
  24. }
  25. }
复制代码
第五步

执行即可(先运行主java程序,后运行注入程序)
[img=720,231.84]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403061541869.png[/img]

[img=720,262.8]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202403061541870.png[/img]


更多网安技能的在线实操练习,请点击这里>>
  

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

道家人

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表