Neulich stieß ich auf ein Programm, bei dem ich aus einer vorgefertigten Auswahl an Abfragen wählen und dann mit einem Server kommunizieren konnte, um die Antwort auf die ausgewählte Abfrage abzurufen. Ich wurde misstrauisch, als mir auffiel, dass das Programm nie nach einem Passwort für die Authentifizierung beim Server fragte. Es stellte sich heraus, dass das Passwort im Programm eingebettet war. Der Autor erklärte, dass dies in Ordnung sei, weil 1) es sich um eine Binärdatei handelte, die niemand lesen konnte, und 2) selbst wenn man sie lesen könnte, man die Passwortzeichenfolge nicht finden würde.
Keiner dieser Gründe ist stichhaltig, und ich möchte dies anhand dieses Beitrags verdeutlichen. Mein Beispielprogramm gibt lediglich das Wort „Passwort“ auf dem Terminal aus, doch der einzige Unterschied zu einem echten Produktionsprogramm besteht in der Anzahl der Zeichenfolgen, die ein böswilliger Benutzer durchsuchen müsste.
#include <stdio.h>
#include <string.h>
main ()
{
char password [9] = {"secret"};
printf ("This is the password: %sn", password);
}
|
| Abbildung 1 – Basisprogramm mit eingebettetem Passwort |
Bei der Ausführung wird Folgendes angezeigt
x1 Das ist das Passwort: secret Bereit 14:12:16 |
| Abbildung 2 – Ausführung des Basisprogramms |
Um die Zeichenfolgen im Programmmodul anzuzeigen, kann unser böswilliger Benutzer den Befehl `strings` aus dem Verzeichnis `>system>gnu_library>bin` verwenden. Die Option `-n5` beschränkt die Ausgabe auf Zeichenfolgen mit mindestens 5 Zeichen. Ich habe die Ausgabe gekürzt (. . . .), um die Darstellung zu verkürzen, aber Sie können sehen, dass das Passwort zu den allerersten angezeigten Zeichenfolgen gehört. Die Nähe des Passworts zu Schlüsselwörtern wie „login“ oder „password“ oder zu einer identifizierbaren Benutzer-ID wie „admin“, „root“ oder „sql“ erleichtert die Suche.
>system>gnu_library>bin>strings -n5 x1.pm
bind, Release 17.1.beta.be
phx_vos#
Noah_Davids.CAC
Vorabversion
Dies ist das Passwort: %s
secret
s$start_c_program
_preemption_cleanup
_exit
. . . . .
|
| Abbildung 3 – Verwendung des GNU-Befehls „strings“, um alle Zeichenfolgen mit mehr als 4 Zeichen im Programmmodul zu finden |
Falls der Befehl „strings“ nicht verfügbar ist, kann unser böswilliger Benutzer einfach das Programmmodul anzeigen. Ich vermute, dass wir das alle schon einmal versehentlich getan haben, und auch wenn es nicht besonders elegant ist, wird dadurch das Passwort angezeigt. Ich habe die Ausgabe erneut gekürzt, und auch hier ist das Passwort zu sehen.
d x1.pm
%phx_vos#m16_mas>SysAdmin>Noah_Davids>x1.pm 13.01.2011 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`00Dies ist das Passwort: %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
. . . .
|
| Abbildung 4 – Anzeige des Programmmoduls zum Auffinden des Passworts |
Es gibt mehrere Alternativen zur Einbettung des Passworts in das Programm.
Das Passwort kann in einer Datei gespeichert werden, die das Programm lesen kann. Nur diejenigen, die das Programm ausführen müssen, erhalten Lesezugriff auf die Datei, während alle anderen keinen Zugriff haben. Natürlich ist „das Programm ausführen müssen“ nicht unbedingt gleichbedeutend mit „das Passwort kennen müssen“. Zudem besteht immer die Gefahr, dass jemand versehentlich die Zugriffsrechte ändert.
Eine Alternative besteht darin, die Passwortzeichenfolge im Programm selbst zu speichern und lediglich den Zugriff auf das Programm zu beschränken. Auch diese Lösung hat den Nachteil, dass sich eine Zugriffsliste leicht ändern lässt. Befindet sich das Programm im selben Verzeichnis wie andere Programme, die von jedem ausgeführt werden können, steigt die Wahrscheinlichkeit, dass die Zugriffsliste geändert wird.
Schließlich kannst du das Passwort im Programmmodul speichern, die Zeichenfolge jedoch auf irgendeine Weise verschleiern. Das folgende Programm zeigt eine einfache Möglichkeit, dies zu bewerkstelligen.
#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);
}
|
| Abbildung 5 – Programm mit verschleierter Passwortzeichenfolge |
Wie du sehen kannst, werden lediglich die verschleierten Zeichen mit einem anderen Satz von Schlüsselzeichen XOR-verknüpft, um das Passwort zu erzeugen. Die Ausführung des Programms liefert dieselbe Ausgabe wie das erste Programm.
x2 Das ist das Passwort: secret Bereit 14:12:51 |
| Abbildung 6 – Ausführung eines verschleierten Programms |
Eine Suche nach Zeichenfolgen liefert jedoch keine Ergebnisse, die dem Passwort ähneln
>system>gnu_library>bin>strings -n5 x1.pm bind, Release 17.1.beta.be phx_vos# Noah_Davids.CAC Vorabversion Dies ist das Passwort: %s s$start_c_program _preemption_cleanup _exit . . . . |
| Abbildung 7 – Der Befehl „strings“ zeigt das Passwort nicht mehr an |
Zwar werden beim Anzeigen der Datei die verschleierten Passwortzeichen und die Schlüsselzeichen angezeigt, doch muss man genau wissen, wo man sie finden kann und wie sie kombiniert werden, um das Passwort zu bilden.
d x2.pm
%phx_vos#m16_mas>SysAdmin>Noah_Davids>x2.pm 13.01.11 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`00Dies ist das Passwort: %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
|
| Abbildung 8 – Bei der Anzeige des Programmmoduls wird kein erkennbares Passwort mehr angezeigt |
Dies ist jedoch noch keine perfekte Lösung, da das Programmmodul disassembliert werden kann, um herauszufinden, wie das Passwort generiert wird. Das Disassemblieren des Programms erfordert jedoch weitaus mehr Fachwissen als die bloße Anzeige des Programmmoduls.
Ich bin mir nicht ganz sicher, ob ich die verschleierte Passwortzeichenfolge in eine Datei schreiben und diese dann über eine Zugriffsliste schützen soll. Einerseits ist dies eine viel bessere Lösung als die Einbettung der verschleierten Passwortzeichenfolge in das Programm, falls das Passwort jemals geändert werden muss. Andererseits vermute ich, dass unser böswilliger Nutzer, selbst wenn die Datei weitere Konfigurationsoptionen enthält, durch das Speichern der Zeichenfolge in der Datei weniger potenzielle Passwortzeichenfolgen zur Untersuchung hat. Natürlich muss er sich dennoch Zugriff auf die Datei verschaffen und dann die Verschleierungstechnik und den Schlüssel herausfinden.
Noch eine letzte Anmerkung: Wie habe ich die verschleierten Passwortzeichen erzeugt? Das Schöne an der XOR-Operation ist, dass ((A XOR B) XOR B) gleich A ist. Deshalb habe ich einfach ein kurzes Programm geschrieben, das das ursprüngliche Passwort nimmt, die Zeichen mit meinem Schlüssel XOR-verknüpft und das Ergebnis ausgibt.
#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]);
}
}
|
| Abbildung 9 – Programm zur Erzeugung eines verschleierten Passworts |
