Serialización y deserialización [en la seguridad JAVA de pozo]

0x01

  • ¿Qué es serialización y deserialización?
  • ¿La función clave de serialización y deserialización?
  • ¿Cuáles son las características de los datos después de la deserialización?
  • ¿Cuáles son las similitudes entre la vulnerabilidad de deserialización de Java y la vulnerabilidad de deserialización de PHP?

En este capítulo, solo necesitamos resolver los primeros tres problemas.De hecho, el principio de vulnerabilidad de deserialización de Java es muy simple, pero cada cadena de POP es más complicada. Presentaré brevemente la serialización de java ~

0x02

En mi opinión, el mecanismo de serialización de Java es almacenar un objeto de forma persistente o transmitir un objeto a través de la red. Todos sabemos que una vez que se cierra jvm, el objeto en java también se destruye, por lo que si desea guardarlo, debe convertirlo en una secuencia de bytes y escribirlo en un archivo u otro.

Serialización:
convierte un objeto en una secuencia de bytes Deserialización: convierte una secuencia de bytes en un objeto

0x03

Para que se serialice un objeto de clase, se deben cumplir dos condiciones:

1. Esta clase debe implementar el objeto java.io.Serializable.

2. Todos los atributos de esta clase deben ser serializables. Si hay un atributo que no se puede serializar, el atributo debe marcarse como transitorio. (No prestemos atención a esto por ahora)

0x04

Para serializar un objeto, primero cree un objeto OutputStream, luego encapsúlelo en un objeto ObjectOutputStream, luego simplemente llame a writeObject () para serializar el objeto y enviarlo a OutputStream (el objeto está basado en bytes, Entonces use InputStream y OutputStream para heredar la jerarquía).

Para deserializar un objeto, debe encapsular un InputStream en ObjectInputStream y luego llamar a readObject ().

El texto no es lo suficientemente intuitivo, carguemos el código directamente (preste atención a los comentarios):

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函数");
    // }
}

Una vez ejecutado el programa, se generará un archivo user.ser en el directorio actual y, después de la deserialización, se ejecutará el método info para imprimir la información del usuario en el terminal:

[Error en la transferencia de la imagen del enlace externo. El sitio de origen puede tener un mecanismo de enlace anti-sanguijuela. Se recomienda guardar la imagen y subirla directamente (img-i2xOGYMA-1586689192839) (serialization / ser.png)]

Puede ver que se ejecutó como se esperaba y un archivo user.ser se generó correctamente. El objeto de clase de usuario después de la deserialización se almacena en este archivo. Echemos un vistazo al contenido. Aquí hay una pequeña herramienta xxd en Linux para ver el contenido:

[Error en la transferencia de la imagen del enlace externo. El sitio de origen puede tener un mecanismo de enlace anti-sanguijuelas. Se recomienda guardar la imagen y subirla directamente (img-0qdxA1YY-1586689192840) (serialization / xxd.png)]

En el resultado mostrado por xxd, la columna del medio es la visualización hexadecimal del archivo y la columna más a la derecha es la visualización de caracteres. El valor característico que debe anotarse aquí son los primeros 32 dígitos en la pantalla hexadecimal:

AC ED: STREAM_MAGIC, que declara que se utiliza el protocolo de serialización, a partir del cual se puede determinar si el contenido guardado son datos serializados. (Este es un punto muy importante en la vulnerabilidad de deserialización minera de caja negra)

00 05: STREAM_VERSION, versión del protocolo de serialización.

0x05

Los conceptos básicos de la serialización se han discutido anteriormente, y todos deberían saber cómo serializar y deserializar un objeto. Entonces, ¿dónde están las lagunas? Si conoce la deserialización de php, entonces debería saber php se activan automáticamente al deserializar un objeto __weakup, __destructestas funciones, si hay alguna operación peligrosa entre estas funciones, entonces puede conducir a vulnerabilidades, lo mismo, ¿qué función se activará automáticamente cuando Java deserialice? Así es, es readObject (), pero la función readObject () en la demostración anterior no es un método de ObjectInputStream. Los desarrolladores no pueden controlarlo. ¿Cómo puede causar una vulnerabilidad?

De hecho, Java admite métodos readObject y writeObject personalizados. Siempre que una determinada clase implemente el método readObject de acuerdo con requisitos específicos, se llamará automáticamente durante la deserialización. Si se utiliza el método readObject personalizado Algunas operaciones peligrosas darán lugar a lagunas de deserialización. Pruébelo: todavía usamos la clase anterior, pero esta vez personalizamos el método readObject de la clase User, es decir, eliminamos el último bit de comentario de código, lo ejecutamos nuevamente y vemos el resultado:

[Error en la transferencia de la imagen del enlace externo. El sitio de origen puede tener un mecanismo de enlace anti-sanguijuelas. Se recomienda guardar la imagen y subirla directamente (img-0QqWYEnm-1586689192841) (serialization / custom_readobject.png)]

Como puede ver, ¡el readObject personalizado se ejecuta!

Ahora, escribimos operaciones peligrosas en readObject, como ejecutar comandos del sistema y jugar con wirehark:

[Error en la transferencia de la imagen del enlace externo. Es posible que el sitio de origen tenga un mecanismo de enlace anti-sanguijuelas. Se recomienda guardar la imagen y subirla directamente (img-YLqeVW2x-1586689192841) (serialization / wirehark.png)]

Por supuesto, nadie escribiría esto en aplicaciones reales, pero Li'er es una de esas razones, pero las operaciones peligrosas en aplicaciones reales están relativamente ocultas, no tan desnudas como escribí.

0x06

Creo que alguien, como yo, no debería entender las distintas secuencias en Java (FileOutputStream / BufferedOutputStream / DataOutputStream / ObjectOutputStream). Aquí hay una referencia para ayudar a comprender el código de serialización:
https: // www. cnblogs.com/shitouer/archive/2012/12/19/2823641.html

Inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/he_and/article/details/105474141
Recomendado
Clasificación