Chiffrement des données et défaillances cryptographiques : Top 10 OWASP #2

Dans un précédent article, nous avions passé en revue la vulnérabilité la plus critique des applications web selon le Top 10 OWASP : le défaut de contrôle d’accès. Aujourd’hui, nous nous attaquons aux vulnérabilités et exploitations courantes liées au manque ou à l’absence de chiffrement dans les applications.

Le chiffrement des données est central pour garantir la sécurité des applications. Dans cet article, nous explorerons les vulnérabilités liées au manque ou à l’absence de chiffrement à travers le prisme de l’OWASP Top 10. En partant de scénarios d’attaques réalisés lors de pentests, nous détaillerons les exploitations courantes ainsi que les bonnes pratiques, correctifs et mesures à implémenter pour bien chiffrer les données afin de prévenir les risques de compromission.   

Plan détaillé de l’article :

Qu’est-ce que le chiffrement de données ?

Le chiffrement est un procédé qui consiste à convertir tous types de données en un code chiffré, indéchiffrable sans une clé spécifique (clé de chiffrement). Élément central de toute stratégie cybersécurité, il permet non seulement d’assurer la confidentialité et l’intégrité des données échangées et stockées mais également de vérifier l’authenticité d’une authentification ou de contrôler l’accès à une ressource ou un service par un utilisateur ou un système.

Quels sont les différents types de chiffrement ?

Les mécanismes de chiffrement sont généralement paramétrés par des clés. La sécurité de ces mécanismes repose presqu’essentiellement sur la confidentialité et/ou l’intégrité de ces clés. En pratique, le chiffrement peut être symétrique ou asymétrique :

Chiffrement symétrique

Le chiffrement symétrique est une méthode de chiffrement dans laquelle la même clé est utilisée pour le chiffrement et le déchiffrement. Cette clé est appelée clé secrète et doit rester confidentielle pour des questions de sécurité.

En pratique, le chiffrement symétrique permet de transformer un message clair en un message chiffré, à l’aide de cette clé. De la même manière, seule cette clé permettra de déchiffrer la communication.

Chiffrement asymétrique

Le chiffrement asymétrique est une méthode de chiffrement utilisant deux clés différentes : une clé publique, qui peut être diffusée publiquement, et une clé privée, qui doit rester confidentielle.

Par exemple, dans un mécanisme de signature électronique, une entité possède une clé privée de signature, et la clé de vérification peut être publiée.

L’opération publique de chiffrement transforme à l’aide de la clé publique un message clair en un message chiffré. Dans le même temps, le déchiffrement permettra de retranscrire en clair la communication à partir du message chiffré et de la clé privée.

Quelles sont les exploitations courantes de manque de chiffrement ?

Chiffrement insuffisant des mots de passe dans une base de données

La compromission d’une base de données est évidemment catastrophique en soi. Cependant, le chiffrement insuffisant, voire absent, des mots de passe stockés dans celle-ci peut faire la différence entre une « simple » fuite de données et la compromission totale de la plateforme.

Nous avons rencontré à plusieurs reprises ce cas de figure : une faille nous permet de récupérer, d’une manière ou d’une autre, des mots de passe insuffisamment hashés ou en clair, ce qui nous permet ensuite de nous connecter, généralement avec des comptes administrateurs, sur la plateforme, la compromettant fortement.

Voyons plus en détail un cas particulier :

Exploitation injection SQL et récupération d’une base de données de mots de passe

Le scénario est le suivant : nous réalisons un test d’intrusion en boîte noire d’une application web.

Une injection SQL sur le formulaire de connexion nous a permis de récupérer la base de données. La plateforme est déjà donc fortement compromise. Cependant, l’injection SQL nous permet uniquement de lire des données alors que nous aimerions en insérer.

De plus, notre objectif ultime est d’obtenir un accès au panneau d’administration afin de compromettre encore plus notre cible.

Découverte de mots de passe hashés en MD5

Les données de la table utilisateur que nous avons récupérée grâce à l’injection SQL sont les suivantes (pour cet exemple, les données ont évidemment été remplacées par des mock-ups) :

Les mots de passe sont hashés, mais leur algorithme de hachage est facilement reconnaissable : du MD5.

Le MD5 est un algorithme inventé en 1991 qui a depuis (d’abord partiellement en 1996, puis complètement en 2004) été compromis. Aujourd’hui, il est considéré comme inadapté à la sécurité et ne doit plus être utilisé pour le stockage de mots de passe.

Son obsolescence nous permet de casser facilement et rapidement la plupart des mots de passe hashés en MD5.

Brute force des mots de passe

Il existe plusieurs moyens de cracker un mot de passe en MD5. Ici, nous avons opté pour une simple attaque par dictionnaire. En revanche, cette méthode ne permet pas de collecter l’intégralité des mots de passe des utilisateurs. Cependant, cela n’est pas nécessaire car il nous suffit d’obtenir quelques mots de passe, à plus forte raison s’il s’agit d’un compte administrateur.

L’outil le plus connu pour cracker des mots de passe est John the ripper. Dans notre cas, nous allons l’utiliser en mode wordlist avec un dictionnaire de mots de passe : rockyou.txt.

Nous mettons tout d’abord tous les hashs dans un fichier texte hashes.txt.

Puis nous lançons John :

L’opération ne dure que quelques secondes et trouve plusieurs mots de passe. Et quand on observe le compteur dans la dernière ligne de la capture ci-dessus « 1.084g/s », cela signifie que le logiciel teste plus d’un milliard de mots de passe possibles par seconde.

C’est l’une des raisons principales pour laquelle le MD5 est obsolète : des failles dans l’algorithme cryptographique permettent de faire des « raccourcis » mathématiques, ce qui diminue considérablement l’effort nécessaire pour calculer un hash et permet de faire autant de tentatives par seconde.

Suite à l’obtention des mots de passe, nous constatons que l’un d’entre eux correspond à un compte administrateur, ce qui nous a donc permis de compromettre une grande partie de l’application.

Utiliser une fonction de hachage robuste pour sécuriser le stockage des mots de passe

Les mots de passe doivent être hashés avec des algorithmes cryptographiques solides tels que Argon2, scrypt, bcrypt ou PBKDF2.

Et pour rajouter une couche de sécurité supplémentaire, les hash peuvent êtres salés, avec une chaine de caractères aléatoire unique pour chaque mot de passe (stockée dans la même table de la base de données que le mot de passe) et poivrés, via une chaine de caractères aléatoire partagée par tous les mots de passe (non stockée sur la base de données mais généralement plutôt sur le serveur applicatif).

Avec le sel et le poivre, un attaquant doit compromettre la base de données ET le serveur applicatif pour avoir seulement une chance d’attaquer les mots de passe. Et même dans ce cas, cela necessitera des ressources et un temps considérables.

De plus, une politique de mots de passe robustes doit être mise en place pour réduire les possibilités d’attaques par dictionnaire.

Enfin, il est à noter que, d’un point de vue juridique, le stockage des mots de passe en clair ou avec des algorithmes clairement identifiés comme obsolètes sont considérés comme une brèche de l’obligation de sécurité des organisations envers leurs utilisateurs vis-à-vis du RGPD notamment et peut conduire à des sanctions judiciaires.

Pour plus d’informations sur le stockage sécurisé des mots de passe, vous pouvez consulter les articles ci-dessous :

Comment stocker les mots de passe de manière sécurisée dans une base de données ?

Comment modifier les mots de passe pour sécuriser leur stockage avec Argon2 ?

Faiblesse des clés HMAC et modification d’une signature de jeton JWT

Un JWT est un jeton, souvent de session, qui a la particularité de pouvoir contenir des données (sous format JSON) permettant d’identifier un utilisateur et de renseigner des métadonnées le concernant : nom, email, rôle, droits d’accès, etc.  

L’intégrité de ce jeton est garantie par un système de signature algorithmique qui permet de s’assurer que le jeton n’a été ni modifié ni forgé.

Pentest en boite grise d’une application web

Cette fois-ci, nous testons une application web très classique, avec un système de droits par strate :

  • Les « users » ont les droits les plus basiques.
  • Les « managers » ont le contrôle d’un espace entreprise et de tous les utilisateurs rattachés à celui-ci
  • Le rôle administrateur est réservé aux employés de la société qui gère l’application web et est utilisé pour mettre en place et gérer les différents espaces.

Des comptes « users » et « managers » nous ont été fournis pour les tests.

Structure du jeton JWT

Le système de session fonctionne grâce à un jeton JWT, généré par le serveur lors de l’authentification et transmis ensuite au client.

Ce jeton ressemble à cela :

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjY0MSIsIm5hbWUiOiJ2YWFkYXRhIHRlc3QgdXNlciAxIiwicm9sZSI6Mn0.yo5wq8EOs96H5IHo3RGGMdaQjknLsRqNfwvneICyF14

Une fois décodé du base 64, on obtient ceci :

{"alg":"HS256","typ":"JWT"}
{"id":"641","name":"vaadata test user 1","role":2} 
+ signature

On voit que le JWT est signé avec du HS256 et qu’il contient l’id et le rôle de l’utilisateur en question. Il est fort probable que si l’on arrive à le modifier, nous puissions voler d’autres comptes en changeant l’id ou élever nos privilèges en modifiant le rôle.

Brute force du secret de la signature

Avant toute chose, testons l’attaque la plus simple : changer l’algorithme de signature à « None » et voir si le serveur accepte tout de même le jeton. Si c’est le cas, cela veut dire que la signature n’est pas vérifiée du tout et que nous pouvons forger n’importe quel JWT. Plusieurs moyens peuvent être utilisés pour générer un jeton JWT. Ici, nous utiliserons le site cyberchef et sa fonction « JWT sign ».

Nous utilisons le jeton ainsi généré à la place du notre et… le serveur renvoie une erreur 401 « unauthorized ».

La signature est donc bien vérifiée, mais est-elle solide ?

Testons une autre technique d’attaque : cracker le secret (le mot de passe) utilisé pour signer les JWT.

Nous savons que la signature est créée avec l’algorithme HASH-MAC256 (HS256). Tentons donc de la cracker avec, une fois de plus, John the ripper.

Nous mettons le JWT dans un fichier (jwt.txt) et nous lançons la tentative de crack, d’abord avec un dictionnaire puis, si cela ne fonctionne pas, nous tenterons une attaque par pure brute force.

Cela a été rapide. La clé semble être « secret », sans doute une clé par défaut qui n’a pas été changée.

Pour vérifier que nous avons la bonne clé, il nous suffit de générer un jeton JWT avec celle-ci.

Après vérification, le jeton est bien accepté par le serveur.

Cela nous donne effectivement un contrôle total du système de session. Ainsi, nous pouvons forger des JWT pour nous connecter avec n’importe quel utilisateur, voire en tant qu’administrateur, nous donnant ainsi un contrôle quasi total de l’application.

Correction de la vulnérabilité

Pour s’assurer de la sécurité du jeton JWT, deux paramètres sont à prendre en compte :

  • L’algorithme. Assurez-vous de non seulement utiliser un algorithme adapté à votre usage, mais également que celui-ci est bien vérifié avec le même algorithme ! Nous trouvons régulièrement des serveurs qui se fient entièrement aux métadonnées du jeton pour définir son type de signature, ce qui peut être abusé en changeant l’algorithme à « none » et ainsi contourner complètement le système de signature.
  • Le secret. Assurez-vous de choisir un mot de passe fort comme secret. Celui-ci doit être le plus long possible et généré aléatoirement.

Auteur : Renaud CAYOL – Pentester @Vaadata