SuiteCRM: vulnerabilidad de deserialización de PHAR que permite ejecutar código
Sam Sanoop
7 de mayo de 2021
0 minutos de lecturaSuiteCRM es una aplicación gratuita y de código abierto de gestión de relaciones con clientes para servidores. Este aviso detalla una vulnerabilidad de deserialización de PHAR en SuiteCRM que un administrador autenticado podría aprovechar para ejecutar comandos en el sistema operativo subyacente. Este problema se corrigió en la versión 7.11.19.
En PHP, los archivos PHAR (PHP Archive) se pueden usar para empaquetar aplicaciones y bibliotecas PHP en un solo archivo. El formato PHAR de PHP utiliza un formato de archivo único para almacenar y ejecutar varios códigos PHP. Los archivos PHAR contienen metadatos sobre los archivos del archivo comprimido. En un archivo PHAR, estos metadatos se almacenan en formato serializado.
Si se realiza una operación de archivo en un archivo PHAR mediante el wrapper phar://, los metadatos del archivo PHAR se deserializan. Por lo tanto, un atacante podría realizar una inyección de objetos PHP sin usar la función unserialize(), mediante la carga de un archivo PHAR. Esta vulnerabilidad ganó popularidad después de que Sam Thomas publicara su investigación en BlackHat USA 2018, titulada It's a PHP Unserialization Vulnerability Jim, but Not as We Know It, que afectó a varios sistemas de gestión de contenidos. Para explotar esta vulnerabilidad, deben cumplirse dos condiciones:
Una función del sistema de archivos de PHP, como
file_exists, cuyo control pueda obtenerse y que active la funciónunserialize()La capacidad de cargar en el sistema objetivo un archivo PHAR con la extensión .phar, .zip o .jpeg, y conocer la ruta de este archivo
Detalles técnicos de la deserialización de PHAR
Causa raíz
Esta vulnerabilidad evade los mecanismos de seguridad implementados por los responsables de SuiteCRM como parte de la corrección de CVE-2020-8801. Como se indica en el aviso sobre CVE-2020-8801, se puede activar la deserialización de PHAR desde varias secciones del panel de administración de SuiteCRM, como Copias de seguridad, Importación y UpgradeWizard. Los responsables corrigieron este problema en la versión 7.11.13 mediante el commit 571cbfa209da4c8280a5359f301115de25b4c6e3.

La función strpos se usa para comprobar si un parámetro del usuario contiene una aparición de la URI phar://. Sin embargo, debido al uso de la función strpos, esta comprobación distingue entre mayúsculas y minúsculas. Por lo tanto, es posible evadirla usando letras mayúsculas y activar la deserialización de PHAR mediante la llamada PHAR://.
Encontrar un gadget utilizable
Aunque es posible evadir el parche de SuiteCRM para la comprobación de la URI PHAR, se descubrió que los responsables de SuiteCRM tomaron precauciones para impedir el uso de todos los gadgets POP posibles que un atacante podría activar mediante la deserialización. Para ello, agregaron un método mágico __wakeup a las clases consideradas peligrosas. Este método se invoca automáticamente cada vez que se deserializa un objeto y garantiza que se destruyan todas sus propiedades durante la deserialización. A continuación se muestra un ejemplo.

En modules/Import/sources/ImportFile.php, existe un método mágico __destruct que se podría aprovechar para eliminar archivos arbitrarios del sistema mediante una deserialización insegura. Sin embargo, debido a la presencia del método __wakeup mencionado anteriormente, un atacante no puede aprovechar este método __destruct. Esta comprobación se encontró en todo el código base de SuiteCRM.
Sin embargo, al examinar más de cerca las dependencias de SuiteCRM, se pudo encontrar un método __destruct utilizable para eliminar archivos arbitrarios. SuiteCRM usa la biblioteca zend-gdata, que a su vez usa zf1/zend-http como dependencia transitiva.
En el archivo Stream.php del paquete zf1/zend-http, existe un método __destruct que, al activarse, ejecuta la función @unlink en la propiedad $stream_name de un objeto. La función @unlink de este método se puede aprovechar para eliminar un archivo. Para que esta función se active, también debe existir una propiedad $_cleanup para el objeto en cuestión. A continuación se muestra el código de este método __destruct.

La existencia de este gadget ya es conocida y está disponible para usarse en la biblioteca PHPGGC. PHPGGC es una biblioteca de cargas útiles para unserialize() que incluye un script para generar una carga útil de gadget POP a partir de los parámetros proporcionados por el usuario.
Nota: Si también se instalan todas las dependencias de desarrollo en una instalación de SuiteCRM, se puede aprovechar una versión vulnerable de PHP-CS-Fixer para eliminar archivos arbitrarios en lugar de zf1/zend-http. Aquí puedes consultar el pull request que integra este gadget POP en PHPGGC: https://github.com/ambionics/phpggc/pull/93.
Encontrar y aprovechar una funcionalidad de carga
Aunque el aviso sobre CVE-2020-8801 explica los parámetros y las secciones de SuiteCRM que se pueden usar para la deserialización de PHAR, ni el aviso ni la entrada de blog relacionada del investigador que descubrió este problema indican dónde se puede cargar un archivo PHAR ni qué ruta o ubicación se podría aprovechar. Además, se descubrió que todos los archivos que se cargan en SuiteCRM se renombran sin extensión y reciben un identificador UUID aleatorio. Por ejemplo, el archivo party-parrot.png que se carga como parte de un documento se renombrará a 51eea769-ce13-40bb-fb25-60197bf855ae.

Sin embargo, al revisar con más detalle todas las funcionalidades de SuiteCRM, se descubrió que las cargas de archivos ZIP del Module Loader no siguen este comportamiento: los archivos ZIP de módulos se cargan y guardan en una ubicación arbitraria con la extensión .zip, que un atacante puede adivinar. Esto puede servir para cumplir los requisitos de una vulnerabilidad de deserialización de PHAR. A continuación se muestra un ejemplo:

El archivo examplemodule.zip cargado se guardará en la siguiente ubicación. El archivo manifest.php se toma del directorio module.zip y también está disponible en esa misma ubicación.

Activar la eliminación arbitraria de archivos
Ahora que se conoce la ruta de un archivo ZIP cargado, que hay un gadget de eliminación de archivos y que existen funciones que activan la deserialización de PHAR, es posible aprovechar estas condiciones para explotar una instalación de SuiteCRM.
Con PHPGGC, se puede crear un archivo PHAR de ejemplo de la siguiente manera:
El comando anterior creará un archivo PHAR en formato ZIP con el nombre malicious.zip. Esto insertará una carga útil serializada del gadget POP zf1/zend-http mencionado anteriormente y establecerá la propiedad $stream_name de este objeto serializado en /tmp/test.txt. Además, la opción -f de PHPGGC también se puede usar para garantizar que el objeto serializado se destruya inmediatamente después de la llamada a unserialize(), lo que hace que la carga útil sea más confiable.
Nota: Para que la aplicación acepte este archivo ZIP, también hay que agregar un archivo manifest.php de ejemplo al ZIP. En Linux, puedes hacerlo de la siguiente manera:
Una vez cargado, este archivo estará en el directorio upload/upgrades/module.

Ahora se puede activar este archivo desde la sección Copias de seguridad del panel de administración de SuiteCRM.

De la eliminación de archivos a la ejecución de código
Al aprovechar la eliminación de archivos, es posible eliminar archivos del código fuente de la aplicación y llevar a cabo ataques de denegación de servicio. También es posible aprovecharla para ejecutar código arbitrario en una instalación de SuiteCRM: basta con eliminar un archivo .htaccess y acceder directamente a los archivos cargados.
El archivo .htaccess es un archivo de configuración distribuido que permite a Apache gestionar los cambios de configuración por directorio. En una instalación de SuiteCRM, este archivo impide el acceso directo a directorios como /upload y /files. Se puede aprovechar la deserialización de PHAR para eliminar este archivo. Además, el archivo mainfest.php mencionado anteriormente se puede usar para ocultar y activar código PHP.
Al cargar un módulo mediante la funcionalidad Module Loader, SuiteCRM requiere que también haya un archivo manifest.php. A continuación se muestra un ejemplo:

De forma predeterminada, SuiteCRM comprueba que el archivo cargado no contenga llamadas a funciones sospechosas, como exec o system. Aquí puedes consultar la lista completa de llamadas a funciones restringidas: Restricciones de Module Loader
Esta comprobación no tiene en cuenta la función “include”. En PHP, la función include se puede usar para incluir archivos (de forma predeterminada, archivos locales), que luego se ejecutan como código PHP. Por lo tanto, se puede ocultar una función include en el archivo manifest para que acepte un parámetro del usuario (include($_GET['p']);); después, se puede proporcionar un archivo cargado (que SuiteCRM renombra) con código PHP malicioso para lograr la ejecución de código.
Resumen de la deserialización de PHAR
En resumen, el proceso para pasar de la deserialización de PHAR a la ejecución de código es el siguiente:
1. Cargar un archivo en SuiteCRM
Cargar un archivo en SuiteCRM mediante su funcionalidad de almacenamiento habitual. En este ejemplo, se carga el siguiente archivo como shell.php: <?php echo system($_GET["cmd"]); ?>

La aplicación le cambia el nombre a eb7cde01-6190-9ca9-b81b-601998504b41 y lo almacena en el directorio /var/www/html/uploads. Este UID se puede ver en la URL del archivo:
2. Cargar un PHAR ZIP
Cargar un archivo PHAR ZIP que, al activarse, elimine el archivo .htaccess y que incluya un manifest.php con código PHP oculto. Se puede usar PHPGGC de la siguiente manera:
Después, se puede agregar el siguiente código a un archivo manifest.php y añadirlo al archivo PHAR ZIP.
![Editor de código que muestra una instrucción include de PHP resaltada que usa un parámetro GET: include($_GET[123]);](https://res.cloudinary.com/snyk/image/upload/f_auto,w_2560,q_auto/f_auto/q_auto/v1620399714/wordpress-sync/blog-suitecrm-phar-include.png)
Luego, se puede cargar este archivo ZIP en el sistema mediante el componente Module Loader.
3. Activar la deserialización de PHAR
Activar la deserialización de PHAR llamando al archivo maliciousmodule.zip. Se puede usar la sección Copias de seguridad para activar la deserialización de PHAR. La solicitud HTTP enviada a la aplicación es la siguiente:
4. Acceder al manifest de maliciousmodule
Acceder al archivo manifest de malicousmodule navegando a la ruta del directorio e incluyendo el archivo shell.php.txt cargado. Ahora que se eliminó el archivo .htaccess, se puede acceder al directorio de cargas. El archivo malcioiusmodule-manifest.php ahora está disponible en la siguiente ruta:
Ahora se puede especificar ?123 y proporcionar el archivo shell.php.txt:
El archivo shell.php.txt incluido se interpretará como código, y se puede proporcionar el parámetro cmd, que ejecutará el comando del sistema.

Conclusión
En conclusión, al validar la entrada del usuario, se deben tomar precauciones para garantizar que las comprobaciones no distingan entre mayúsculas y minúsculas. Además, al corregir y prevenir el uso de gadgets de deserialización, hay que tener en cuenta las dependencias transitivas, ya que un proyecto las carga mediante la función de carga automática de Composer. Snyk Open Source también es compatible con el análisis de PHP y se puede usar para analizar e informar sobre bibliotecas conocidas que eliminaron de su código los gadgets de deserialización.
