jeudi 25 août 2011

Apache range header et CVE-2011-3192

Apache est vulnérable à une attaque par déni de service. L'origine de ce CVE débute le 20 Août sur la mailing liste full disclosure par un message de Kingcope. Il propose en effet un petit outil en perl killapache.pl réalisant un denial of service sur les serveurs web apache, toutes versions confondues. Je propose une analyse rapide de celui-ci en deux points: tout d'abord une explication de cette attaque, ensuite les moyens d'en réduire l'impact.

1/ L'attaque
Une lecture rapide du code perl montre qu'il utilise le header HTTP Range. Une explication claire de ce header HTTP est disponible ici. Pour résumer, un serveur HTTP peut ne renvoyer que quelques parties d'un fichier sur demande d'un client à l'aide de l'entête "Range".
Cet outil d'attaque, killapache.pl, envoie une première requête afin de s'assurer que le serveur distant accepte d'envoyer des morceaux de fichiers (des "Range") et si oui l'attaque est lancée [Attention, cette vérification n'est pas fiable, c'est à dire qu'un serveur marqué non vulnérable peut l'être..]. L'outil analyse le code retour de la première requête en cherchant le mot "Partial".

J'ai utilisé socat afin de voir l'attaque fonctionner 'in vivo'. Depuis un xterm je lance donc:
kevin@slackware:~$ socat - TCP-LISTEN:8080,reuseaddr,fork


D'un autre xterm je lance l'attaque (après avoir modifié le script pour qu'il tape le port 8080, constante PeerPort):
kevin@slackware:~$ perl kill_apache.pl 127.0.0.1 

Il suffit d'observer l'attaque après avoir renvoyé "Partial" (une réponse non RFC mais suffisante pour que l'attaque soit lancée):
[je coupe un peu, c'est long.  snip--- snip--- snip--- vous comprenez l'idée de cette ligne d'en-tête. ]
Et les requêtes s'enchaînent.

L'attaque devient évidente. En réponse à ces requêtes, le serveur va donc prendre la page d'accueil du site web attaqué, la zipper 1300 fois puis découper ces 1300 fichiers zippés afin de renvoyer les bonnes parties de celui-ci au client.
Finesse supplémentaire de l'attaque, ce n'est pas un GET, mais un HEAD qui est demandé. Donc le serveur va calculer une très grosse quantité de données et n'en renvoyer que le début ! Nous sommes donc en présence d'un DoS de belle facture où le client avec quelques requêtes va provoquer énormément de travail sur un serveur sans être lui-même impacté.

2/ Mitigations
Un ensemble de bons conseils ont été donnés sur la mailing list apache. Il n'existe pas de solution unique, je décris les idées émises.

Nous avons vu que l'en-tête Range est utile pour n'envoyer qu'une partie des fichiers. Cet en-tête est donc particulièrement employé pour des sites pourvoyeurs de gros pdfs (genre e-readers) ou de videos. En dehors de ces cas ou autre emploi similaire (Webdav?), la désactivation de cet en-tête est la solution la plus simple à mettre en oeuvre:
  RequestHeader unset Range

Une deuxième solution propose de limiter la longueur des en-têtes. Les images ci-dessus montrent que l'en-tête Range: ne fait qu'une seule ligne. La directive de configuration:

        LimitRequestFieldSize 200
permet de bloquer effectivement cette attaque. Deux points sont à considérer. Tout d'abord certains autres en-têtes peuvent légitimement avoir besoin d'une taille supérieure ce qui provoquera un blocage du service se servant de cette en-tête. C'est donc à adapter au cas par cas. Ensuite, cette attaque est appelée à évoluer et il apparaît comme crédible qu'elle fonctionnera avec un en-tête plus petit.

Une troisième solution préconise de limiter le nombre de champ Range dans la même requête au nombre de 5 (limite arbitraire, à adapter, des cas légitimes d'usages existent). Ceci se fait via un module apache développé pour l'occasion, ou des directives de configuration (expliquées dans le mail apache).

Enfin, la dernière solution consiste à attendre :-) Les développeurs apache ont promis une solution dans les 48 heures.

Pour l'historique, L'en tête Range: a déjà souffert d'une faille légèrement similaire en requêtant plusieurs fois le même morceau de fichier: CVE-2007-0086. Mon conseil serait donc de désactiver cet en-tête à moins que le site web en fasse un usage vital. Deux CVE sur un même en-tête HTTP risquent de donner des idées à des attaquants qui chercheront à affiner/modifier cette attaque pour qu'elle soit la plus efficace possible en étant moins bruyante.

3/conclusion
C'est effectivement un attaque fructueuse, certains messages sur des mailings listes indiquent que la machine s'est mise à swapper de manière démesurée jusqu'à provoquer un blocage complet. Les méthodes de mitigation sont très effectives et clairement exposées dans le mail apache. Une proposition d'évolution de la norme HTTP RFC 2616 est faite suite à discussion sur une ML apache.
Ceci dit, je suis surpris qu'on ne parle pas de IIS ou nginx, alors que ceux-ci savent utiliser Range et la compression. Peut-être un autre CVE, je n'ai pas de IIS ou nginx pour tester. Quelqu'un? :-)

EDIT: Le correctif apache, http://www.apache.org/dist/httpd/Announcement2.2.html Edit (bis): il ne s'agit pas du correctif attendu, merci à "Anonyme" de l'avoir signalé. Edit (ter): le lien est correct, la mise à jour est annoncée, c'est bien le 2.2.20 qui corrige ce CVE.
EDIT secondaire: testé rapidement sur un lighttpd et un nginx, conf par défaut après un apt-get debian. Les deux semblent non vulnérables, j'ai plus de CPU consommé par le script killapache.pl que par le webserver :-)

8 commentaires:

  1. J'ai lighttpd, il est vulnérable ou pas?

    RépondreSupprimer
  2. @Anonyme1: la réponse d'anonyme2 est sans doute la meilleure :)

    RépondreSupprimer
  3. Je ne comprends pas le "EDIT" qui indique le correctif : La version est la 2.2.19 qui date de mai 2011, donc antérieure à cette vulnérabilité

    RépondreSupprimer
  4. @Anonyme: erreur de copie de ma part, j'update le message. Sur la ML apache-dev http://www.gossamer-threads.com/lists/apache/dev/, rien de probant, apparemment.

    RépondreSupprimer
  5. Cette fois ça semble être bon (2.2.20) : http://www.apache.org/dist/httpd/Announcement2.2.html

    RépondreSupprimer
  6. @Anonyme: effectivement, cela corrige bien le CVE-2011-3192

    RépondreSupprimer