
CalderaForms 1.5.9.1 XSS (WordPress-Plugin) - Tutorial
CalderaForms 1.5.9.1 XSS (WordPress-Plugin) - Tutorial
CalderaForm ist ein WordPress-Plugin, mit dem sich einfach per Drag & Drop Formulare erstellen lassen. Im Rahmen einer aktuellen Tätigkeit habe ich einige Portale getestet, auf denen genau ein solches, mit diesem Plugin erstelltes Kontaktformular gehostet wurde. Die benutzerdefinierte Konfiguration der betreffenden Instanz ermöglichte es mir, eine Sicherheitslücke zu finden: Aufgrund ihrer einfachen, lehrbuchhaften Natur denke ich, dass sie ein guter Anlass ist, um Einsteigern einige Mechanismen zu veranschaulichen.
Ausschließlich zu Lehrzwecken – diese Informationen nicht zum Testen von Zielen ohne ausdrückliche Genehmigung oder für illegale Zwecke verwenden – nicht nach dem Essen in kaltes Wasser springen – sich bei Hitze zwiebelartig anziehen
Für den vollständigen Exploit:
https://www.exploit-db.com/exploits/44489/
Für die CVE:
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-7747
In der untersuchten Konfiguration war das Formular so eingestellt, dass es dem Benutzer mit einer Dankesnachricht antwortet, die ihn mit dem gerade eingegebenen Namen anspricht.
Um die Testumgebung nachzubauen, installieren Sie lokal eine WordPress-Instanz und das Plugin CalderaForms Version 1.5.9.1 (verfügbar hier oder hier).
Nach der Installation: Über die WordPress-Administrationskonsole > linke Spalte > „Caldera Forms“ > obere Buttons > „New Form“ > Contact Form auswählen, umbenennen und „Create Form“

Nach der Erstellung kann die Konfiguration geändert werden: Obere Buttons > „Form Settings“ > Die Erfolgsmeldung (Success Message) so ändern, dass sie einen der vom Benutzer eingegebenen Daten enthält. Klicken Sie auf das Feld, es erscheint eine Dropdown-Liste mit Vorschlägen. Fügen Sie %first_name% hinzu

Obere Buttons > „Save Form“
Um das Formular in eine Seite einzufügen: Linke Spalte > „Pages“ > „Sample Page“ > „Edit“ > „Caldera Form“ > das gerade erstellte Formular auswählen > „Insert Form“ > rechte Spalte > „Update“

Erledigt.
Lassen Sie uns Schritt für Schritt die notwendigen Schritte zur Durchführung dieser Art von Angriff nach dem Prinzip „Teile und herrsche“ durchgehen.
Während des Tests, wenn man mit einer Komponente interagiert, muss man stets auf ihre Reaktionen auf die gegebenen Reize achten; insbesondere konzentrieren wir uns auf den „Weg“ der von uns eingegebenen Daten und etwaige Veränderungen, die sie durchlaufen.
Ein konkretes Beispiel für unseren Fall ist das Folgende:
Wir besuchen die Seite mit dem Formular: http://127.0.0.1/wordpress/sample-page/
Wir füllen das Formular mit den folgenden Daten aus
"First Name": myName
"Last Name": myLast
"Email Address": my@e.mail
"Comments": myComm
Die Daten werden gemäß der Plugin-Logik verarbeitet
Die erhaltene Dankesnachricht enthält die von uns im Feld First Name eingegebene Zeichenfolge
"Thank you myName, form has been successfully submitted."

Die von uns im Feld „First Name“ eingegebene Zeichenfolge wird in der Dankesnachricht zurückgegeben.
Insbesondere ist die Zeichenfolge in einem HTML-div-Tag enthalten.
Unsere Eingabe landet im HTML der Seite.
Bemerkung: „Gefällt uns. Wir haben einen Berührungspunkt.“
Machen wir einen Schritt vorwärts. Wie wird unsere Eingabe während der Phase, die wir „Verarbeitung“ (Punkt 2) genannt haben, behandelt? Insbesondere wollen wir wissen: Gibt es Einschränkungen bei den Zeichen (und deren Kombinationen), die wir verwenden können? Das Ziel ist natürlich, „Zeug“ injizieren zu können. Bei dem Versuch einer Injektion muss man im Hinterkopf behalten, wo unsere Eingabe landet, und die entsprechende „Sprache“ verwenden.
Daher interessiert uns, ob wir die typischen HTML-Zeichen und -Konstrukte verwenden können, und insbesondere, ob wir angesichts der Fähigkeit dieser Sprache, JavaScript zu enthalten/interpretieren, eine Strategie finden, um unseren Code in der „Landezone“, also dem zuvor bemerkten div-Tag, zu platzieren.
Dazu fügen wir im Feld „First Name“ ein einfaches HTML-Tag ein und beobachten, ob es „bereinigt“ (sanitized) wird, also so modifiziert, dass es harmlos/nicht interpretierbar gemacht wird, oder ob es uns unverändert zurückgegeben wird. Wir verwenden zu diesem Zweck ein <br>-Tag, das zum Einfügen eines Zeilenumbruchs im Text verwendet wird.
Unter Bezugnahme auf die vorherige Nummerierung:
Wir füllen das Formular mit den folgenden Daten aus
"First Name": m<br>yName
"Last Name": myLast
"Email Address": my@e.mail
"Comments": myComm
Die Dankesnachricht enthält unser HTML-Tag, das nicht verändert wurde, und es wird korrekt interpretiert, indem ein Zeilenumbruch in der Mitte der Nachricht eingefügt wird
"Thank you m
yName, form has been successfully submitted."

Bemerkung: „Gefällt uns. Wir können die Zeichen < und > verwenden, wir können HTML-Tags einfügen, die nicht bereinigt und interpretiert werden.“
Schritt weiter. Ersetzen wir das Formatierungstag durch etwas Nützlicheres, wie ein <script>-Tag, mit dem wir JavaScript-Code innerhalb der Seite einfügen und ausführen können.
Wir füllen das Formular mit den folgenden Daten aus
"First Name": m<script>alert(1);</script>yName
"Last Name": myLast
"Email Address": my@e.mail
"Comments": myComm
Die Dankesnachricht enthält unser HTML-Tag, das nicht verändert wurde und korrekt interpretiert wird, und zeigt uns eine Alert-Box an

Bemerkung 1: „Gefällt uns. Wir können beliebigen JavaScript-Code im Kontext des Benutzerbrowsers ausführen.“
Bemerkung 2: „Gefällt uns nicht. Der Benutzer, der das JavaScript ausführt, sind wir selbst.“
Die Situation ist folgende: Wir können JavaScript über eine von uns nicht kontrollierte Website im Kontext des Browsers eines Benutzers ausführen, aber dieser Benutzer ist momentan derjenige, der die Werte in das Formular eingibt. Das ist ziemlich nutzlos.
Die Idee ist: Gibt es eine Möglichkeit, die Dankesnachricht, die unseren auszuführenden Code enthält, erneut aufzurufen?
Kehren wir zu unserem ersten Submit zurück, dem der „Erkundung“ (oder führen wir die ersten Schritte erneut aus).
Durch Analyse des Netzwerkverkehrs oder des Seitenquellcodes erkennen wir, dass das Formular eine POST-Anfrage an die folgende Adresse sendet:
http://127.0.0.1/wordpress/cf-api/CF5ad9b3176c0f4
(Der letzte Teil kann variieren; passen Sie ihn in allen folgenden Beispielen entsprechend an.)
also an die Adresse:
http://<target>/cf-api/<form-id>
und dass die Antwort auf diese Anfrage ein JSON ist, das einige Daten enthält, darunter die Dankesnachricht, und die folgende Struktur hat:
{
"data":
{"cf_id":"48"},
"html":"<div class=\" alert alert-success\">Thank you myName, form has been successfully submitted.<\/div>",
"type":"complete",
"form_id":"CF5ad9b3176c0f4",
"form_name":"MyContactForm",
"status":"complete"
}
Heben wir uns diese Information auf, wir werden gleich darauf zurückkommen; insbesondere beachten wir die Felder "form_id" und "cf_id".
Was befindet sich an der Adresse, an die die POST gesendet wird? Ohne viele Vermutungen: Sehen wir, was passiert, wenn wir eine GET ausführen, also die Seite unter http://127.0.0.1/wordpress/cf-api/CF5ad9b3176c0f4 besuchen, und finden nichts anderes als das HTML des betreffenden Formulars.
und prüfen den vom Submit ausgehenden Netzwerkverkehr

Dieses Mal erhalten wir einen HTTP-Statuscode 302 (Redirect) auf die Location /wordpress/cf-api/CF5ad9b3176c0f4/?cf_su=1&cf_id=49, der uns nichts anderes als das HTML mit dem div-Tag der Dankesnachricht zurückgibt.
Beachten wir das Format dieser Adresse:
http://<target>/cf-api/<form-id>/?cf_su=1&cf_id=<cf-id>
wobei die Werte von <form-id> und <cf-id> genau diejenigen sind, die im zuvor analysierten JSON enthalten sind, nämlich "form_id" und "cf_id".
Haben wir die Ausgangsfrage beantwortet? Ja. Wir haben einen Weg gefunden, den Inhalt der Dankesnachricht erneut aufzurufen.
Bemerkung: „Gefällt uns. Wir können die Nachricht mit unseren Daten nach Bedarf abrufen.“
Fassen wir alles zusammen, indem wir alle bisher gesammelten Informationen verknüpfen und einen Angriff schnüren.
1) Wir speichern unseren schädlichen Code auf dem Ziel.
2) Wir sammeln die notwendigen Daten, um diesen Code abzurufen.
3) Wir konstruieren die URL, um unseren Angriff auszulösen.
Wir füllen das Formular (von einer der beiden Seiten, ist egal) mit den folgenden Daten aus
"First Name": m<script>document.body.innerHTML=String.fromCodePoint(128046);</script>yName
"Last Name": myLast
"Email Address": my@e.mail
"Comments": myComm
Durch Analyse des generierten Traffics, sei es das Lesen des empfangenen JSONs im Fall der Sample-Seite oder das Lesen des Redirects im Fall der Seite, die nur das Formular enthält, rufen wir die Identifikatoren form_id und cf_id ab
{
"data":
{"cf_id":"69"},
"html":"...",
"type":"...",
"form_id":"CF5ad9b3176c0f4",
"form_name":"...",
"status":"..."
}
http://127.0.0.1/wordpress/cf-api/CF5ad9b3176c0f4/?cf_su=1&cf_id=69

Einige Anmerkungen:
Dem interessierten Leser wird vorgeschlagen:
' (einfaches Anführungszeichen), das Zeichen " (doppeltes Anführungszeichen) oder das Zeichen ` (Backtick, Gravis) zu verwenden, das auf italienischen Tastaturlayouts fehlt.