Récemment, lors de la vérification de la sécurité des ressources Web de la banque, nous avons trouvé une vulnérabilité dans le serveur de messagerie Exim 4.89, qui pourrait conduire à l'exécution de code à distance. La vulnérabilité est connue sous le nom de CVE-2018-6789. En utilisant l'exploit PoC, nous avons obtenu le Reverse Shell sur la machine distante, puis nous avons accédé au site Web de la banque.
Naturellement, nous nous sommes demandé pourquoi une telle exploitation de la vulnérabilité était devenue possible.
D'où vient la CVE-2018-6789?
En bref, la vulnérabilité est due à une erreur de calcul de la longueur du tampon dans la fonction base64.c: b64decode utilisée par Exim. Vous pouvez en savoir plus ici (en anglais).
Si vous entrez une chaîne d'une longueur spéciale, vous pouvez écraser un octet d'informations et, à l'aide d'actions simples, modifier les commandes du serveur, exécutant ainsi du code arbitraire (RCE).
Exim alloue un tampon de 3 * (len / 4) +1 octets pour contenir les données décodées. Cependant, si une chaîne base64 incorrecte est transmise à l'entrée de fonction, par exemple 4n + 3 de long, Exim allouera 3n + 1 octets pour le tampon. Mais en même temps, il écrira 3n + 2 octets de données dans le tampon. Cela provoque l'écrasement d'un octet dans le tas.
Exim fournit store_malloc_3 et store_free_3, qui sont des wrappers pour le malloc et des fonctions gratuites de Glibc. Glibc alloue un gros bloc de données, puis stocke ses métadonnées dans les 0x10 premiers octets et renvoie un pointeur vers la mémoire où l'utilisateur peut écrire ses données. Voici à quoi cela ressemble: Les
métadonnées incluent la taille du bloc précédent (celui en mémoire ci-dessus), la taille du bloc actuel et quelques indicateurs. Les trois premiers bits de la taille sont utilisés pour stocker les indicateurs. Dans l'exemple, la taille 0x81 implique que le bloc actuel est de 0x80 octets et que le bloc précédent est déjà utilisé.
Les blocs libérés, une fois utilisés par Exim, sont placés dans une liste doublement liée. Glibc le maintient en fonction des indicateurs et fusionne les blocs libérés contigus en un plus grand bloc pour éviter la fragmentation. Pour chaque demande d'allocation de mémoire, Glibc examine ces morceaux dans l'ordre FIFO et les réutilise.
Pour améliorer les performances, Exim utilise son propre module complémentaire de gestion de la mémoire; il est basé sur la structure du storeblock. La principale caractéristique de storeblock est que chacun d'eux a une taille d'au moins 0x2000 octets, ce qui devient une limitation pour l'exploitation. Notez que storeblock est également un bloc de données. Voici à quoi cela ressemble en mémoire:
Commandes prises en charge par le serveur de messagerie pour organiser les données sur le tas:
- EHLO hostname. EHLO hostname sender_host_name. , store_free store_malloc .
- . , , Exim .
- AUTH. Exim base64 . , store_get (). store_get().
- Reset EHLO/HELO, MAIL, RCPT. , Exim smtp_reset. store_reset , « ». , storeblock- store_get .
Afin d'utiliser un débordement d'un octet dans le tas, nous devons être en mesure de libérer le bloc de données qui se trouve sous la chaîne décodée en base64. Sender_host_name convient pour cela.
Le tas doit être formé de manière à laisser le bloc de données libéré au-dessus du bloc contenant sender_host_name.
Pour ce faire, vous devez:
1. Mettre un gros bloc dans le bac non trié. Tout d'abord, nous envoyons un message EHLO avec un nom d'hôte surdimensionné afin qu'il alloue et libère un morceau de longueur 0x6060 dans un bac non trié.
2. Sélectionnez le premier storeblock. Ensuite, nous envoyons une commande non reconnue pour appeler store_get () et allouons le storeblock à l'intérieur du bloc libéré.
3. Sélectionnez le deuxième bloc et relâchez le premier. Nous envoyons EHLO pour recevoir le deuxième bloc. Le premier bloc est libéré séquentiellement en raison de l'appel smtp_reset une fois EHLO terminé.
Une fois le tas préparé, nous pouvons l'utiliser pour écraser la taille de bloc d'origine. Nous modifions 0x2021 en 0x20f1, ce qui élargit légèrement le bloc.
4. Envoyez les données base64 et débordez de 1 octet sur le tas. Exécutez la commande AUTH pour envoyer des données base64.
5. Créez et envoyez une chaîne de taille appropriée. Depuis que nous avons étendu le bloc de données, le début du morceau suivant se trouve maintenant quelque part à l'intérieur. Nous devons maintenant le corriger afin de réussir le contrôle d'intégrité de Glibc. Nous envoyons ici une autre chaîne base64.
6. Libérez le bloc étendu. Pour contrôler le contenu du bloc étendu, nous devons d'abord libérer le bloc, car nous ne pouvons pas le modifier directement. Autrement dit, nous devons envoyer un nouveau message EHLO pour libérer l'ancien nom d'hôte. Cependant, le traitement de la commande EHLO appelle smtp_reset lors de l'exécution réussie. Cela peut entraîner une interruption du programme ou un arrêt anormal. Pour éviter cela, nous envoyons un nom d'hôte invalide comme un +.
7. Remplacez le pointeur suivant du bloc de stockage qui se chevauchent.
Une fois le bloc libéré, nous pouvons l'obtenir avec AUTH et écraser une partie du storeblock qui se chevauche. Ici, nous utilisons une technique appelée «enregistrement partiel». Cela nous permet de changer le pointeur sans rompre ASLR. Nous avons partiellement changé le pointeur suivant sur un bloc contenant des lignes ACL. Les lignes ACL sont spécifiées par un ensemble de globals, par exemple uschar * acl_smtp_helo;
Ces pointeurs sont initialisés au début du processus Exim et définis en fonction de la configuration. Par exemple, si la configuration contient la ligne acl_smtp_mail = acl_check_mail, le pointeur acl_smtp_mail pointe vers la ligne acl_check_mail.
Chaque fois que le serveur reçoit une commande MAIL FROM, Exim effectue une vérification ACL, qui développe d'abord acl_check_mail. Lors de l'expansion, si Exim rencontre la ligne $ {run {cmd}}, il essaiera d'exécuter la commande cmd, afin qu'un attaquant distant puisse obtenir le code à exécuter.
8. Réinitialisez storeblock et récupérez le storeblock contenant l'ACL. Le bloc ACL est maintenant sur la blockchain. Il sera libéré après que smtp_reset () soit terminé, puis nous pourrons le récupérer à nouveau en allouant quelques blocs.
9. Écrasez les lignes ACL et exécutez la vérification ACL. Enfin, nous réécrivons le bloc entier contenant les lignes ACL. Maintenant, nous envoyons des commandes comme EHLO, MAIL, RCPT pour exécuter la vérification d'ACL.
D'ailleurs, l'exploitation de la vulnérabilité a été facilitée par la désactivation de l'ASLR pour une raison inconnue de nous.
Quels problèmes le client a-t-il eu?
Le premier est le manque de gestion des mises à jour. Du fait que l'ancienne version d'Exim était utilisée, il était possible d'organiser un compromis du système. Pour éviter cela, nous vous recommandons d'organiser une vérification régulière et l'installation des mises à jour de sécurité sur les composants de l'infrastructure d'informations.
Nous vous recommandons de vérifier les nouvelles mises à jour de sécurité et critiques au moins une fois par mois. Pour vérifier les mises à jour, il est préférable d'utiliser les sites / listes de diffusion des équipementiers ou les informations des référentiels.
La banque manquait également d'un processus de gestion de la vulnérabilité, raison pour laquelle la vulnérabilité n'a pas été détectée à temps. L'utilisation de scanners de vulnérabilité spécialisés, par exemple, OpenVAS, Nessus, xSpider, etc., aiderait à corriger la situation.
Et pour couronner le tout. La banque n'avait pas de processus de gestion du changement. Toutes les modifications ont été apportées par les administrateurs dans l'environnement de production. Par conséquent, personne n'a contrôlé ou surveillé cela. Cela a conduit au fait que ASLR a été désactivé sur le serveur.
Production
Plusieurs violations apparemment non liées ont entraîné la compromission du site Web de la banque. Cela pourrait être utilisé par des attaquants pour, par exemple, changer les coordonnées bancaires en leurs propres.
L'histoire s'est bien terminée. Après le compromis, nous avons immédiatement informé le client de la situation. La banque a mis à jour d'urgence le serveur Exim vers la version actuelle, pour laquelle la vulnérabilité n'est plus pertinente. Cependant, si la vulnérabilité avait été identifiée non pas lors du test de pénétration, mais par de vrais attaquants, le résultat aurait pu être différent.