Deserialization
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
La serialización se entiende como el método de convertir un objeto en un formato que puede ser preservado, con la intención de almacenar el objeto o transmitirlo como parte de un proceso de comunicación. Esta técnica se emplea comúnmente para asegurar que el objeto pueda ser recreado en un momento posterior, manteniendo su estructura y estado.
La deserialización, por el contrario, es el proceso que contrarresta la serialización. Implica tomar datos que han sido estructurados en un formato específico y reconstruirlos de nuevo en un objeto.
La deserialización puede ser peligrosa porque potencialmente permite a los atacantes manipular los datos serializados para ejecutar código dañino o causar un comportamiento inesperado en la aplicación durante el proceso de reconstrucción del objeto.
En PHP, se utilizan métodos mágicos específicos durante los procesos de serialización y deserialización:
__sleep
: Invocado cuando un objeto está siendo serializado. Este método debe devolver un array con los nombres de todas las propiedades del objeto que deben ser serializadas. Se utiliza comúnmente para comprometer datos pendientes o realizar tareas de limpieza similares.
__wakeup
: Llamado cuando un objeto está siendo deserializado. Se utiliza para restablecer cualquier conexión a la base de datos que pueda haberse perdido durante la serialización y realizar otras tareas de reinicialización.
__unserialize
: Este método se llama en lugar de __wakeup
(si existe) cuando un objeto está siendo deserializado. Ofrece más control sobre el proceso de deserialización en comparación con __wakeup
.
__destruct
: Este método se llama cuando un objeto está a punto de ser destruido o cuando el script termina. Se utiliza típicamente para tareas de limpieza, como cerrar manejadores de archivos o conexiones a bases de datos.
__toString
: Este método permite que un objeto sea tratado como una cadena. Puede ser utilizado para leer un archivo u otras tareas basadas en las llamadas a funciones dentro de él, proporcionando efectivamente una representación textual del objeto.
Si miras los resultados, puedes ver que las funciones __wakeup
y __destruct
se llaman cuando el objeto es deserializado. Ten en cuenta que en varios tutoriales encontrarás que la función __toString
se llama al intentar imprimir algún atributo, pero aparentemente eso ya no está sucediendo.
El método __unserialize(array $data)
se llama en lugar de __wakeup()
si está implementado en la clase. Te permite deserializar el objeto proporcionando los datos serializados como un array. Puedes usar este método para deserializar propiedades y realizar cualquier tarea necesaria al deserializar.
Puedes leer un ejemplo de PHP explicado aquí: https://www.notsosecure.com/remote-code-execution-via-php-unserialize/, aquí https://www.exploit-db.com/docs/english/44756-deserialization-vulnerability.pdf o aquí https://securitycafe.ro/2015/01/05/understanding-php-object-injection/
Podrías abusar de la funcionalidad de autoload de PHP para cargar archivos php arbitrarios y más:
PHP - Deserialization + Autoload ClassesSi por alguna razón deseas serializar un valor como una referencia a otro valor serializado, puedes:
PHPGGC puede ayudarte a generar payloads para abusar de las deserializaciones de PHP.
Ten en cuenta que en varios casos no podrás encontrar una forma de abusar de una deserialización en el código fuente de la aplicación, pero podrías abusar del código de extensiones PHP externas.
Así que, si puedes, revisa el phpinfo()
del servidor y busca en internet (e incluso en los gadgets de PHPGGC) algunos posibles gadgets que podrías abusar.
Si has encontrado un LFI que solo está leyendo el archivo y no ejecutando el código php dentro de él, por ejemplo, usando funciones como file_get_contents(), fopen(), file() o file_exists(), md5_file(), filemtime() o filesize(). Puedes intentar abusar de una deserialización que ocurre al leer un archivo usando el protocolo phar. Para más información, lee el siguiente post:
phar:// deserializationCuando el objeto se deserializa, se ejecutará la función ___reduce____. Cuando se explota, el servidor podría devolver un error.
Antes de verificar la técnica de bypass, intenta usar print(base64.b64encode(pickle.dumps(P(),2)))
para generar un objeto que sea compatible con python2 si estás ejecutando python3.
Para más información sobre cómo escapar de pickle jails consulta:
Bypass Python sandboxesLa siguiente página presenta la técnica para abusar de una deserialización insegura en bibliotecas de yamls de python y termina con una herramienta que se puede usar para generar cargas útiles de deserialización RCE para Pickle, PyYAML, jsonpickle y ruamel.yaml:
Python Yaml DeserializationJS no tiene funciones "mágicas" como PHP o Python que se ejecutan solo por crear un objeto. Pero tiene algunas funciones que son frecuentemente utilizadas incluso sin ser llamadas directamente como toString
, valueOf
, toJSON
.
Si abusas de una deserialización, puedes comprometer estas funciones para ejecutar otro código (potencialmente abusando de contaminaciones de prototipos) podrías ejecutar código arbitrario cuando sean llamadas.
Otra manera "mágica" de llamar a una función sin llamarla directamente es comprometiendo un objeto que es devuelto por una función asíncrona (promesa). Porque, si transformas ese objeto de retorno en otra promesa con una propiedad llamada "then" de tipo función, será ejecutado solo porque es devuelto por otra promesa. Sigue este enlace para más información.
__proto__
y contaminación de prototype
Si quieres aprender sobre esta técnica echa un vistazo al siguiente tutorial:
NodeJS - __proto__ & prototype PollutionEsta biblioteca permite serializar funciones. Ejemplo:
El objeto serializado se verá así:
Puedes ver en el ejemplo que cuando una función es serializada, la bandera _$$ND_FUNC$$_
se añade al objeto serializado.
Dentro del archivo node-serialize/lib/serialize.js
puedes encontrar la misma bandera y cómo el código la está utilizando.
Como puedes ver en el último fragmento de código, si se encuentra la bandera, se utiliza eval
para deserializar la función, así que básicamente la entrada del usuario se está utilizando dentro de la función eval
.
Sin embargo, simplemente serializar una función no la ejecutará, ya que sería necesario que alguna parte del código llame a y.rce
en nuestro ejemplo y eso es altamente improbable.
De todos modos, podrías modificar el objeto serializado agregando algunos paréntesis para que la función serializada se ejecute automáticamente cuando el objeto sea deserializado.
En el siguiente fragmento de código nota el último paréntesis y cómo la función unserialize
ejecutará automáticamente el código:
Como se indicó anteriormente, esta biblioteca obtendrá el código después de _$$ND_FUNC$$_
y lo ejecutará usando eval
. Por lo tanto, para auto-ejecutar código puedes eliminar la parte de creación de la función y el último paréntesis y simplemente ejecutar un oneliner de JS como en el siguiente ejemplo:
Puedes encontrar aquí más información sobre cómo explotar esta vulnerabilidad.
Un aspecto notable de funcster es la inaccesibilidad de los objetos incorporados estándar; quedan fuera del alcance accesible. Esta restricción impide la ejecución de código que intente invocar métodos en objetos incorporados, lo que lleva a excepciones como "ReferenceError: console is not defined"
cuando se utilizan comandos como console.log()
o require(something)
.
A pesar de esta limitación, es posible restaurar el acceso completo al contexto global, incluidos todos los objetos incorporados estándar, a través de un enfoque específico. Al aprovechar el contexto global directamente, se puede eludir esta restricción. Por ejemplo, el acceso se puede restablecer utilizando el siguiente fragmento:
Para más información, lea esta fuente.
El paquete serialize-javascript está diseñado exclusivamente para fines de serialización, careciendo de cualquier capacidad de deserialización incorporada. Los usuarios son responsables de implementar su propio método para la deserialización. Se sugiere un uso directo de eval
en el ejemplo oficial para deserializar datos serializados:
Si esta función se utiliza para deserializar objetos, puedes explotarlo fácilmente:
Para más información, lea esta fuente.
En las siguientes páginas puedes encontrar información sobre cómo abusar de esta biblioteca para ejecutar comandos arbitrarios: