PHP Command Shell - Kleine Helferlein

PHP Command Shell

Kleine Helferlein

Michael Schneider
von Michael Schneider
am 24. August 2017
Lesezeit: 5 Minuten

Keypoints

  • Eine Command Injection injiziert ein Kommando in eine bestehende Befehlskette
  • Klassisches Beispiel ist das Anfügen eines Befehls an einen Ping-Parameter
  • PHP bietet verschiedene Mechanismen, um Kommandos auf dem Dateisystem auszuführen
  • Unsere PHP-Skripte finden entsprechende Angriffsvektoren auf Systemen

Die Schwachstelle Command Injection, beschrieben im OWASP Testing Guide unter OTG-INPVAL-013, ist ein seltener, aber gerne gesehener “Gast” – zumindest aus der Sicht des Angreifers. Hierbei ist der Angreifer in der Lage, Befehle der jeweiligen Programmiersprache über eine Eingabevariable einzuschleusen.

Beispiel mit Ping

Ein praktisches Beispiel dafür ist ein Netzwerk-Tool wie eine Ping-Funktion, die es ermöglicht, ICMP-Echo Pakete an eine beliebige IP-Adresse zu senden. Wenn nun der Angreifer anstelle einer IP-Adresse die Eingabe erweitert, beispielsweise durch 127.0.0.1; whoami, und keine Validierung stattfindet, ist eine Command Injection möglich.

In diesem Fall kann der Angreifer seine Befehle direkt über die vorgesehene Funktion einschleusen.

Ansatz via PHP

Nun gibt es aber auch die Situation, bei welcher der Angreifer die Möglichkeit hat, eigenen Programm-Code auf dem Zielsystem zu platzieren und dies ausnutzen will, um Befehle auf Betriebssystemebene auszuführen. Das kann beispielsweise in Form eines PHP-Skripts sein.

Die Skriptsprache PHP kennt mehrere Funktionen, um Befehle auf Betriebssystemebene auszuführen. Weit verbreitet sind dabei die Funktionen system() oder exec(), welche auch in anderen Programmiersprachen wie C anzutreffen sind. Die Funktionen nehmen ein Kommando entgegen, führen dies aus und geben das Resultat der Ausführung zurück.

Auf einem gut gehärteten Webserver werden solche Funktionen, die über ein solches Schadenpotential verfügen, deaktiviert. Dazu muss in der Konfigurationsdatei php.ini die Einstellung disable_functions entsprechend gepflegt werden. Ein Schwachpunkt des Blacklist-Ansatzes ist, dass nur die Funktionen deaktiviert werden, die dem Verwalter auch bekannt sind.

Wenn ein Angreifer nun eigene PHP-Skripte auf einem Server ausführen kann, versucht dieser herauszufinden, welche Funktion er nutzen kann, um Befehle auf Betriebssystemebene auszuführen. Dies kann am einfachsten über die Funktion phpinfo() bewerkstelligt werden. Ein Verteidiger wird jedoch wiederum diese Funktion in die Liste der deaktivierten Funktion aufnehmen, um eine Preisgabe der Konfigurationseinstellungen zu verhindern. Dementsprechend muss der Angreifer andere Wege finden, um funktionierende Funktion zu identifizieren.

Unser Test Skript

Wir haben dazu ein PHP-Skript shell_test.php (GitHub) geschrieben, das alle möglichen Funktionen zur Ausführung von Befehlen durchprobiert und eine entsprechende Rückmeldung gibt, ob die jeweilige Funktion auf dem Webserver genutzt werden kann. Das Skript ist für Linux-Systeme geschrieben, sollte aber auch auf Windows-Systemen grösstenteils funktionieren.

Das Skript selbst bietet jedoch keine Interaktivität; der auszuführbare Befehl muss mittels einer Variablen definiert werden. Daher haben wir dieses Skript weiter ausgebaut und ein einfaches Eingabeformular hinzugefügt: shell.php (GitHub). Das Formular ermöglicht es Befehle mit der Funktion, die auch vom Webserver unterstützt werden, ausführen zu lassen. Falls mehrere Funktionen verfügbar sind, kann die gewünschte Funktion in einer Dropdown-Liste ausgewählt werden. Bei der ersten Ausführung, respektive wenn keine Befehle angegeben werden, führt das Skript einige Basis-Abfragen durch wie das Auslesen der Linux-Kernelversion, des Benutzernamens, Verfügbarkeit von Netcat, Auflistung des aktuellen Verzeichnisses, Auflistung der laufenden Prozesse sowie der aktiven Netzwerkverbindungen.

Beim Testen des Skripts haben wir festgestellt, dass es auf Windows Systemen vorkommen kann, dass die Funktion system() keinen Rückgabewert ausgibt und so wichtige Informationen nicht angezeigt werden. Die Ursache dafür ist, dass es Befehle/Programme gibt, welche die Rückgabe von erweiterten Information in den Standard-Error-Stream (stderr) zurückgeben. Dies ist unter anderem bei einigen PowerShell Cmdlets der Fall. Durch das Hinzufügen von 2>&1 ans Ende des Kommandos wird der Stream stderr an den Standard-Output-Stream (stdout) weitergeleitet. Damit können auch erweitere Informationen angezeigt werden. Der Aufruf von system() sieht dann so aus: system("command 2>&1", $return).

Fazit

Die Skripte sind hier im Labs verlinkt und zusätzlich auf unserem GitHub Repository verfügbar. Wir freuen uns über jede Art von Feedback, ob die Skripts irgendwo zum Einsatz gekommen sind, für Änderungsvorschläge oder Feature Requests.

Über den Autor

Michael Schneider

Michael Schneider arbeitet seit dem Jahr 2000 in der IT. Im Jahr 2010 hat er sich auf die Informationssicherheit spezialisiert. Zu seinen Aufgaben gehören das Penetration Testing, Hardening und das Aufspüren von Schwachstellen in Betriebssystemen. Er ist bekannt für eine Vielzahl in PowerShell geschrieber Tools zum Finden, Ausnutzen und Beheben von Schwachstellen. (ORCID 0000-0003-0772-9761)

Links

Sie brauchen Unterstützung bei einem solchen Projekt?

Unsere Spezialisten kontaktieren Sie gern!

×
HardeningKitty

HardeningKitty

Michael Schneider

KleptoKitty

KleptoKitty

Michael Schneider

Linux Hardening

Linux Hardening

Michael Schneider

Sie wollen mehr?

Weitere Artikel im Archiv

Sie brauchen Unterstützung bei einem solchen Projekt?

Unsere Spezialisten kontaktieren Sie gern!

Sie wollen mehr?

Weitere Artikel im Archiv