CMS iKISS: 716 kommunale Websites waren von XSS-Lücke betroffen

Das Content-Management-System iKISS der Firma Advantic GmbH ist bei vielen Websites von Städte, Gemeinden und Landkreisen im Einsatz. Laut Herstellerangaben verwendet jeder 5. Landkreis in Deutschland das CMS iKISS. Dieses war nun von einer Cross-Site-Scripting-Lücke betroffen.

Recherche ist wichtig!

Die Story beginnt mit einem Joke und einer versäumten Recherche. Ich entdeckte die reflected-XSS-Lücke zunächst auf der Webseite des Kreises Mettmann (kreis-mettmann.de). Zu dem Zeitpunkt war mir nicht klar, dass es sich hierbei um eine Lücke in einem weitverbreiteten CMS handelt. Viel mehr ging ich von einer „laienhaft“ programmierten PHP-Datei aus und schenkte der Lücke keine weitere Aufmerksamkeit. Auch auf das Reporten verzichtete ich, da es auf der Webseite augenscheinlich keine Daten gibt, welche man abgreifen könnte. Nach einigen Tagen viel mir beim Verzehr eines Mettbrötchens die XSS-Lücke erneut ein. Da man an einem Samstagabend in Coronazeiten nicht so viel machen kann, fing ich an zu „programmieren“.

Die Idee war: Ein Mett-Bestellservice für den Kreis Mettmann.

Gesagt getan, mit ein bisschen JavaScript konnte ich mein Wunderwerk der Programmierkunst auf der Webseite des Kreises Mettmann platzieren und es den Leuten auf Twitter präsentieren.

Erst später kam ich auf Idee, mal nach der PHP-Datei vt_stats.php zu Googeln, welche hier als Grundlage für die XSS-Lücke dient.

Oh no!
Scheinbar war es kein Einzelfall. Bei Google waren mehrere hundert Webseiten auffindbar, welche alle die gleiche XSS-Lücke aufwiesen.

Durch das sichten der Meta-Tags betroffener Webseiten, stellte ich fest, dass es sich um das CMS iKISS handeln musste.

Und was lerne ich daraus?: Erst Recherchieren, dann lustige Spielereien auf Twitter posten oder es sein lassen 🙂

Was erlaubt die Lücke?

Die reflected-XSS-Lücke erlaubt die Ausführung von JavaScript auf der betroffenen Webseite im Kontext des Benutzers. Dazu ist der Aufruf eines manipulierten Links notwendig. Durch die Ausführung von JavaScript können Falschinformationen dargestellt werden (bspw. ein Mett-Bestellservice) und auch Informationen abgegriffen werden. Letzteres ist besonders kritisch, wenn der Benutzer im CMS eingeloggt ist, wie es z.B. bei Administratoren und Mitarbeitern der Stadt / des Landkreises der Fall ist. Aber auch die Darstellung eines gefälschten Login-Dialogs ist möglich. Zudem ist unklar, ob die XSS-Payload möglicherweise auch an anderen Stellen zur Ausführung kommt. Sofern das Admin-Panel zur Darstellung der Link-Statistiken ähnliche Lücken aufweist, könnte das Ausmaß deutlich drastischer sein.

Technische Details

Die Datei /output/vt_stats.php wird zum Weiterleiten auf interne und externe Webseiten genutzt. Dabei werden wahrscheinlich Statistiken erfasst, um die Anzahl der Klicks diverser Links zu messen. Der URL-Parameter query enthält unter anderem das Ziel der Weiterleitung und sieht wie folgt aus:

/output/vt_stats.php?query=eyJzZWFyY2giOiJaMlZ6ZFc1a2FHVnBkSE5oYlhRPSIsInRhcmdldCI6IlwvP29iamVjdD10eCwyMDIzLjI5ODcuMSIsIk1vZElEIjoiNyIsIlZUTGEiOjF9

Das „ey“ zu Beginn der Zeichenkette lässt auf ein Base64-kodiertes JSON-Objekt schließen. Ein decoding bestätigt dies. Das JSON-Objekt hat folgende Struktur:

{"search":"Z2VzdW5kaGVpdHNhbXQ=","target":"\/?object=tx,2023.2987.1","ModID":"7","VTLa":1}

Das Attribut search enthält erneut einen Base64-kodierten Suchbegriff. In diesem Fall „gesundheitsamt“. Das Attribut target stellt das Ziel der Weiterleitung dar. Die anderen Parameter dienen vermutlich nur für die Statistikerfassung und sind im weiteren Verlauf irrelevant.

Wer den OWASP-Katalog kennt, dem wird wahrscheinlich direkt das Problem mit den Unvalidated Redirects and Forwards einfallen. Ein einfacher Test zeigt, ob das Problem auch hier zutrifft.

Modifiziertes JSON-Objekt (unnötige Attribute entfernt):
{"target":"https://google.com"}

Das Ganze Base64-encoded:
eyJ0YXJnZXQiOiJodHRwczovL2dvb2dsZS5jb20ifQ==

Wichtig: Base64-Strings in die URL zu kloppen führt oft zu Fehlern. Denn bei der serverseitigen Interpretierung gelten die Regeln einer URL. Sonderzeichen wie +, /, und = sind reserviert und haben eine andere Bedeutung in URLs. Ein + wird bspw. als Leerzeichen interpretiert. Daher sollten Base64-String in URLs immer URL-Encoded werden oder das Base64-URL-Encoding nutzen.

Dies bestätigt nun also den „Open-Redirect“, was aus meiner sicht aber kein wirkliches Sicherheitsrisiko darstellt. Viel spannender wirds wenn man die gängigen XSS-Ansätze ausprobiert. Davon ausgegangen, dass das href-Attribut nicht korrekt unescaped wird und es keine sonstigen URL-Validerungen oder Filterungen gibt, wäre die die Payload "><script>alert(0)</script> erfolgreich.

Wie man sehen kann, wird im Response-Quelltext ein valides Script-Tag zurückgegeben. Dies kommt allerdings nicht zur Auführung, da der Browser direkt der Weiterleitung aus dem Location-Header folgt.

Lustigerweise kann man aber bei manchen PHP-Frameworks den Header entfernen, indem man den CRLF Injection Schutz ausnutzt. Diese Schutzmaßnahmen verhindern oftmals das Setzen von Header-Werten mit Zeilenumbrüchen. So auch hier.

Payload: "> \n <script>alert(0)</script>

Nun ist der Location-Header weg und aus dem 302 Found wird ein 200 OK. Jetzt noch ein Aufruf im Browser:

Nach kurzer Recherche war es mir möglich mehr als 300 betroffene Websites ausfindig zu machen. Ca. 90% der Websites waren Internetauftritte von Städte und Landkreise in ganz Deutschland. Bei allen Websites war die Base64-kodierte Payload ohne Änderungen ausführbar.

Kontaktaufnahme mit der Advantic GmbH

Nachdem ich leider etwas voreilig die Lücke auf Twitter präsentiert habe, kontaktierte ich am 06.12.2020 die Advantic GmbH, welche sich recht schnell mit dem Thema befasste und einen Patch entwickelte.

06.12.2020 – Meldung der XSS-Lücke an die Advantic GmbH per E-Mail.
07.12.2020 – Die Advantic GmbH bestätigt die Lücke und kündigt einen Patch an.
08.12.2020 – Ein Update mit der Version iKISS 7.3 P1 wird an die Kunden verteilt.

Der „Fix“

Inzwischen verzichte ich meist auf Lösungsvorschläge beim Reporten von Bugs, da die Hersteller meist eh einen anderen Weg wählen und der Vorschlag kommentarlos ignoriert wird. Ob hier ein Lösungsvorschlag das folgende Drama verhindert hätte, bleibt fraglich.

Am 09.12.2020 testete ich einige Websites erneut. Tatsächlich hatte das Update bereits einen kleinen Teil der betroffenen Websites erreicht. Beim Betrachten des Fix staunte ich nicht schlecht.

Anstelle die Ausgabe des target-Parameters einfach durch htmlspecialchars() zu jagen und eine ordentliche URL-Validierung durchzuführen, bestand der Fix lediglich aus:

  • Der Entfernung des <script>-Tags. Oder besser gesagt: <script> wird durch XSC_1> ersetzt.
  • Einer unzureichenden Validierung des target-Parameters. Dieser muss nun mit http://, https:// oder / beginnen. Damit kann zumindest die Verwendung von javascript: als Ziel verhindert werden.

Response mit alter Payload:

Neue Payload:

  • Beginnt mit /
  • Nutzt das SVG onload-Event zur Ausführung von JavaScript anstelle des <script>-Tags

{"target":"/\">\n<svg onload=\"alert(document.cookie)\">"}

Fix bypassed 🙂

14.12.2020 – Erneute Kontaktaufnahme per Mail
14.12.2020 – Die Advantic GmbH möchte sich dem Thema erneut widmen
16.12.2020 – Ein weiterer Patch wird released (vermutlich iKISS 7.3 P2)

Nach dem zweiten Anlauf konnte die Advantic GmbH die XSS-Lücke stabil schließen.

Fazit

Responsible disclosure funktioniert nicht so gut wenn man das Ganze direkt mit einem Joke auf Twitter rausposaunt. Immerhin war nicht nur ich ziemlich inkompetent. Da es sich bei iKISS um ein „Closed Source“ CMS handelt, lassen sich derartige Lücken oftmals nur schwer identifiziere und bleiben somit über lange Zeit unentdeckt. Viele solcher proprietären CMS-Hersteller bieten zudem auch kein Bug Bounty Programm an.

Kommentare

    1. nein, bei Unternehmen die kein Bug-Bounty-Programm betreiben, frage ich nur bei gravierenden Lücken nach einem Bounty. Z.B. bei SQL-Injections o.ä. Bei den Webseiten der Länder, Städte und Gemeinden ist generell kein Bounty drin 🙁

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.