Offene Umleitung in der Harvest-App ermöglichte den Diebstahl von OAuth-Tokens für Microsoft-Konten
(eval.blog)- Im OAuth-Verbindungsfluss von Harvest für Outlook Calendar leitete die Callback-URL erneut zum im
state-Wert angegebenen Ziel weiter, wodurch eine offene Umleitung entstand; in Kombination mit dem impliziten Grant-Flow konnten Tokens an externe URLs offengelegt werden - Das Problem lag nicht bei Microsoft, sondern auf der Seite der Harvest-Integration; das registrierte OAuth-
redirect_uriwurde zu einer Umleitungsstation, die Nutzer an eine vom Angreifer angegebene Domain schickte stateist URI-kodiertes JSON; wenn man insubdomaineine externe Domain mit Slash wieexample.com/einträgt, führt das zu einer Weiterleitung in der Formexample.com/.harvestapp.com/...- Das PoC zeigt mit der Microsoft-OAuth-Authorize-URL und
client_id=0dcef4db-36d8-4aed-9cc5-ab43e1814884,response_type=id_token,response_mode=fragment,scope=openid, wie das Fragment#id_token=...an das Weiterleitungsziel angehängt wird - Die Schwachstelle wurde nach einer Meldung am 23. August 2020 erst am 1. August 2023 als gepatcht bestätigt; am 22. Oktober 2023 entschuldigte sich Harvest und erklärte, die Verzögerung sei ein human error gewesen
Datenleck von Tokens im OAuth-Callback
- Harvest ist eine Zeiterfassungssoftware, mit der Nutzer Outlook Calendar per OAuth verbinden können
- Wenn die Autorisierung erfolgreich ist, werden Nutzer zu
https://outlook-integration.harvestapp.com/auth/outlook-calendar/…weitergeleitet - Dieser Callback verschiebt den Nutzer anschließend erneut zu der in
stateangegebenen URL, wodurch eine offene Umleitung entsteht - Der ursprünglich bestätigte
state-Wert der Callback-URL ist URI-kodiertes JSON- Dekodiert hat er die Form
{"return_to":"/","subdomain":"hackerone295"} - Der Wert
subdomainwird verwendet, um einen Harvest-App-Bereich wiehackerone295.harvestapp.comzu bestimmen
- Dekodiert hat er die Form
- Fügt man an
subdomaineinen Slash an, etwa mitexample.com/, wird die Callback-URL zu einer Weiterleitung auf eine externe Domain - Diese Callback-URL ist das in der OAuth-Anwendung registrierte redirect_uri; kombiniert man die offene Umleitung mit dem impliziten Grant-Flow, können Tokens am Weiterleitungsziel offengelegt werden
- Die PoC-Authorize-URL verwendet die folgenden Werte
client_id=0dcef4db-36d8-4aed-9cc5-ab43e1814884response_type=id_tokenredirect_uri=https://outlook-integration.harvestapp.com/auth/outlook-calendar/…?...scope=openidresponse_mode=fragmentstate=1nonce=123456
- Nutzer werden am Ende an eine URL in der folgenden Form weitergeleitet
https://example.com/.harvestapp.com/auth/… access token]&state=1
- Es handelt sich nicht um eine Schwachstelle auf Microsoft-Seite
Zeit bis zum Patch nach der Meldung
- Das Harvest-Team reagierte während der Offenlegung und des Patch-Prozesses nur sehr wenig; selbst nachdem die Schwachstelle im Triage-Prozess anerkannt worden war, dauerte die Behebung sehr lange
- Die Schwachstelle wurde am 23. August 2020 gemeldet, und am 16. Oktober 2020 nahm Harvest erstmals Kontakt auf
- Am 27. November 2020 erhielt der Report den Status triaged
- Am 28. April 2022 erklärte das Unternehmen, an einem Fix zu arbeiten, und nannte zwei Wochen als Zeithorizont, tatsächlich dauerte es aber noch etwa ein weiteres Jahr bis zur Behebung
- Am 1. August 2023 wurde bestätigt, dass die Schwachstelle gepatcht war
- Am 21. Oktober 2023 wurde der Bericht durch einen veröffentlichten Beitrag öffentlich
- Zum Stand dieses Tages befand sich der Report weiterhin im Status triage; obwohl die Bug-Bounty-Richtlinie eine Belohnung erwähnte, wurden weder eine Bounty noch HackerOne-Punkte ausgezahlt
- Nachdem der Beitrag am 22. Oktober 2023 Aufmerksamkeit erhalten hatte, entschuldigte sich Harvest und erklärte in einem Kommentar, dass die Verzögerung auf human error zurückzuführen gewesen sei
1 Kommentare
Kommentare auf Hacker News
Als Verantwortlicher für das Bug-Bounty-Programm erkläre ich, was intern passiert ist. Ich habe mich bereits bei @0xcrypto entschuldigt und es intern erklärt, aber ich halte es für richtig, es auch hier zusammenzufassen.
Wir konnten das Problem von Anfang an nicht vollständig reproduzieren und konnten es auch nicht schließen, weil wir Sorge hatten, etwas zu übersehen. Kurz nachdem ich zuletzt geantwortet hatte, dass ich „eine Lösung finden“ würde, kamen wir der Einschätzung näher, dass es nicht reproduzierbar sei. Dann ging eine ähnliche OAuth-bezogene Meldung ein, wodurch intern Verwirrung entstand und wir fälschlich annahmen, wir hätten sie bereits bearbeitet und weitergegeben.
Wegen der Benachrichtigungseinstellungen habe ich Folgemeldungen verpasst, und das Issue blieb auf unbestimmte Zeit im Triage-Status, ohne Updates. Das ist keine Ausrede; ich war lange selbst als Bug-Bounty-Hunter aktiv und weiß sehr gut, wie frustrierend es ist, auf Updates eines Unternehmens zu warten. Kundensicherheit hat oberste Priorität, und was auf der Sicherheitsseite steht, entspricht der Wahrheit.
Außerdem ist nun unklar, wie eine Meldung behandelt werden soll, die sich nicht mehr reproduzieren lässt. Ich hätte das gern auf HackerOne weiter diskutiert, aber nach der Entschuldigung scheint wieder Funkstille eingetreten zu sein.
Der App-Zustand weicht häufig vom Server-Zustand ab; Serveränderungen werden erst nach einem erzwungenen Refresh sichtbar, oder Client-Änderungen werden nach dem Speichern wieder zurückgesetzt. Auch die User Experience beim Zeiterfassen ist unbequem: Buttons sind erst nach dem Scrollen sichtbar, oder die Positionen der Start-/Stopp-/Neustart-/Löschen-Buttons ändern sich ständig je nach Status des Eintrags. Die alte App war nicht hübsch, funktionierte aber problemlos.
Das ist ziemlich beunruhigend. Als ich Harvest genutzt habe, war der Support wirklich hervorragend: schnelle Antworten, ein sehr genaues Verständnis dafür, wie Kunden das Produkt verwenden, und ausführliche Hinweise dazu, wie man bestehende Funktionen kreativ nutzen kann.
Bei nicht implementierten Funktionen lautete die Antwort: „Wir nehmen es ins Backlog auf, können aber nichts versprechen.“ Es heißt, es gebe 30 Personen im Engineering [1], aber ich bin mir nicht sicher, wofür diese Kapazität eingesetzt wird, da ich auch nicht gesehen habe, dass andere Funktionen schnell ausgeliefert werden.
Als ich anfing, Spam als „Harvest-Nutzer“ zu bekommen, vermutete ich, dass die Kundenliste verkauft worden sei. Die Verantwortlichen des Unternehmens meldeten sich jedoch direkt, widersprachen entschieden und nahmen die Sache so ernst, dass sie sofort eine Untersuchung einleiteten. Das war gut.
Am Ende wirkt aber auch das wie ein Engineering-Problem. Ich fand eine ziemlich einfache Methode heraus, mit der man aktive Kunden abschätzen konnte; auch das landete im „Backlog“ und ist seit Monaten nicht behoben. Die Korrektur wirkte äußerst trivial. Außerdem bietet MFA nur dann Schutz, wenn man sich mit Google anmeldet [2]. Trotzdem macht die App selbst ihre eigentliche Aufgabe wirklich gut.
1: https://www.getharvest.com/about/meet-the-team
2: https://support.getharvest.com/hc/en-us/articles/36005266713...
Dass die Kommunikation mit dem Melder in diesem Thread schiefgelaufen ist, war vollständig mein Fehler, und wie in meiner Antwort oben erklärt, werde ich dafür sorgen, dass so etwas nicht noch einmal passiert.
Einige Funktionswünsche sind sogar tatsächlich ins Produkt eingeflossen. Vielleicht lag das nicht an meinem Einfluss, aber zumindest hatten wir offenbar ähnliche Vorstellungen davon, was einen guten Zeiterfasser ausmacht.
Der Titel wirkt Microsoft gegenüber ziemlich unfair. Es fühlt sich so an, als solle ausgenutzt werden, dass Microsoft durch die jüngsten Authentifizierungsvorfälle im Fokus steht; als ich den Titel sah, dachte ich sofort: „Schon wieder ein MS-Breach?“
Tatsächlich handelt es sich um Harvests Token, und wegen einer Injection-Schwachstelle im Harvest-Code wurden lediglich Harvest-App-Zugriffsrechte falsch offengelegt. Hinter jedem anderen Identity Provider wäre es genauso verwundbar gewesen.
Die Schwachstelle betrifft nämlich nur die OAuth-Implementierung für die Verknüpfung von Microsoft-Konten. Der ursprüngliche Titel lautete „Microsoft OAuth token leak via open redirect in Harvest App“, später habe ich ihn in „Microsoft Account's OAuth tokens leaking via open redirect in Harvest App“ geändert. Ich bin weiterhin offen dafür, ihn zu ändern, und nehme Vorschläge an.
RFC 6749 behandelt ausführlich, wie Authorization Server solche Angriffe verhindern können.
Authorization Server müssen für öffentliche Clients zwingend die Registrierung von Redirect-URIs verlangen; für vertrauliche Clients wird dies ebenfalls empfohlen. Wenn in der Anfrage eine Redirect-URI angegeben ist, muss der Authorization Server sie gegen den registrierten Wert prüfen.
Daher frage ich mich, wie das möglich war, wo die Harvest-App doch wohl keine bösartige
redirect_uriregistriert hatte. Ignoriert der Microsoft-OAuth-Server beim Vergleich mit den registrierten Redirect-URIs des OAuth-Clients die URL-Parameter innerhalb derredirect_uri?stategepackt. Vermutlich sollte damit an eine beliebige Stelle weitergeleitet werden.Der beabsichtigte Ablauf war wohl: zur Harvest-Authentifizierungs-URL gehen → Weiterleitung zur Microsoft-Authentifizierungs-URL mit
redirect_uri=registered_uriundstate=some_encoded_final_uri→ der Nutzer gibt seine Zugangsdaten ein → Weiterleitung zur registrierten URI →stateauslesen und erneut zu der darin enthaltenen URI weiterleiten.Auch dieser Angriff leitet weiterhin zu einer erlaubten URI weiter, aber dieser Endpoint liest
stateaus und reicht die Antwort/das Token unverändert weiter. Es gab drei Fehler: Missbrauch vonstate, falls man es schon missbraucht,statenicht zu verschlüsseln und zu validieren, und Implicit Grant aktiviert zu haben. Falls das nötig war, hätte man dafür eine separate Registrierung mit eingeschränktem Zweck anlegen sollen.redirect_urivon Harvest ist bei Microsoft registriert. Nachdem der Microsoft-OAuth-Server zu Harvest weitergeleitet hatte, implementierte Harvest auf Basis der Daten instateeine eigene Weiterleitung.Implicit Grant ist aus genau solchen Gründen, wie in diesem Beitrag zu sehen, ziemlich furchtbar.
Nebenbei: In der kommenden OAuth-2.1-Spezifikation soll er entfernt werden: https://www.ietf.org/archive/id/draft-ietf-oauth-v2-1-09.htm...
Dass die Behebung der Schwachstelle 3 Jahre gedauert hat? Von August 2020 bis August 2023 – ich kenne die Größe des Harvest-Teams nicht, aber das wirkt trotzdem völlig absurd.
Ich würde mir wünschen, dass ein OAuth-Experte dieses Problem etwas genauer erklärt. Ich habe den Blog mehrmals gelesen, verstehe die eigentliche Schwachstelle aber immer noch nicht.
Nach meinem sehr begrenzten OAuth-Verständnis bittet die Harvest-App Microsoft darum, den Nutzer zu verifizieren; Microsoft verifiziert den Nutzer und leitet bei Erfolg zur Callback-URL weiter, wobei das Access Token im Antwortkörper übergeben wird.
Hat der Blogautor in diesem Fall nicht einfach nur eine selbst gebaute URL erstellt, bei der die Rückgabe-URL nicht die echte Rückgabe-URL ist, sondern zu example.com führt?
harvestapp, und der vom Angreifer kontrollierte Teil befindet sich instate, das aus Sicht des OAuth-Servers weitgehend undurchsichtig ist.Mit dieser URL kann man jemandem einen Link zu
login.microsoftonline.comschicken, eine Login-Aufforderung „Bei Harvest anmelden“ anzeigen lassen und danach kann der Angreifer echte Berechtigungen im Zusammenhang mit dem Harvest-Konto erhalten.Normalerweise ist das nicht möglich. Ein Angreifer kann zwar eine neue App registrieren, die zu
example.comweiterleitet, aber dann erhält er kein Access Token mit Harvest-bezogenen Berechtigungen, also ist das nutzlos.Die OAuth-App auf Microsoft-Seite hat eine gültige Allowlist für Redirects, daher würde ein Versuch wie
login.microsoftonline.com/authorize?client_id=$harvestAppID&redirect_uri=attacker.combei Microsoft einen Fehler auslösen. Der Angriff ist möglich, weil eine gültige URL unteroutlook-integration.harvestapp.comdas Access Token entgegennimmt und anschließend zur Angreifer-Website weiterleitet – samt Access Token.outlook-integration.harvestapp.com. Alsstatewurde ein JSON-Objekt verwendet, das Anweisungen enthielt, die nach einem erfolgreichen OAuth2-Callback auszuführen waren.Die Eigenschaft
subdomainwurde genutzt, um den Browser auf eine Subdomain vonharvestapp.comweiterzuleiten und dabei#id-tokenzu übergeben. Das Problem war, dass der Wert vonsubdomainunverändert in die folgende URL eingefügt wurde:https://${subdomain}.harvestapp.com/...#id-token=...
Wenn man im JSON-Payload
subdomainauf einen Wert wieattacker-controlled.com/mit angehängtem Slash setzt, wird die URL zuhttps://attacker-controlled.com/.harvestapp.com/...#id-token=.., und der Browser wechselt auf eine andere Domain, wobei das Token offengelegt wird.Daher ist das kein inhärentes Problem von OAuth selbst, sondern eine schlechte Implementierung.
Statt beim Einrichten des Workflows eine echte Liste vertrauenswürdiger Callback-URLs anzulegen, haben sie möglicherweise Wildcards in der Allowlist für Callback-URLs verwendet. Ich könnte auch völlig danebenliegen.
Ich verstehe nicht, warum man drei Jahre gewartet hat. Eine Frist vor der Veröffentlichung von 90 Tagen reicht aus.
Solche zusätzlichen Aufschübe sollten allerdings von den Forschern bzw. deren Anwälten/Vertretern gewährt werden. Das ist die Art von Bitte, die ein Unternehmen bei einem außergewöhnlich großen Fall in gutem Glauben stellen kann.
Wenn HackerOne zulässt, dass Unternehmen solche Dinge drei Jahre liegen lassen, scheint es seine Rolle nicht richtig zu erfüllen.
Auf der einfachsten Stufe stellen sie lediglich eine Plattform zur Offenlegung von Schwachstellen sowie standardisierte Rechtstexte bereit, damit Forscher nicht vom Legal-Team verklagt werden.
In den meisten Fällen lehnen Unternehmen Anfragen zur Veröffentlichung ab. Wenn Forscher ohne Erlaubnis veröffentlichen, verstoßen sie gegen die Vereinbarungen mit HackerOne und dem Unternehmen und setzen sich rechtlicher Haftung aus. In diesem Fall scheint das Unternehmen der Veröffentlichung zugestimmt zu haben; auch wenn die Reaktion sehr langsam war, ist das meiner Ansicht nach anzuerkennen.
Ich persönlich hatte auch schon mehrfach Bugs mit vierstelligen Prämien, die länger als ein Jahr nicht behoben wurden, habe das aber nicht HackerOne angelastet.
HackerOne hat das nicht interessiert. Obwohl wir mehrfach darauf hingewiesen haben, dass diese Person gegen ihre Regeln verstößt, hieß es, man könne nichts tun.
Es wirkte, als sei ein Unternehmen, das einmal auf Normalbetrieb ausgelegt war, auf eine Minimalbesetzung zusammengeschrumpft worden, bei der Support-Mitarbeiter ohne Befugnisse Fragen beantworten. Das ist schon eine Weile her, also kann es heute anders sein, aber damals war das mein Eindruck.
Wenn Unternehmen das Gefühl bekommen, dass HackerOne Grenzen überschreitet und entscheidet, was es dem Unternehmen „erlaubt“, zu tun, werden sie HackerOne einfach verlassen und interne Lösungen aufbauen.
Ich verstehe nicht, warum dieses Issue nicht an Microsoft weitergeleitet wurde. Microsoft hätte die Zugriffsrechte dieser OAuth-Anwendung entziehen können, bis das Problem behoben ist.
Allerdings dürfte es bei Microsoft Tausende ähnlich schlechte Implementierungen geben, die per OAuth angebunden sind.