[Into the pit JAVA security] serialization and deserialization

0x01

  • What is serialization and deserialization?
  • The key function of serialization and deserialization?
  • What are the characteristics of the data after deserialization?
  • What are the similarities between java deserialization vulnerability and php deserialization vulnerability?

In this chapter, we only need to figure out the first three issues. In fact, the principle of java deserialization vulnerability is very simple, but each POP chain is more complicated. I will briefly introduce the serialization of java~

0x02

In my opinion, the serialization mechanism of java is to store an object persistently or transmit an object over the network. We all know that once the jvm is closed, the object in java is also destroyed, so if you want to save it, you need to convert it to a byte sequence and write it to a file or other.

Serialization: Convert an object to a sequence of bytes
Deserialization: Convert a sequence of bytes to an object

0x03

For a class object to be serialized, two conditions must be met:

1. This class must implement the java.io.Serializable object.

2. All attributes of this class must be serializable. If there is an attribute that is not serializable, the attribute must be marked as transient. (Let’s not pay attention to this for now)

0x04

To serialize an object, first create an OutputStream object, then encapsulate it in an ObjectOutputStream object, then just call writeObject() to serialize the object and send it to the OutputStream (the object is byte-based, So use InputStream and OutputStream to inherit the hierarchy).

To deserialize an object, you need to encapsulate an InputStream in ObjectInputStream, and then call readObject().

The text is not intuitive enough, let's directly upload the code (pay attention to the comments):

import java.io.*;

public class Test {
    
    

    public static void main(String[] args){
    
    
        User user = new User("axin", 18, 180);
        try {
    
    
            // 创建一个FIleOutputStream
            FileOutputStream fos = new FileOutputStream("./user.ser");
            // 将这个FIleOutputStream封装到ObjectOutputStream中
            ObjectOutputStream os = new ObjectOutputStream(fos);
            // 调用writeObject方法,序列化对象到文件user.ser中
            os.writeObject(user);
            
            System.out.println("读取数据:");
            //  创建一个FIleInutputStream
            FileInputStream fis = new FileInputStream("./user.ser");
            // 将FileInputStream封装到ObjectInputStream中
            ObjectInputStream oi = new ObjectInputStream(fis);
            // 调用readObject从user.ser中反序列化出对象,还需要进行一下类型转换,默认是Object类型
            User user1 = (User)oi.readObject();
            
            user1.info();
        } catch (FileNotFoundException e) {
    
    
            e.printStackTrace();
        } catch (IOException e) {
    
    
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
    
    
            e.printStackTrace();
        }
    }
}

class User implements Serializable{
    
    
    private String name;
    private int age;
    private float height;

    public User(String name, int age, float height) {
    
    
        this.name = name;
        this.age = age;
        this.height = height;
    }

    public void info(){
    
    
        System.out.println("Name: "+name+", Age: "+age+", Height: "+height);
    }

    // private void readObject(ObjectInputStream input) throws IOException, ClassNotFoundException{
    
    
    //     System.out.println("[*]执行了自定义的readObject函数");
    // }
}

After the program is executed, a user.ser file will be generated in the current directory, and after deserialization, the info method will be executed to print out the User information on the terminal:

[External link image transfer failed. The source site may have an anti-leech link mechanism. It is recommended to save the image and upload it directly (img-i2xOGYMA-1586689192839)(serialization/ser.png)]

You can see that it was executed as expected, and a user.ser file was successfully generated. The user class object after deserialization is stored in this file. Let's take a look at the content. Here is a small tool xxd under Linux to view the content:

[External link image transfer failed. The origin site may have an anti-leech link mechanism. It is recommended to save the image and upload it directly (img-0qdxA1YY-1586689192840)(serialization/xxd.png)]

In the result displayed by xxd, the middle column is the hexadecimal display of the file, and the rightmost column is the character display. The characteristic value to be noted here is the first 32 digits in hexadecimal display:

AC ED: STREAM_MAGIC, which declares that the serialization protocol is used, from which you can determine whether the saved content is serialized data. (This is a very important point in the black box mining deserialization vulnerability)

00 05: STREAM_VERSION, serialization protocol version.

0x05

The basics of serialization have been discussed above, and everyone should know how to serialize and deserialize an object. So, where are the loopholes? If you know php deserialization, then you should know php automatically triggered when deserializing an object __weakup, __destructthese functions, if there are some dangerous operation among these functions, then it may lead to vulnerabilities, the same, which function will be triggered automatically when java deserialize it? That's right, it is readObject(), but the readObject() function in the demo above is not a method of ObjectInputStream. Developers can't control it. How can it cause a vulnerability?

In fact, Java supports custom readObject and writeObject methods. As long as a certain class implements the readObject method according to specific requirements, it will be automatically called during deserialization. If the custom readObject method is used Some dangerous operations will lead to deserialization loopholes. Try it out: we still use the above class, but this time we customize the readObject method of the User class, that is, remove the last bit of code comment, execute it again, and view the result:

[External link image transfer failed. The origin site may have an anti-leech link mechanism. It is recommended to save the image and upload it directly (img-0QqWYEnm-1586689192841)(serialization/custom_readobject.png)]

As you can see, the custom readObject is indeed executed!

Now, we write dangerous operations in readObject, such as executing system commands and playing wireshark:

[External link image transfer failed. The source site may have an anti-leech link mechanism. It is recommended to save the image and upload it directly (img-YLqeVW2x-1586689192841)(serialization/wireshark.png)]

Of course, no one would write this in real applications, but Li'er is just such a reason, but dangerous operations in real applications are relatively hidden, not as naked as I wrote

0x06

I think someone, like me, should not understand the various streams in java (FileOutputStream/BufferedOutputStream/DataOutputStream/ObjectOutputStream). Here is a reference to help understand the serialization code:
https://www. cnblogs.com/shitouer/archive/2012/12/19/2823641.html

Insert picture description here

Guess you like

Origin blog.csdn.net/he_and/article/details/105474141