Passer au contenu principal

L'autre jour, je suis tombé sur un programme qui me permettait de sélectionner parmi un ensemble prédéfini de requêtes, puis de communiquer avec un serveur pour récupérer la réponse à la requête sélectionnée.  Je me suis posé des questions lorsque j'ai réalisé que le programme ne demandait jamais de mot de passe pour s'authentifier auprès du serveur. Il s'avère que le mot de passe était intégré au programme. L'auteur a expliqué que cela ne posait pas de problème, car 1) il s'agissait d'un fichier binaire que personne ne pouvait lire et 2) même si quelqu'un pouvait le lire, il ne serait pas en mesure de trouver la chaîne de caractères correspondant au mot de passe.

Aucune de ces raisons n'est valable et j'aimerais utiliser cet article pour le démontrer. Mon programme exemple écrit simplement le « mot de passe » sur le terminal, mais la seule différence entre celui-ci et un programme de production réel réside dans le nombre de chaînes qu'un utilisateur malveillant devrait parcourir.

#include <stdio.h>
#include <string.h>

main ()
{
char password [9] = {"secret"};

printf ("This is the password: %sn", password);

}
Figure 1 – Programme de base avec mot de passe intégré

Une fois exécuté, il affiche

x1
Voici le mot de passe : secret
prêt  14:12:16
Figure 2 – Exécution du programme de base

Pour afficher les chaînes dans le module du programme, notre utilisateur malveillant peut utiliser la commande strings du répertoire >system>gnu_library>bin. L'option -n5 limite la sortie aux chaînes de 5 caractères ou plus. J'ai tronqué la sortie (. . . .) pour raccourcir l'affichage, mais vous pouvez voir que le mot de passe est l'une des toutes premières chaînes affichées. Le fait que le mot de passe se trouve à proximité de mots clés tels que « login » ou « password » ou d'un identifiant utilisateur identifiable tel que « admin », « root » ou « sql » facilite la recherche.

>system>gnu_library>bin>strings -n5 x1.pm
bind, version 17.1.beta.be
phx_vos#
Noah_Davids.CAC
Préversion
Voici le mot de passe : %s
secret
s$start_c_program
_preemption_cleanup
_exit.
 . . . .
Figure 3 – Utilisation de la commande GNU strings pour trouver toutes les chaînes de plus de 4 caractères dans le module de programme

Si la commande strings n'est pas disponible, notre utilisateur malveillant peut simplement afficher le module du programme. Je pense que nous avons tous déjà fait cela par accident et, même si ce n'est pas très élégant, cela permet d'afficher le mot de passe. J'ai de nouveau tronqué la sortie et, là encore, vous pouvez voir le mot de passe.

d x1.pm

%phx_vos#m16_mas>SysAdmin>Noah_Davids>x1.pm  11-01-13 14:13:59 mst

`00`01`00`1Abind, version 17.1.beta.be`00`00`00`00`00`00`00`04ctp
`00`00`00`00`0
+`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`0
0phx_vos
+#`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`
00`00Noa.
 . . .
+`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`C
D'`8B`C0
+`00`00`00`00Voici le mot de passe : %s
`00`00`00`00`00`00`00secret`00`00`00`00`00`00`00`04`B0`00`00`00`00`01`00
`00`00,`
+`00`00`04`00`00`00`03@`00`FF`F8`FF`FE`00`04main`00`00`83`EC`2C`C7D$$`00.
 . . .
Figure 4 – Affichage du module du programme permettant de trouver le mot de passe

Il existe plusieurs alternatives à l'intégration du mot de passe dans le programme.

Le mot de passe peut être placé dans un fichier et le programme peut lire ce fichier. Seules les personnes ayant un « besoin d'exécution » ont un accès en lecture au fichier, tous les autres n'ont aucun accès. Bien sûr, le « besoin d'exécution » n'est pas nécessairement synonyme de « besoin de connaître le mot de passe ». De plus, il existe toujours un risque que quelqu'un modifie par erreur l'accès.

Une autre solution consiste à conserver la chaîne de caractères du mot de passe dans le programme et à simplement limiter l'accès au programme. Cette solution souffre également du problème lié à la facilité avec laquelle il est possible de modifier une liste d'accès. Si le programme est conservé dans le même répertoire que d'autres programmes pouvant être exécutés par n'importe qui, la probabilité d'une modification de la liste d'accès augmente.

Enfin, vous pouvez conserver le mot de passe dans le module du programme, mais en obscurcissant la chaîne d'une manière ou d'une autre. Le programme suivant montre une manière simple de procéder.

#include <stdio.h>
#include <string.h> 

main ()
{
char obfuscate [9] = {0x0c, 0x81, 0xe2, 0x94, 0xe6, 0x9c};
char key [9] = {127, 228, 129, 230, 131, 232, 133, 234, 135};
char password [9];
int i;

for (i = 0; i < strlen (obfuscate); i++)
    password [i] = obfuscate [i] ^ key [i];
password [i] = 0x0;
printf ("This is the password: %sn", password);
}
Figure 5 – Programme avec chaîne de mot de passe obscurcie

Comme vous pouvez le voir, tout ce qu'il fait, c'est prendre les caractères obscurcis et les combiner avec un autre ensemble de caractères clés pour créer le mot de passe. L'exécution du programme produit le même résultat que le premier programme.

x2
Voici le mot de passe : secret
prêt  14:12:51
Figure 6 – Exécution d'un programme obscurci

Mais une recherche de chaînes de caractères ne montre rien qui ressemble au mot de passe.

>system>gnu_library>bin>strings -n5 x1.pm
bind, version 17.1.beta.be
phx_vos#
Noah_Davids.CAC
Préversion
Voici le mot de passe : %s
s$start_c_program
_preemption_cleanup
_exit.
 . . .
Figure 7 – La commande strings n'affiche plus le mot de passe

Et bien que l'affichage du fichier révèle les caractères obscurcis du mot de passe et les caractères clés, vous devez savoir exactement où les chercher et comment ils sont combinés pour créer le mot de passe.

d x2.pm  
  
%phx_vos#m16_mas>SysAdmin>Noah_Davids>x2.pm  11-01-13 14:15:27 mst

. . . .  
+`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`CD'`8B`
C0`00`0
+0`00`00Voici le mot de passe : %s

`00`00`00`00`00`00`00`0C`81`E2`94`E6`9C`00`00`00`00`00`00`00`00`00`00`7F
`E4`81`
+E6`83`E8`85`EA`87`00`00`00`00`04`B0`00`00`00`00`01`00`00`00`00`00`00`0
4`01`B0
+`00`03@`00`FF`F0`00`08`FF`FE`00`04main`00`00`83`EC`89$X`89t$T`89|$P`C
7D$L`00
Figure 8 – L'affichage du module du programme ne montre plus le mot de passe reconnaissable.

Ce n'est toujours pas une solution parfaite, car le module du programme peut être désassemblé pour comprendre comment le mot de passe est généré. Cependant, le désassemblage du programme nécessite beaucoup plus de sophistication que le simple affichage du module du programme.

Je suis partagé quant à l'idée de placer la chaîne de caractères du mot de passe obscurci dans un fichier, puis de protéger ce fichier à l'aide d'une liste d'accès. D'un côté, si le mot de passe doit être modifié, cette solution est bien meilleure que d'intégrer la chaîne de caractères du mot de passe obscurci dans le programme. D'un autre côté, je soupçonne que même s'il existe d'autres options de configuration dans le fichier, le fait de placer la chaîne dans le fichier donnera à notre utilisateur malveillant moins de chaînes de caractères potentielles à examiner.  Bien sûr, il devra toujours accéder au fichier, puis découvrir la technique de cryptage et la clé.

Une dernière chose : comment ai-je généré les caractères du mot de passe obscurci ? L'avantage de l'opération XOR est que ((A XOR B) XOR B) est égal à A. J'ai donc simplement écrit un petit programme pour prendre le mot de passe d'origine, effectuer une opération XOR sur les caractères avec ma clé et afficher le résultat.

#include <stdio.h>
#include <string.h>

main ()
{
char password [9];
char key [9] = {127, 228, 129, 230, 131, 232, 133, 234, 135};
char newPW [9];
int i;

strcpy (password, "secret");
for (i = 0; i < strlen (password); i++)
    {
    newPW [i] = password [i] ^ key [i];
    printf ("%xn", newPW [i]);
    }
}
Figure 9 – Programme permettant de générer un mot de passe obscurci