Ghost : une grave faille dans la glibc de Linux

Par:
fredericmazue

mer, 28/01/2015 - 11:45

Une grave faille de sécurité, baptisée Ghost, a été découverte dans la glibc de Linux. Cette librairie est au coeur de tous les systèmes Linux.

Selon l'éditeur de solutions de sécurité Qualys qui a publié des informations concernant cette faille, celle-ci est présente depuis la glibc-2.2 qui a été publiée le 10 novembre 2000  

Depuis 2013, d'autres correctifs ont été apportés à cette librairie qui peuvent atténuer la gravité de la faille.

La vulnérabilité se situe dans les fonctions gethostbyname et gethostbyaddr. Elle est exploitable par une classique attaque en débordement de tampon et permet potentiellement la prise de contrôle total, à distance, de la machine attaquée. Si l'exploit n'est pas très facile à réaliser, en revanche, il ne nécessite aucun droit dans le système ni aucune connexion au système préalables. Il suffit de provoquer une résolution DNS sur un nom de domaine mal formé. Ceci peut, selon la configuration du serveur attaqué, être obtenu par exemple par le simple envoi d'un mail.

Les administrateurs système doivent vérifier d'urgence si leurs systèmes sont vulnérables et de toutes façons appliquer d'urgence le correctif, que la plupart des distributions Linux ont déjà mis à disposition.

Le code C ci-dessous, test-ghost.c, permet de tester la vulnérabilité des systèmes et l'efficacité des correctifs appliqués.

Compiler ainsi

gcc test-ghost.c -o test-ghost

Puis lancer le test ainsi

./test-ghost.

Le message Not vulnerable doit s'afficher après application du correctif de sécurité.

#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#define CANARY "in_the_coal_mine"

struct {
  char buffer[1024];
  char canary[sizeof(CANARY)];
} temp = { "buffer", CANARY }; 

int main(void) {
  struct hostent resbuf;
  struct hostent *result;
  int herrno;
  int retval; 

  /*** strlen (name) = size_needed - sizeof (*host_addr) - sizeof (*h_addr_ptrs) - 1; ***/
  size_t len = sizeof(temp.buffer) - 16*sizeof(unsigned char) - 2*sizeof(char *) - 1;
  char name[sizeof(temp.buffer)];
  memset(name, '0', len);
  name[len] = '\0'; 

  retval = gethostbyname_r(name, &resbuf, temp.buffer, sizeof(temp.buffer), &result, &herrno);

  if (strcmp(temp.canary, CANARY) != 0) {
    puts("vulnerable");
    exit(EXIT_SUCCESS);
  }

  if (retval == ERANGE) {
    puts("not vulnerable");
    exit(EXIT_SUCCESS);
  }

  puts("should not happen");
  exit(EXIT_FAILURE);
}