Cela me conforte sur ce que je pense de MySQL et cie \o/ Merci
Cela me conforte sur ce que je pense de MySQL et cie \o/ Merci
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 ?
Celà n'empêche pas non plus les logiciels propriétaires d'être également touchés par des failles simplement exploitables, on a vu par exemple la CVE-2010-4669, où le fait de lancer un grand nombre de RA IPv6 sur un réseau avec un sipmple script fait planter les machines Windows du réseau... Et on pourrait noter que contrairement à la faille de MySQL, celle-ci ne semble toujours pas corrigée !
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).
Loupé!
Au contraire, l'obfuscation ne résout rien, elle donne simplement un sentiment de sécurité. Du coup quand le code est ouvert, plus de personnes lisent le code, (y compris des hackers qui publient leurs découvertes), et plus de personnes corrigent les failles, donc à priori le code est mieux sécurisé. Et puis dans le logiciel libre, quand on trouve une faille, on le dit. Du coup y'a plein de trolls comme toi qui disent que les logiciels libre sont moins sécurisés puisqu'ils communiquent sur leurs failles.
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
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.
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 :
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 11111111 01010101 00110011
Dans ce cas, la comparaison tronquee retourne 0, alors que la comparaison sur les 32 bits ne retourne pas 0.
Code : Sélectionner tout - Visualiser dans une fenêtre à part 00000000 01010101 11111111 00110011
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 :
[edit]
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 !
A partir de gcc 4.3, -Wconversion permet de détecter ce problème.
Merci pour ces éclaircissements.
Effectivement, je pensais qu'une méthode avec la même entrée(le sel est fixe sur un login donné) donnait toujours le même résultat. Je comprends mieux ma méprise.
Le bon point, c'est que ca serait detecté par java sans problème, et je pense que meêm en PHP je ne pourrais pas avoir le même soucis.
Pierre
Pour ceux qui pensent être protégés par le fait que le serveur est ouvert que sur localhost faites tout de même attention.
Si vous utilisez un système permettant de ce logger par l'intermédiaire d'un script (exemple typique phpmyadmin) il suffit théoriquement au pirate d'utiliser ces scripts.
En pratique c'est un peu plus compliqué car avec phpmyadmin sauf astuce que je ne connais pas il faut faire 2 connexions (une pour entrer dans le logiciel avec le login+pass , une autre pour la requête) donc ça fait 256² requêtes ce qui est plus délicat mais suffisant pour être cassé rapidement.
Effectivement, mon exemple naif est trop naif, j'ai tronque les valeurs comparees, et non pas la valeur de retour.
Je corrige donc naivement :
comparaison qui retourne faux : 00000000 11111111 01010101 00110011
Mais si on ne regarde que le 1er octet, ce qui se passe dans notre cas, la comparaison est vue comme juste.
Merci de m'avoir alerte sur ma connerie
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager