IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

MySQL Discussion :

MySQL/MariaDB : alerte à une faille de sécurité "tragiquement comique"


Sujet :

MySQL

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre extrêmement actif

    Homme Profil pro
    Software Developer
    Inscrit en
    Mars 2008
    Messages
    1 470
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Software Developer

    Informations forums :
    Inscription : Mars 2008
    Messages : 1 470
    Par défaut
    Citation Envoyé par gb_68 Voir le message
    J'avoue ne pas avoir tout de suite compris ce bug ayant une probabilité de 1/256.
    Voici quelques morceaux codes complémentaires :
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    /*
        Check that scrambled message corresponds to the password; the function
    [...]
      RETURN VALUE
        0  password is correct
        !0  password is invalid
    */
     
    my_bool
    check_scramble(const char *scramble_arg, const char *message,
                   const uint8 *hash_stage2)
    {
    Donc la fonction doit renvoyer 0 si le mot de passe est correcte et un nombre quelconque différent de zéro dans le cas contraire.
    C'est bien ce que fait memcmp
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    return memcmp(hash_stage2, hash_stage2_reassured, SHA1_HASH_SIZE);
    Le hic est que le type retourné par memcmp est un int alors que my_bool est défini comme suit (/include/my_global.h)
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    typedef char		my_bool; /* Small bool */
    Le cast int -> char revient à faire un modulo 256, soit transformer toutes les valeurs multiples de 256 en 0. Si l'on considère que memcmp va nous renvoyer de manière uniforme toutes les valeurs possibles alors l'on obtient cette roulette russe de 1/256 pour le mot de passe.
    Merci beaucoup pour toutes ces précisions

  2. #2
    Membre Expert
    Avatar de pmithrandir
    Homme Profil pro
    Responsable d'équipe développement
    Inscrit en
    Mai 2004
    Messages
    2 419
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Responsable d'équipe développement
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2004
    Messages : 2 419
    Par défaut
    Citation Envoyé par gb_68 Voir le message
    Le cast int -> char revient à faire un modulo 256, soit transformer toutes les valeurs multiples de 256 en 0. Si l'on considère que memcmp va nous renvoyer de manière uniforme toutes les valeurs possibles alors l'on obtient cette roulette russe de 1/256 pour le mot de passe.
    Bon, j'ai toujours pas compris...

    En gros, la valeur renvoie 0 quand faux, ou un nombre entre 1 et plusieurs millions selon l'erreur du mot de passe et le degré de différence.

    Mais si j'essaye de transformer "2000" en char, il ne devrait pas y avoir une erreur de casting relevée par le moteur ? Ca ne me semble pas du tout évident de trouver ce genre d'erreur et de détecter que 512 = 0...

    Par ailleur, si on essaye toujours le même mot de passe, ca veut dire que l'on devrait avoir les même valeur, donc la même comparaison, donc le même modulo... donc finalement pas tant de problèmes que cela non?

    Quelqu'un pour m'éclairer ?

    Merci,
    Pierre

  3. #3
    Modérateur
    Avatar de gangsoleil
    Homme Profil pro
    Manager / Cyber Sécurité
    Inscrit en
    Mai 2004
    Messages
    10 150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Manager / Cyber Sécurité

    Informations forums :
    Inscription : Mai 2004
    Messages : 10 150
    Par défaut
    Citation Envoyé par pmithrandir Voir le message
    Bon, j'ai toujours pas compris...

    En gros, la valeur renvoie 0 quand faux, ou un nombre entre 1 et plusieurs millions selon l'erreur du mot de passe et le degré de différence.
    valeur de retour 0 : le mot de passe est le bon
    valeur de retour != 0 : le mot de passe n'est pas le bon.

    Maintenant, regardons de plus pres ce different de 0.

    Citation Envoyé par pmithrandir Voir le message
    si on essaye toujours le même mot de passe, ca veut dire que l'on devrait avoir les même valeur, donc la même comparaison, donc le même modulo... donc finalement pas tant de problèmes que cela non?
    Non, pas si c'est bien fait, ce qui est le cas. Tu ne hash pas le mot de passe, mais un couple mot de passe + grain de sel, donc le hash est different a chaque fois.

    Bien, nous avons donc un hash sur 32 bits, mais une comparaison qui va tronquer ca sur un char, c'est a dire sur 8 bits. Il suffit donc que les 8 bits de comparaison soient les memes pour que l'acces soit donne.

    Exemple foireux juste pour comprendre :
    hash qui va bien :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    00000000 11111111 01010101 00110011
    hash qui ne devrait pas aller, mais qui va bien si on ne regarde que les 8 premiers ou les 8 derniers bits :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    00000000 01010101 11111111 00110011
    Dans ce cas, la comparaison tronquee retourne 0, alors que la comparaison sur les 32 bits ne retourne pas 0.
    "La route est longue, mais le chemin est libre" -- https://framasoft.org/
    Les règles du forum

  4. #4
    Membre éclairé Avatar de rt15
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2005
    Messages
    262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Octobre 2005
    Messages : 262
    Par défaut
    Citation Envoyé par pmithrandir Voir le message
    Quelqu'un pour m'éclairer ?
    Dans certaines (rares) implémentation de memcmp, la valeur de retour est "aléatoire" et ne "dépend pas" des valeurs en entrée. Tout en étant conforme à la norme bien sûr. Par exemple, comparer "a" et "b" renverra tantôt -1, -516, -2000... Que des nombres négatifs, mais de valeurs différentes d'un appel à l'autre. Apparemment c'est le cas de l'implémentation de la glibc sous Linux qui utilise SSE pour aider à obtenir une comparaison très rapide (Mais cette implémentation n'est pas souvent utilisée par gcc qui utilise une built-in). L'aléatoire est certainement introduit par utilisation d'une valeur non initialisée par la fonction elle même.

    Ensuite, pour ce qui est de la perte des octets de poids fort, il n'y a pas de "moteur", le code est en C. Donc au mieux on aurait une erreur ou un warning à la compilation, pas à l'exécution. Tout le souci est dans le cast implicite au niveau du return. Je ne sais pas pourquoi aucun warning n'est donné... Ce serait peut être pas mal que le compilo réclame un cast explicite à ce niveau. Avec un cast explicite, le problème aurait sauté au yeux des développeurs.

    gangsoleil -> Relit le code de alex_vino. Je ne pense pas que tu sois sur la bonne piste. Il n'y a pas troncation des valeurs comparées. Et il y a de bonne chance pour que le hash soit toujours le même, car le sel doit rester le même. Ce qu'on compare, c'est Hash(tentative + sel) avec la valeur stockée dans la table "user" de MySQL, qui elle même à été généré avec Hash(pwd + même sel).

    Code de simulation :
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
     
    typedef char my_bool;
     
    /**
     * Implémentation de memcmp correcte, mais renvoyant des valeurs aléatoires.
     */
    int my_memcmp(const void* ptr1, const void* ptr2, size_t num)
    {
      unsigned char* lpArea1;
      unsigned char* lpArea2;
      int nResult;
      int i;
     
      lpArea1 = (unsigned char*)ptr1;
      lpArea2 = (unsigned char*)ptr2;
     
      nResult = 0;
      for (i = 0; i < num; i++)
        if (lpArea1[i] != lpArea2[i])
        {
          nResult = rand() + 1;
          nResult = nResult * ((lpArea1[i] > lpArea2[i]) ? 1 : -1);
          break;
        }
      return nResult;
    }
     
    /**
     * Fonction vérifiant le mot de passe dans MySQL.
     */
    my_bool checkPwd(char* ref, char* pwd)
    {
      int nMemCmpResult;
     
      nMemCmpResult = my_memcmp(ref, pwd, 4);
      printf("%d -> ", nMemCmpResult);
     
      /* Le souci est dans la ligne suivante où on ne récupère que l'octet de poid faible de nMemCmpResult */
      return nMemCmpResult;
    }
     
    int main()
    {
      my_bool nMemCmpResult;
     
      srand(time(NULL));
     
      /* On essaie toujours le même mot de passe jusqu'à ce qu'il soit correcte */
      while (1)
      {
        nMemCmpResult = checkPwd("bbbb", "aaaa");
        printf("%d\n", nMemCmpResult);
        if (! nMemCmpResult)
        {
          printf("Pwd OK !\n");
          break;
        }
      }
     
      return 0;
    }

    Sortie :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32208 -> -48
    17727 -> 63
    5728 -> 96
    19104 -> -96
    7460 -> 36
    25916 -> 60
    26045 -> -67
    21198 -> -50
    5390 -> 14
    29278 -> 94
    27887 -> -17
    2476 -> -84
    600 -> 88
    3870 -> 30
    6687 -> 31
    25618 -> 18
    2180 -> -124
    2750 -> -66
    4626 -> 18
    31743 -> -1
    ...
    9425 -> -47
    30113 -> -95
    4156 -> 60
    2683 -> 123
    10749 -> -3
    7017 -> 105
    10044 -> 60
    13231 -> -81
    19968 -> 0
    Pwd OK !
    [edit]
    A partir de gcc 4.3, -Wconversion permet de détecter ce problème.

  5. #5
    Membre expérimenté
    Avatar de Lyche
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Janvier 2007
    Messages
    2 523
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : Janvier 2007
    Messages : 2 523
    Billets dans le blog
    4
    Par défaut
    Cela me conforte sur ce que je pense de MySQL et cie \o/ Merci
    Rejoignez la communauté du chat et partagez vos connaissances ou vos questions avec nous

    Mon Tutoriel pour apprendre les Agregations
    Consultez mon Blog SQL destiné aux débutants

    Pensez à FAQ SQL Server Ainsi qu'aux Cours et Tuto SQL Server

  6. #6
    Membre très actif
    Profil pro
    Inscrit en
    Juillet 2010
    Messages
    657
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juillet 2010
    Messages : 657
    Par défaut
    En même temps cela prouve l'utilité de l'open source.
    Combien de bugs inconnus et failles existent dans les SGBD dont le code est fermé ? de plus le fix est simple suffit de corriger et de recompiler.

    Bref on peut tout à faire faire du proprio , mais l’accès aux sources d'un produit permet finalement de pointer facilement des bugs ou des failles de sécurités.

    Comment savoir si tel ou tel système proprio n'a pas de backdoor ?

  7. #7
    Membre extrêmement actif

    Homme Profil pro
    Software Developer
    Inscrit en
    Mars 2008
    Messages
    1 470
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Software Developer

    Informations forums :
    Inscription : Mars 2008
    Messages : 1 470
    Par défaut
    Citation Envoyé par camus3 Voir le message
    En même temps cela prouve l'utilité de l'open source.
    Combien de bugs inconnus et failles existent dans les SGBD dont le code est fermé ? de plus le fix est simple suffit de corriger et de recompiler.

    Bref on peut tout à faire faire du proprio , mais l’accès aux sources d'un produit permet finalement de pointer facilement des bugs ou des failles de sécurités.

    Comment savoir si tel ou tel système proprio n'a pas de backdoor ?
    Bah l'avantage de ne pas avoir acces au code sources empeche les hackers de trouver des failles en regardant juste le code source.
    Ca leur demande beaucoup plus de travail aux hackers et d'avancer a tatonnement

  8. #8
    Membre chevronné
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Mars 2006
    Messages
    400
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo

    Informations forums :
    Inscription : Mars 2006
    Messages : 400
    Par défaut
    Citation Envoyé par Idelways Voir le message
    La faille se situe au niveau d'une librairie C dont dépendent ces SGBD. Il s'agit d'une erreur de casting qui a une chance sur 256 fois de se produire lors de la vérification du résultat de comparaison des mots de passe fournis et attendus (avec la fonction memcmp).
    Corrigez moi si je me trompe, mais il me semble que la faille en question ne se situe pas au niveau d'une fonction d'une bibliothèque tierce, mais est liée à la manière d'interpréter le résultat de cette fonction.

    En l'occurence, la fonction incriminée doit renvoyer 0 ou !0 sur 8 bits, mais se contente de renvoyer la valeur de retour de memcmp, 0 ou !0 sur 32 bits.
    Seuls les 8 bits de poids faible seront donc exploités par un code appelant cette fonction.

    Il s'agit donc d'un mauvais usage de la valeur de retour d'une fonction (memcmp).

Discussions similaires

  1. Réponses: 34
    Dernier message: 19/06/2012, 09h05
  2. Réponses: 15
    Dernier message: 17/07/2009, 23h18
  3. Réponses: 0
    Dernier message: 15/07/2009, 12h16

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo