SuiteCRM : vulnérabilité de désérialisation PHAR permettant l’exécution de code
Sam Sanoop
7 mai 2021
0 minutes de lectureSuiteCRM est une application de gestion de la relation client gratuite et open source destinée aux serveurs. Cet avis détaille une vulnérabilité de désérialisation PHAR dans SuiteCRM, qu’un administrateur authentifié pourrait exploiter pour exécuter des commandes sur le système d’exploitation sous-jacent. Ce problème a été corrigé dans la version 7.11.19.
En PHP, les fichiers PHAR (PHP Archive) permettent de regrouper des applications et des bibliothèques PHP dans un seul fichier d’archive. Le format PHAR de PHP utilise un format de fichier unique permettant de stocker et d’exécuter plusieurs codes PHP. Les fichiers PHAR contiennent des métadonnées sur les fichiers de l’archive. Dans un fichier PHAR, ces métadonnées sont stockées sous forme sérialisée.
Lorsqu’une opération sur un fichier PHAR est effectuée via le wrapper phar://, les métadonnées du fichier PHAR sont désérialisées. Ainsi, un attaquant pourrait effectuer une injection d’objet PHP sans utiliser la fonction unserialize(), en téléversant un fichier PHAR. Cette vulnérabilité a notamment gagné en popularité après la publication par Sam Thomas de ses travaux de recherche à BlackHat USA 2018, intitulés C'est une vulnérabilité de désérialisation PHP, Jim, mais pas comme on les connaît, qui concernaient plusieurs systèmes de gestion de contenu. Pour exploiter cette vulnérabilité, deux conditions doivent être réunies :
Une fonction du système de fichiers PHP telle que
file_exists, dont le comportement peut être contrôlé et qui déclenchera la fonctionunserialize()La possibilité de téléverser sur le système cible un fichier PHAR portant l’extension .phar, .zip ou .jpeg, et de connaître le chemin d’accès à ce fichier
Détails techniques de la désérialisation PHAR
Cause racine
Cette vulnérabilité contourne les mécanismes de sécurité mis en place par les responsables de la maintenance de SuiteCRM dans le cadre de la correction de CVE-2020-8801. Comme indiqué dans l’avis concernant CVE-2020-8801, plusieurs sections du panneau d’administration de SuiteCRM, notamment Sauvegardes, Importation et UpgradeWizard, peuvent déclencher une désérialisation PHAR. Les responsables de la maintenance ont corrigé le problème dans la version 7.11.13 avec le commit 571cbfa209da4c8280a5359f301115de25b4c6e3.

La fonction strpos permet de vérifier si un paramètre utilisateur contient une occurrence de l’URI phar://. Toutefois, comme la fonction strpos est utilisée, cette vérification est sensible à la casse. Il est donc possible de la contourner en utilisant des majuscules et de déclencher une désérialisation PHAR en appelant l’URI sous la forme PHAR://.
Trouver un gadget exploitable
Bien qu’il soit possible de contourner le correctif SuiteCRM pour la vérification de l’URI PHAR, nous avons constaté que les responsables de la maintenance de SuiteCRM avaient pris des précautions afin d’empêcher l’utilisation de tous les gadgets POP susceptibles d’être déclenchés par un attaquant au moyen de la désérialisation. Pour cela, ils ont ajouté une méthode magique __wakeup aux classes considérées comme dangereuses. Cette méthode est automatiquement appelée chaque fois qu’un objet est désérialisé et veille à détruire toutes ses propriétés au cours de la désérialisation. En voici un exemple.

Dans modules/Import/sources/ImportFile.php, une méthode magique __destruct peut être détournée pour supprimer arbitrairement des fichiers d’un système par le biais d’une désérialisation non sécurisée. Toutefois, en raison de la présence de la méthode __wakeup mentionnée ci-dessus, un attaquant ne peut pas exploiter cette méthode __destruct. Cette vérification a été repérée dans l’ensemble du code de SuiteCRM.
Cependant, un examen plus approfondi des dépendances de SuiteCRM a permis de trouver une méthode __destruct exploitable pour supprimer des fichiers arbitrairement. SuiteCRM utilise la bibliothèque zend-gdata, qui a pour dépendance transitive zf1/zend-http.
Dans le fichier Stream.php du package zf1/zend-http, une méthode __destruct exécute la fonction @unlink sur la propriété $stream_name d’un objet lorsqu’elle est déclenchée. La fonction @unlink de cette méthode peut être exploitée pour supprimer un fichier. Pour que cette fonction soit déclenchée, l’objet concerné doit également posséder une propriété $_cleanup. Le code de cette méthode __destruct est présenté ci-dessous.

L’existence de ce gadget est déjà connue et il est disponible dans la bibliothèque PHPGGC. PHPGGC est une bibliothèque de charges utiles unserialize(), accompagnée d’un script qui génère une charge utile de gadget POP à partir des paramètres fournis par l’utilisateur.
Remarque : Si les dépendances de développement sont également installées dans une instance SuiteCRM, une version vulnérable de PHP-CS-Fixer peut aussi être exploitée pour supprimer arbitrairement des fichiers, à la place de zf1/zend-http. La pull request qui ajoute ce gadget POP à PHPGGC est disponible ici : https://github.com/ambionics/phpggc/pull/93.
Trouver et exploiter une fonctionnalité de téléversement
Bien que l’avis concernant CVE-2020-8801 explique quels paramètres et quelles sections de SuiteCRM peuvent être utilisés pour déclencher une désérialisation PHAR, ni cet avis ni l’article de blog associé du chercheur ayant découvert le problème ne précisent où téléverser un fichier PHAR ni quel chemin ou emplacement pourrait être exploité. Nous avons également constaté que tout fichier téléversé dans SuiteCRM est renommé sans extension, et que son nom est remplacé par un identifiant UUID aléatoire. Par exemple, le fichier party-parrot.png téléversé avec un document est renommé 51eea769-ce13-40bb-fb25-60197bf855ae.

Cependant, après avoir exploré plus en détail toutes les fonctionnalités de SuiteCRM, nous avons constaté que les fichiers ZIP téléversés via Module Loader ne suivent pas ce comportement : les fichiers ZIP de module sont téléversés et enregistrés à un emplacement arbitraire, avec l’extension .zip, que l’attaquant peut deviner. Cela permet de réunir les conditions nécessaires à l’exploitation d’une vulnérabilité de désérialisation PHAR. En voici un exemple :

Le fichier examplemodule.zip téléversé sera stocké à l’emplacement suivant. Le fichier manifest.php est extrait du répertoire module.zip et se trouve également à cet emplacement.

Déclencher la suppression arbitraire de fichiers
Une fois le chemin d’un fichier ZIP téléversé connu, le gadget de suppression de fichiers identifié et les fonctions déclenchant la désérialisation PHAR disponibles, il est possible d’exploiter ces conditions pour compromettre une installation SuiteCRM.
Avec PHPGGC, il est possible de créer un fichier PHAR d’exemple comme suit :
La commande ci-dessus crée un fichier PHAR au format ZIP nommé malicious.zip. Elle y insère une charge utile sérialisée du gadget POP zf1/zend-http mentionné précédemment et définit la propriété $stream_name de cet objet sérialisé sur /tmp/test.txt. En outre, l’option -f de PHPGGC permet également de garantir la destruction de l’objet sérialisé immédiatement après l’appel à unserialize(), ce qui rend la charge utile plus fiable.
Remarque : Pour que l’application accepte ce fichier ZIP, il faut également y ajouter un fichier manifest.php d’exemple. Sous Linux, vous pouvez procéder comme suit :
Une fois téléversé, ce fichier se trouvera dans le répertoire upload/upgrades/module.

Ce fichier peut alors être déclenché depuis la section Sauvegardes du panneau d’administration de SuiteCRM.

De la suppression de fichiers à l’exécution de code
En exploitant la suppression de fichiers, il est possible de supprimer des fichiers du code source de l’application et de lancer des attaques par déni de service. Il est également possible d’exploiter cette suppression pour exécuter du code arbitraire sur une installation SuiteCRM, en supprimant un fichier .htaccess et en accédant directement aux fichiers téléversés.
Le fichier .htaccess est un fichier de configuration distribué qui permet à Apache de gérer les changements de configuration pour chaque répertoire. Dans une installation SuiteCRM, ce fichier interdit l’accès direct à des répertoires tels que /upload et /files. La désérialisation PHAR peut être exploitée pour supprimer ce fichier. De plus, le fichier mainfest.php mentionné précédemment peut servir à dissimuler et à déclencher du code PHP.
Lorsqu’un module est téléversé via la fonctionnalité Module Loader, SuiteCRM exige également la présence d’un fichier manifest.php. En voici un exemple :

Par défaut, SuiteCRM vérifie que le fichier téléversé ne contient aucun appel de fonction suspect, comme exec ou system. Vous trouverez ici la liste complète des appels de fonction interdits : Restrictions de Module Loader
Cette vérification ne tient pas compte de la fonction « include ». En PHP, la fonction include permet d’inclure des fichiers (des fichiers locaux par défaut), qui sont exécutés comme du code PHP. Il est donc possible de dissimuler une fonction include dans le fichier manifest, en lui passant un paramètre utilisateur (include($_GET['p']);) ; un fichier téléversé (que SuiteCRM renomme) contenant du code PHP malveillant peut alors être fourni pour exécuter du code.
Récapitulatif de la désérialisation PHAR
En résumé, l’exploitation d’une désérialisation PHAR pour exécuter du code se déroule ainsi :
1. Téléverser un fichier dans SuiteCRM
Téléversez un fichier dans SuiteCRM via sa fonctionnalité de stockage habituelle. Dans cet exemple, le fichier suivant est téléversé sous le nom shell.php : <?php echo system($_GET["cmd"]); ?>

L’application le renomme eb7cde01-6190-9ca9-b81b-601998504b41 et le stocke dans le répertoire /var/www/html/uploads. Cet UID apparaît dans l’URL du fichier :
2. Téléverser un fichier PHAR au format ZIP
Téléversez une archive PHAR au format ZIP qui, lorsqu’elle est déclenchée, supprime le fichier .htaccess et contient un fichier manifest.php avec du code PHP dissimulé. Vous pouvez utiliser PHPGGC comme suit :
Ajoutez ensuite le code suivant à un fichier manifest.php, puis ajoutez celui-ci à l’archive PHAR ZIP.
![Éditeur de code affichant une instruction PHP include mise en évidence et utilisant un paramètre 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)
Cette archive ZIP peut ensuite être téléversée dans le système via le composant Module Loader.
3. Déclencher la désérialisation PHAR
Déclenchez la désérialisation PHAR en appelant le fichier maliciousmodule.zip. La section Sauvegardes permet de déclencher la désérialisation PHAR. Voici la requête HTTP envoyée à l’application :
4. Accéder au manifest de maliciousmodule
Accédez au fichier manifest de malicousmodule en naviguant jusqu’au chemin du répertoire et incluez le fichier shell.php.txt téléversé. Maintenant que le fichier .htaccess a été supprimé, le répertoire de téléversement est accessible. Le fichier malcioiusmodule-manifest.php est désormais accessible comme suit :
Vous pouvez maintenant spécifier ?123 et fournir le fichier shell.php.txt :
Le fichier shell.php.txt inclus sera interprété comme du code, et le paramètre cmd pourra être fourni ; la commande système l’exécutera.

Pour conclure
En conclusion, lors de la validation des entrées utilisateur, veillez à ce que les vérifications ne soient pas sensibles à la casse. Par ailleurs, pour corriger et empêcher l’utilisation de gadgets de désérialisation, il faut tenir compte des dépendances transitives, car un projet les charge via la fonctionnalité de chargement automatique de Composer. Snyk Open Source prend également en charge l’analyse PHP et peut servir à analyser les bibliothèques connues et à signaler celles qui ont supprimé les gadgets de désérialisation de leur code.
