Kto się boi duchów – resztki po GHOST

Ostatnie dni stały pod znakiem sensacyjnego, bo 14-letniego błędu w bibliotece glibc, która czyniła większość dystrybucji linuksowych podatnymi na zdalny atak. Jak to zwykle bywa, błąd został poprawiony niemal z dnia na dzień, a nawet i rok wcześniej (Google naprawiło glibc w Chrome OS i nikomu się nie pochwaliło). Na dodatek, większość współczesnych dystrybucji nie jest rozprowadzana z tym błędem, zatem i poprawki nie są potrzebne. Kto więc jest zagrożony i powinien się naprawiać?

Błąd o kryptonimie GHOST to typowe wykorzystanie przepełnienia bufora (buffer overflow). A można do niego doprowadzić wykorzystując luki w funkcji __nss_hostname_digits_dots() biblioteki glibc. Służy ona do translacji nazw DNS na adresy IP (i na odwrót). Tym samym podatne na ew. zdalny atak są wszystkie programy/usługi korzystające z protokołu DNS i funkcje gethostbyname*(). W momencie ogłoszenia luki podatne na nią były dystrybucje użytkujące starsze wersje glibc:

  • RHEL (Red Hat Enterprise Linux) version 5.x, 6.x and 7.x
  • CentOS Linux version 5.x, 6.x & 7.x
  • Ubuntu Linux version 10.04, 12.04 LTS
  • Debian Linux version 7.x
  • Linux Mint version 13.0
  • Fedora Linux version 19 or older
  • SUSE Linux Enterprise 11 and older (also OpenSuse Linux 11 or older versions).
  • SUSE Linux Enterprise Software Development Kit 11 SP3
  • SUSE Linux Enterprise Server 11 SP3 for VMware
  • SUSE Linux Enterprise Server 11 SP3
  • SUSE Linux Enterprise Server 11 SP2 LTSS
  • SUSE Linux Enterprise Server 11 SP1 LTSS
  • SUSE Linux Enterprise Server 10 SP4 LTSS
  • SUSE Linux Enterprise Desktop 11 SP3
  • Arch Linux glibc version <= 2.18-1

Należy zaznaczyć, że najpopularniejsze Ubuntu 14.04/14.10 nie są podatne na wspomnianą przypadłość.

Aby sprawdzić, czy nasza maszyna jest podatna na tego rodzaju ataki, możemy wykorzystać poniższy kod:

#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);
}

Wystarczy pobrać, skompilować i uruchomić. Martwimy się, jeżeli wynikiem będzie komunikat „vulnerable”. W tym przypadku należy zaktualizować w swojej dystrybucji glibc.

W większości starszych dystrybucji (wspieranych) powinna wystarczyć typowa aktualizacja. Np. Ubuntu 10.04/12.04/Debian:

sudo apt-get clean
sudo apt-get update
sudo apt-get upgrade

I gotowe. Znaleziona luka z pewnością może wydać się sporym ciosem w bezpieczeństwo Linuksa, jednak należy pamiętać, że poprawki dla tego błędu pojawiły się już jakiś czas temu, choć sam błąd nie został uznany za krytyczny. Starsze dystrybucje otrzymały poprawki niemal z dnia na dzień.