L'autre jour, je suis tombé sur un programme qui me permettait de choisir parmi un ensemble de requêtes préétablies et de communiquer avec un serveur pour récupérer la réponse à la requête sélectionnée. J'ai commencé à me poser des questions lorsque j'ai réalisé que le programme ne demandait jamais de mot de passe pour l'authentification avec le serveur. Il s'est avéré que le mot de passe était intégré au programme. L'auteur a expliqué qu'il était correct parce que 1) c'était un fichier binaire, donc personne ne pouvait le lire et 2) s'ils pouvaient le lire, ils ne pourraient pas trouver la chaîne du mot de passe.
Aucune de ces raisons n'est valable et je voudrais utiliser ce poste pour le démontrer. Mon programme d'exemple se contente d'écrire le "mot de passe" sur le terminal, mais la seule différence entre celui-ci et un programme de production réel est le nombre de chaînes de caractères qu'un utilisateur malveillant devrait rechercher.
#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é |
Lorsqu'il est 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 de caractères dans le module de programme, notre utilisateur malveillant peut utiliser la commande strings du répertoire >system>gnu_library>bin. La commande -n5 limite l'affichage 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 d'avoir le mot de passe à proximité de mots clés comme "login" ou "password" ou d'un identifiant identifiable comme "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
Communiqué de presse
Voici le mot de passe : %s
secret
s$start_c_program
Nettoyage de la prévention
Sortie
. . . . .
|
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 soupçonne que nous avons tous fait cela par accident et, bien que ce ne soit pas joli, il affichera le mot de passe. J'ai de nouveau tronqué la sortie et vous pouvez de nouveau voir le mot de passe.
j x1.pm
%phx_vos#m16_mas>SysAdmin>Noah_Davids>x1.pm 11-01-13 14:13:59 mst
`00`01`00`1Abind, Release 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`00C'est 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 de programme pour 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 le fichier. Seules les personnes ayant un "besoin de fonctionner" ont un accès en lecture au fichier et toutes les autres personnes n'ont aucun accès. Bien sûr, "besoin de fonctionner" n'est pas forcément synonyme de "besoin de connaître le mot de passe". En outre, il y a toujours le risque que quelqu'un modifie l'accès par erreur.
Une alternative consiste à conserver la chaîne de mots de passe dans le programme et à limiter simplement l'accès au programme. Cette solution souffre également du problème du "il est facile 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'un changement de liste d'accès augmente.
Enfin, vous pouvez conserver le mot de passe dans le module de programme mais en obscurcissant la chaîne d'une manière ou d'une autre. Le programme suivant montre une façon simple de le faire.
#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 mots de passe obscurcie |
Comme vous pouvez le voir, tout ce qu'il fait est de prendre les caractères obscurcis et de les XORer avec un autre ensemble de caractères clés pour créer le mot de passe. L'exécution du programme produit la même sortie 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 révèle 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 Communiqué de presse Voici le mot de passe : %s s$start_c_program Nettoyage de la prévention Sortie . . . . |
Figure 7 - La commande strings ne montre plus le mot de passe |
Et tout en affichant le fichier, vous verrez les caractères obscurcis du mot de passe et les caractères clés que vous devez savoir exactement où chercher pour les trouver et aussi comment ils sont combinés pour créer le mot de passe.
j 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`00C'est 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 de programme n'indique plus de mot de passe reconnaissable |
Ce n'est pas encore une solution parfaite puisque le module du programme peut être démonté pour comprendre comment le mot de passe est généré. Le désassemblage du programme nécessite encore beaucoup plus de sophistication que le simple affichage du module de programme.
Je suis d'accord pour mettre la chaîne de mots de passe obscurcie dans un fichier et protéger ensuite le fichier via une liste d'accès. D'une part, si le mot de passe doit être modifié un jour, c'est une bien meilleure solution que d'intégrer la chaîne de mots de passe obscurcis dans le programme. D'autre part, je pense que même s'il y a d'autres options de configuration dans le fichier, le fait d'inclure la chaîne dans le fichier donnera à notre utilisateur malveillant moins de chaînes de mots de passe potentielles à examiner. Bien sûr, il devra toujours accéder au fichier et devra ensuite trouver la technique et la clé d'obscurcissement.
Un dernier point, comment ai-je généré les caractères obscurcis du mot de passe ? Ce qui est bien avec l'opération XOR, c'est que ((A XOR B) XOR B) est égal à A. J'ai donc écrit un petit programme pour prendre le mot de passe original XOR les caractères avec ma clé et imprimer 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 pour générer un mot de passe obscurci |