Software-Sicherheit ist ein schwieriges Thema: Nicht nur, weil es trotz zahlreicher Maßnahmen zur Fehlervermeidung nahezu unmöglich ist, komplett fehlerfreie Software zu schreiben, sondern auch, weil das Beheben eines Fehlers dessen Gefahrenpotential extrem steigern kann. Im Umfeld von OpenSource-Software haben sich daher verschiedene Vorgehensweisen zum Umgang mit gemeldeten Fehlern etabliert, die von Full Disclosure, über Responsible Disclosure bis hin zu Irresponsible Disclosure reichen. Einen Vertreter der letzteren Kategorie möchte ich heute einmal vorstellen, da in diesem Fall einige Dinge zwar richtig angegangen wurden, in ihrer Umsetzung aber eine unnötige Gefährdung der Nutzer resultierte.
Angefangen hat die hier beispielhaft dargestellte Episode vor etwa einem Monat, mit einem Tweet von nomoketo mit der Frage für einen Kontakt zum Reporten eines Sicherheitsproblems, der korrekt nicht-öffentlich bearbeitet wurde. Soweit recht normal und wenig spannend. Was mich auf die Sache aufmerksam machte, war ein weiterer Kommentar mit Quellenangabe, der kurz darauf folgte: Erst 2013 wurde die Speicherung von Passwörtern von Klartext auf (ungesalzene) Hashes umgestellt. Dass die Hashes ungesalzen waren, ergab sich durch einen Blick in den Quelltext; und wie es nunmal so ist, war dieser Blick einer zu viel und neben der (Quasi-)Klartext-Speicherung vielen gleich 3 weitere Probleme auf:
- Akzeptieren des Hashes als Klartext-Passwort (Logic Bug)
- Nicht-Konstantzeit-String-Vergleich bei der Passwort-Prüfung (Timing Oracle)
- Unzureichende Hash-Stärke
Wirkt harmlos? Schauen wir einmal: Auf Grund des Timing Oracles konnte man anhand der Antwort-Zeit des Servers (bei ausreichend genauer Messung) den Inhalt des Datenbank-Feldes rekonstruieren. Dieser beinhaltete entweder das Passwort selbst oder dessen Hash. Mit dem Legacy-Passwort ist man drin (Authentiction Bypass). Bei einem ausreichend starken Hash wäre hier eigentlich Schluss, aber dank eines Logik-Fehlers bei der Passwort-Prüfung führte ein Fehlschlag des Hash-Vergleichs zum direkten String-Vergleich zwischen Hash und dem gesendeten Passwort. Da wir den Hash durch das Timing Oracle kennen, sind wir also auch hier drin (Authentication Bypass). Ein stärkerer Hash hätte mit diesem Logik-Fehler zwar nur wenig ausrichten können, hätte aber zumindest den für das Timing Oracle notwendigen Code-Pfad extrem verlangsamt, womit der Angriff erheblich auffälliger geworden wäre. Außerdem hätte der Angreifer mit einem starken Passwort-Hash nicht die Wahl gehabt, sich nach dem Erbeuten des Hashes ganz normal mit dem Klartext-Passwort anzumelden. Entsprechende Datenbanken gibt es zu Hauf …
Die Reaktion war entsprechend eindeutig. Details gab es an dieser Stelle aber vorerst ausschließlich privat. Kurz darauf kontaktierte mich Thorsten Eckel via DM mit Details für den Security-Kontakt. Da sein Account nur den üblichen Ei-Avatar hatte, und ich wusste, dass nomoketo bereits kontakt hatte, ließ ich mir die Details kurz Gegenprüfen – eine öffentliche Liste der Maintainer, sowie eine Möglichkeit zur Ende-zu-Ende-verschlüsselten Kommunikation fehlten leider. Diese sollten auf der Webseite, oder auf Anfrage griffbereit verfügbar sein. Infos zur verschlüsselten Kommunikation mit mir, gibt’s bei keybase.io.
Die initiale Meldung der oben aufgeführten Probleme lief via Email an die von Thorsten genannte Adresse – inklusive einer ausführlichen Beschreibung der verschiedenen Lücken, Voraussetzungen für deren Ausnutzung und die damit assoziierten Gefahren (AKA Risiko-Einschätzung). Zwei der 4 genannten Probleme trugen dabei die Stufe hoch. Die Antwort erfolgte zeitnah und verwies auf eine erste Version eines möglichen Patches für die genannten Probleme. Dies ist in sich nicht weiter tragisch, wäre der Patch nicht gerade direkt öffentlich auf Github gelandet.
Bei sicherheitskritischen Bugs ist es essentiell, dass Details zu einer Lücke erst öffentlich werden, wenn auch ein Patch zur Verfügung steht, um diese zu schließen. Andernfalls können Angriffe auf verwundbare Systeme gestartet werden, ohne dass eine effektive Gegenwehr möglich ist. Je nach Verbreitung einer Software finden solche Angriffe dabei meist bereits nach wenigen Stunden automatisiert und im großen Stil statt. Wenn also zur Mitte des üblichen 4-Wochen-Release-Zyklus ein Zero-Day öffentlich wird, haben Angreifer mehr als genug Zeit, diese Schwachstelle auszunutzen. Verschärfend kam in diesem Fall auch noch hinzu, dass der Patch zwar funktional war, aber in Hinblick auf die Best Practices unvollständig war.
Analog wurde auch die von nomoketo gemeldete Lücke auf diese Art vorzeitig öffentlich: Ein trivial ausnutzbarer Clientside-XSS-Bug, der beliebige Inhalte direkt auf die Webseite einbinden ließ. Im Gegensatz zu den Problemen betreffs meiner Meldung war der hierfür anfänglich vorgeschlagene Patch aber löchrig bis unwirksam, so dass jedem, der die Github-Logs etwas beobachtet, auf dem Präsentierteller eine erstklassige Vorlage für eine Lücke samt Exploit geliefert wurde – mit Anleitung, wie dieser auch auf notdürftig gepatchten Systemen weiterhin ausnutzbar wäre.
Davon abgesehen sind beide Patches insgesamt vergleichsweise umfangreich, so dass ein Review recht anstrengend ist. Die dennoch an den Commit, der eine Blacklist für bösartigen Code implementierte, angehängten Kommentare verwiesen daher auch schnell auf die zwei relevanten Quellen für diesen Fall:
- Das OWASP Cross Side Scripting Cheat Sheet – mit XSS-Angriffsvektoren
- Den OWASP Cross Side Scripting Mitigation guide – mit Best Practices zur Vermeidung von XSS
Auch andere Kommentare empfahlen recht zügig, den Blacklist-Ansatz zu Gunsten einer Whitelist-Lösung ersetzt wurde. Weitere Vorschläge für die Absicherung wurden genannt, sind aber im Zuge eines Security-Updates zu umfangreich umzusetzen, da diese primär auf Defense-in-Depth abzielen. Zu den weiteren Vorschlägen gehörten u.a.
- Content Security Policy
- Sub-Resource Integrity
- Nonces für Script-Ausführung
Es bleibt aber zu hoffen, dass diese zu einem späteren Zeitpunkt noch nachgereicht werden und die Anstrengungen beim Absichern gegen Sicherheitslücken nicht nachlässt, wie es bei der Kommunikation der Zwischenstände der Fall war. Abseits der unregelmäßig im Git öffentlich einsehbaren neuen Patches, war lange Zeit die Information, dass aktuell CVE-Nummern angefordert werden, die letzte Information von offizieller Seite in direkter Kommunikation.
Und so war auch das Testen der Bugfixes eher unkoordiniert: Tage vor dem wahrscheinlichen Release-Termin des Bugfix-Releases probierte nomoketo nochmals, ob die gemeldeten Fehler nun behoben sind – und stellte gleich den nächsten Fehler fest, der in Kombination mit der weiter oben erwähnten Authentifizierungsproblematik deren Ausnutzung stark begünstigte. Das Problem dieses Mal war, dass die API zum Abfragen von Daten zu einem Nutzer, neben den üblichen Details unter gewissen Umständen auch den Hash des Nutzerpasswortes (oh oops, ich meinte: das Passwort) lieferte. Erschwerend hinzu kam, dass für diese API CORS-Header gesendet wurden, wodurch – verhindert nur durch ein Security-Feature im Browser – man über Domain-Grenzen hinweg die Gesamte Nutzerliste samt verwendeter Passworte auslesen konnte. Wer Zammad im Einsatz hatte, sollte also einmal alle Passwörter zurücksetzen und diese auch überall, wo sie sonst noch Verwendung fanden, einmal ändern. Den Patch dazu gibt es wie gehabt auf Github (diesmal aber erst nach dem Release zugänglich).
Abschließend bleibt also zu sagen, dass jedes OpenSource-Projekt neben einem regulären Bugtracker auch einen Prozess zum Melden kritischer Sicherheitsprobleme vorweisen sollte. Dieser sollte leicht zu finden sein und die vertrauliche, verschlüsselte Kommunikation ermöglichen. Zudem sollte dieser Prozess sicherstellen, dass sicherheitskritische Patches solange wie möglich unter Verschluss gehalten werden und nur für die Behebung benötigten Personen zugänglich sind. Diese Einschränkung der Sichtbarkeit mag zuerst im Widerspruch zur Transparenz in OpenSource-Projekten erscheinen, schützt korrekt umgesetzt aber vorhandene, verwundbare Installationen der Software vor großflächigen Angriffen mit dieser Verwundbarkeit. Sollte ein Exploit – oder Details zu einem Sicherheitsproblem – in the wild existieren, so ist ein Sicherheitsrelease – auch Abseits des üblichen Rhythmus – oberste Priorität.
Etabliert haben sich im Bereich der Responsible Disclosure von Lücken etwa die Regelungen des Project Zero unter Leitung von Google. Werden Details zu einer vertraulich gemeldeten Lücke fahrlässig vorab bekannt, ist dies nicht nur für die Nutzer riskant, sondern auch für die Meldenden frustrierend. Durch einfache Gestaltung des Prozesses zum Melden von Fehlern und Vermeidung der größten Fettnäpfchen bei deren Beseitigung, werden sich regelmäßig Leute finden, die unvoreingenommen und abseits der eingefahrenen Muster im Projekt einmal einen Blick werfen, und ihren Fund melden. Wie die 5 Bugs in diesem Release eindrucksvoll zeigen.
Ansonsten kann ich mich hier nur nomoketo anschließen, und jedem Nutzer von Zammad DRINGEND zum Update und zum Wechsel seines Passwortes raten. Die letzten 4 Wochen waren eine sehr interessante Erfahrung und es besteht die Hoffnung, dass das Entwickler-Team das neu gewonnene Wissen gewinnbringend für die weitere Verbesserung der Software einsetzen kann.