dimanche 10 juillet 2011, 21:00:02 (UTC+0200)

Audit partiel des composants Open Source intégrés à VMware ESX (SFCB)

Suite à un pari (que j'ai depuis perdu) avec Marc Olanié, je devais trouver une exécution de code à distance dans les produits ESX/vSphere de VMware, simplement en lisant le code de projets Open Source embarqués dans ces produits. Cet article a pour objectif de présenter les vulnérabilités identifiées lors de cette analyse et leur impact (ou pas) sur ESX/vSphere. De plus, la publication des détails techniques permettra d'identifier d'autres produits incluant des versions vulnérables de ces composants ou souffrant de bugs similaires. La première partie, ici présente, couvre le serveur CIMOM, alors que la deuxième (à venir) abordera SLP.


WBEM est une suite de protocoles veillant à fournir aux administrateurs d'informatique distribuée (dite Cloud) des outils centralisés de gestion, suivi et déploiement. SBLIM est l'implémentation de référence, sous Linux, de ces protocoles. La partie "serveur CIMOM" (pour Common Information Model Object Manager) est implémentée sous le nom de SFCB.


sfcbd (version testée : 1.3.6) écoute sur les ports TCP/5988 (HTTP) ou TCP/5989 (HTTPS) et accepte les requêtes POST et M-POST. Ce service étant avant tout un serveur Web "maison", la première chose à tester (en dehors du GET de 4100 caractères ;-) est la gestion de l'en-tête Content-Length, vu le nombre de vulnérabilités liées à ce traitement (Opera, Nagios, CA iGateway, Quicktime, Apache mod_proxy, Novell eDirectory, ...). Et on n'est pas déçu, l'oeil étant immédiatement attiré par un memcpy() (ligne 406) réalisé sur un tampon dont la taille est fournie par l'attaquant (ligne 405) :

401     static int getPayload(CommHndl conn_fd, Buffer * b)
402     {
403        unsigned int c = b->length - b->ptr;
404        int rc = 0;
405        b->content = (char *) malloc(b->content_length + 8);
406        if (c) memcpy(b->content, (b->data) + b->ptr, c);
407     
408        if (c > b->content_length) {
409          mlogf(M_INFO,M_SHOW,"--- HTTP Content-Length is lying; content truncated\n");
410          c = b->content_length;
411        }
412     
413        rc = readData(conn_fd, (b->content) + c, b->content_length - c);
414        *((b->content) + b->content_length) = 0;
415        return rc;
416     }

Le critère de taille est bel et bien vérifié, mais *après* la copie, donc trop tard. Et hop, un heap overflow (CVE-2010-1937) ! Le correctif pour cette vulnérabilité est trivial, et consiste simplement à vérifier les données *avant* de les utiliser (cf. le diff coloré). Ce qui donne ce type de code :

401     static int getPayload(CommHndl conn_fd, Buffer * b)
402     {
403        unsigned int c = b->length - b->ptr;
404        int rc = 0;
405     
406        if (c > b->content_length) {
407          mlogf(M_INFO, M_SHOW,
408                "--- HTTP Content-Length is lying; rejecting %d %d\n", c, b->content_length);
409          return -1;
410        }
411     
412        b->content = (char *) malloc(b->content_length + 8);
413        if (c) memcpy(b->content, (b->data) + b->ptr, c);
414     
415        rc = readData(conn_fd, (b->content) + c, b->content_length - c);
416        *((b->content) + b->content_length) = 0;
417        return rc;
418     }

Pour autant, l'instruction malloc(b->content_length + 8) (ligne 412) est toujours vulnérable à un débordement d'entier débouchant sur un débordement de tampon si aucune vérification préalable n'a lieu. La fonction doHttpRequest() réalise en amont diverses vérifications sur la valeur du champ Content-Length, dont deux qui nous intéressent dans le cas présent :

841              unsigned int maxLen;
842              if (getControlUNum("httpMaxContentLength", &maxLen) != 0) {
843                genError(conn_fd, &inBuf, 501, "Server misconfigured (httpMaxContentLength)", NULL);
844                _SFCB_TRACE(1, ("--- exiting: bad config httpMaxContentLength"));
845                commClose(conn_fd);
846                exit(1);
847              }
848              if((clen >= UINT_MAX) || ((maxLen) && (clen > maxLen))) {
849                 genError(conn_fd, &inBuf, 413, "Request Entity Too Large", NULL);
850                 _SFCB_TRACE(1, ("--- exiting: content-length too big"));      
851                 commClose(conn_fd);
852                 exit(1);
853              }
854              inBuf.content_length = clen;

La variable clen correspond au b->content_length de getPayload(). Nous avons donc trois cas possibles, selon la valeur de l'option de configuration httpMaxContentLength :

  • elle n'est pas définie dans le fichier de configuration => une erreur est levée
  • elle est définie et vaut zéro => la variable clen doit être inférieure à UINT_MAX
  • elle est définie et est différente de zéro => la variable clen doit être inférieure à UINT_MAX et inférieure ou égale à httpMaxContentLength

Ce débordement d'entier est donc exploitable (CVE-2010-2054) si httpMaxContentLength vaut zéro ou est légèrement inférieure à UINT_MAX. Le correctif (cf. diff coloré) se contente d'interdire la valeur zéro :

842              if ((getControlUNum("httpMaxContentLength", &maxLen) != 0) || (maxLen == 0)) {

La couverture n'est donc pas totale. Un administrateur mal intentionné pourrait par exemple positioner la variable à 4.294.967.290 (soit UINT_MAX - 5), et ainsi introduire un heap overflow exploitable à distance et sans authentification, sans pour autant impacter les aspects fonctionnels :-(


Je me sentais du coup bien parti pour gagner mon pari ! Sauf que les versions testées à l'époque (VMware ESXi 3.5, ESXi 4 et ESX 4) intégraient une version antérieure et modifiée de sfcbd (v1.3.3 sous ESX 4). CVE-2010-1937 y a été corrigé (silencieusement, c'est-à-dire sans informer ni ses clients ni le projet Open Source d'origine) et CVE-2010-2054 n'affecte pas les versions inférieures à 1.3.4.


Carrramba ! Encore raté ! Mais bon, la surface d'attaque d'un ESX côté réseau d'administration est vaste, et SLP fera l'objet de la deuxième partie de cette étude ...


Posté par Nicolas Grégoire | permalien | dans : vulnérabilités
Commentaires (0)

webmaster@agarri.fr
Copyright 2010-2011 Agarri

 Commentaires

Ajouter un commentaire