trovo.live: Die wohl unsicherste 30 Millionen US-Dollar Plattform

Trovo.live ist der neue Stern am Streaminghimmel. Bei der Plattform handelt es sich um ein Live-Streaming-Videoportal, welches vorrangig zur Übertragung von Games genutzt wird. Nicht nur optisch, sondern auch funktional ähnelt die Plattform Twitch sehr stark. Wer genau hinter dieser Plattform steckt, ist nur schwer zu erkennen. Was jedoch feststeht, ist die Tatsache, dass das chinesische Unternehmen Tencent Holdings Ltd. maßgeblich in die Plattform investiert hat. Genauer gesagt sind es 30.000.000 US-Dollar, welche zum Erfolg der Plattform beitragen sollen.

Momentan befindet sich Webseite sowie die Apps für Android und iOS noch in einer Beta-Phase. Trotzdem ist der Hype groß. Viele ehemalige Twitch-Streamer sind bereits zu Trovo gewechselt. Grund hierfür ist zum einen ein verlockendes Partner-Programm aber auch eine verhältnismäßig hohe Zuschauerzahl. Während viele Streamer auf Twitch kaum Anschluss finden, sind bei Trovo auch auf den untersten Plätzen im Ranking noch im Schnitt 10 Zuschauer anzutreffen. Es macht den Anschein, als wäre das Verhältnis zwischen Anzahl der Broadcaster und Anzahl der Zuschauer auf Trovo deutlich ausgeglichener als es bei Twitch der Fall ist. Ob das dauerhaft so ist, bleibt abzuwarten. Gerade in den ersten Wochen der Plattform strömten viele schaulustige auf Trovo, um sich ein Bild von der Plattform zu machen. Die Resonanz ist durchweg positiv.

Technische Einblicke

Die Macher der Plattform wollen scheinbar auch technologiemäßig ganz groß mitspielen. So findet man moderne Frameworks wie Vue.js und GraphQL sowie ein nahezu latenzfreies Video-encoding. Die Kommunikation mit dem GraphQL-Backend erfolgt hier nicht wie üblich per HTTP(S)-Requests sondern größtenteils über ein Websocket. Die Benutzerauthentifizierung via E-Mail und Passwort geschieht scheinbar über einen Drittanbieter. Zumindest werden die Logindaten an web-us.msdkpass.com gesendet und auch dort validiert. So viel zu den ersten Erkenntnissen.

Das PIN-Desaster

Beim Untersuchen von Webseiten mit Anmeldefunktionen schaue ich mir die „Passwort vergessen“-Funktion meist als erstes an. Hier stößt man immer wieder auf diverse Lücken. Wie schon erwähnt, verwendet Trovo hier einen scheinbar externen Dienstleister unter msdkpass.com. Dann sollte ja alles safe sein, oder?

Der „Account recovery“ Prozess bei Trovo.

Anstelle eines Links erhält man einen 5-stelligen Bestätigungscode an die hinterlegte E-Mail-Adresse. Warum diese unsichere Art der Verifizierung noch immer von manchen Webseiten praktiziert wird, ist mir ein Rätsel. Die werden ja wohl zumindest die Anzahl der Eingabeversuche begrenzen. Oder?

Um zu testen, ob die Anzahl der Eingabeversuche limitiert ist, reicht zunächst das massenhafte „einhämmern“ von falschen Codes, gefolgt von dem korrekten Bestätigungscode. Und siehe da: Nach 15 falschen Codes wurde der korrekte Code akzeptiert und ich konnte ein neues Kennwort vergeben.

Unter einem Brute-Force-Angriff versteht man das massenhafte ausprobieren aller möglichen Kombinationen, mit dem Ziel, den korrekten PIN zu „erraten“. In diesem Fall wären das alle Kombinationen von 00000 bis 99999.

Security by obscurity

Natürlich lässt sich so ein Brute-Force-Angriff schlecht über das Interface durchführen. Ein Tool musste also her, welches die 100.000 möglichen Kombinationen ausprobiert. Die Burp Suite bieten den sogenannten Intruder, welcher speziell für solche Zwecke ausgelegt ist. Das dieser hier allerdings an seine Grenzen stößt, musste ich als nächstes feststellen. Werfen wir einen Blick auf den HTTP(S)-Request zur Prüfung des Codes:

Wie man sehen kann, gibt der Server einen Fehler invalid sig zurück, nachdem der verify_code aus dem original Request verändert wurde. Scheinbar findet im Backend eine Signaturprüfung statt. Der URL-Parameter sig scheint eine Prüfsumme aus dem POST-Body zu sein.

Um dennoch einen Angriff durchführen zu können, benötigt man entweder die Logik zur Generierung der Prüfsumme oder einen Weg die Signaturprüfung zu umgehen. Spontan fällt mir da der URL-Parameter sig_by_os=1 auf. Kann man den vielleicht auf 0 setzen? Kann man, jedoch ohne Erfolg.

Es muss also die Logik zur Generierung der Prüfsumme her. Wo wirds gemacht? Natürlich im JavaScript. Die Chrome Dev Tools sind toll. Natürlich ist der komprimierte JavaScript-Code alles andere als übersichtlich, dennoch hilft in vielen Fällen SHIFT + STRG + F um die richtige JavaScript-Datei zu finden.

Leider ist es nicht gerade Einfach, die Logik hinter den verschachtelten Funktionen zu verstehen. Was jedoch in vielen Fällen hilft, ist das setzen von Debug-Punkten. Bei der Ausführung der Codestelle, hält der Debugger die Auführung des Codes an, was dazu genutzt werden kann, den Inhalt der Variablen sowie den Callstack zu sichten.

Nachdem ich die relevanten Funktionen aus dem JavaScript-Code extrahiert hatte, begann ich diese in einem Node.js-Skript zu implementieren. Natürlich benutze ich für derartige Skripte lieber Python. Der Aufwand die Funktionen in Python zu „übersetzen“ wäre jedoch nicht tragbar gewesen. Node.js hingegen kann den JavaScript-Code ohne Änderungen interpretieren.

Schlimmer geht’s immer

Während des Tests fiel mir ein weiteres Sicherheitsproblem auf: Es können mehrere Bestätigungscodes hintereinander angefordert werden. Davon bleiben alle gültig und können zum Ändern des Kennworts eingelöst werden. Bedeutet konkret: Mit jedem angeforderten Code verringert sich rein statistisch die Anzahl der Versuche bis zum Finden eines korrekten Codes. Allein das Captcha beim Anfordern eines neuen Codes verhindert die Automatisierung dieses Prozesses.

Proof of Concept

Das öffentliche Admin-Interface

Die oben genannte Brute-Force-Lücke ist natürlich nur ausnutzbar, wenn man die E-Mail-Adresse des Opfers kennt. Gibt es nicht vielleicht einen Weg auch noch an diese Info zu kommen? 🤔

Ich entschied mich die Plattform näher unter die Lupe zu nehmen. Schnell stieß ich auf einen interessanten HTTP(S)-Request, welcher beim Laden der Webseite ausgeführt wird.

console.trovo.live klingt doch interessant. Was uns wohl beim Aufrufen der Subdomain erwartet?

Und hier sehen wir eine chinesische Benutzeroberfläche. Was genau hierüber gemacht wird oder gemacht werden soll, konnte ich nicht herausfinden. Was diese Webseite jedoch massenhaft besitzt, sind API-Endpunkte. Zudem interagiert man hier als angemeldeter Benutzer unter dem Trovo-Account.

Als nächstes öffnete ich mal wieder die Dev-Tools um ein Blick in die JavaScript-Dateien zu werfen.

Diesen API-Endpunkt fand ich besonders interessant. Warum erzähle ich später. Zunächst offenbarte die JavaScript-Datei unfreiwillig ein Geheimnis über die Geschichte der Plattform. Anscheinend ist die Plattform gar nicht aus dem „Nichts“ erschienen.

Vor Trovo hieß die Plattform scheinbar Madcat und war unter madcat.tv zu finden. Ein Blick ins Webarchiv gibt Hinweise darauf. Die zerstückelte Webseite stammt aus 2018.

Auf diversen Webseite ist zu lesen, dass die Webseite zunächst Madcat genannt werden sollte, man sich dann aber für Trovo entschied. Ob die Webseite bereits 2018 bestand, lässt sich anhand den Infos aus dem Webarchiv wohl nicht beantworten.

E-Mail-Adressen frei einsehbar

Nun zum API-Endpunkt /addon/public/profile. Dieser API-Endpunkt erlaubt die Auflösung von Nutzernamen im Admin-Interface. Leider offenbart der API-Endpunkt nicht nur die User-ID sondern auch die E-Mail-Adresse.

Heißt konkret: Die oben genannte Brute-Force-Lücke harmoniert natürlich sehr gut mit dieser Lücke, da nun von jedem Nutzer die E-Mail-Adresse ermittelt werden kann, welche zum Zurücksetzen des Passworts benötigt wird.

501 – GraphQL-Authentication not implemented

Zum Zeitpunkt meiner Tests nutzte das beinahe komplette Backend GraphQL auf Websocket-Basis. Inzwischen wurde auf HTTP(S)-Requests umgestellt. Beim Laden der Seite wurde somit eine Websocket-Verbindung zu wss://gql.trovo.live/graphql hergestellt. Die erste Websocket-Nachricht kam vom Client und beinhaltete die Authentifizierung bestehend aus der Nutzer-ID und einem Token.

Mein erster Test beinhaltete eine modifizierte UID – also die eines anderen Nutzers. Erwartetes Ergebnis: Da der Token dann inkorrekt ist, wird die Websocket-Verbindung geschlossen oder einfach kein connection_ack zurückgegeben.

Erwartung != Realität

In der Realität wird jede UID akzeptiert. Aber kann man damit nun wirklich Aktionen im Namen eines anderen Nutzers ausführen? 🤔

Ich schnappte mir also ein paar GraphQL-Queries und versuchte diese auszuführen. Die ersten Tests schlugen fehl, da scheinbar wenigstens bei der konkreten Ausführung einer Aktion die Authentifizierung anhand des Tokens validiert wird. Bis ich schlussendlich ein paar „Operations“ fand, welche auch die Fake-Authentifizierung akzeptierten.

Moderator- und Ban-Management kann jeder

Unter anderem die Funktionen für das Berechtigungsmanagement waren hierfür anfällig. Voraussetzung war, dass man sich zunächst mit der Nutzer-ID des Broadcasters gegen das Websocket authentifiziert. Der Broadcaster hat bekanntlich die Rechte andere Nutzer im Chat zu bannen, sowie Moderatoren zu ernennen.

Das gleiche Prinzip konnte zum Ernennen von Chatmoderatoren angewandt werden. Man konnte somit:

  • Alle Aktivitäten der Moderatoren einsehen
  • Jeden beliebigen Nutzer bannen
  • Im Namen eines Moderators agieren
  • Moderatoren hinzufügen und entfernen

Fraglicher Umgang mit Reports

Natürlich wurden die gefundenen Schwachstellen umgehend an Trovo gemeldet. Aufgrund der hohen Relevanz der Reports entschied ich mich diese parallel sowohl per Mail als auch über die Support-Seite von Trovo zu verteilen. Die versendeten Mails sowie die Supportanfragen sind bis heute unbeantwortet. Die Brute-Force-Schwachstelle wurde zunächst nur unzureichend behoben. Anstelle einer klaren Limitierung der Versuche, lagerte man einfach die Prüfung des Codes auf den nachfolgenden HTTP(S)-Request zum Setzen des neuen Kennworts aus. Dies hatte zur Folge, dass die Abfrage des Bestätigungscodes zunächst jeden Code akzeptiert und man im Falle eines falschen Codes erst beim Setzen des neuen Kennworts darauf hingewiesen wird. Die Brute-Force-Lücke hatte man somit nur auf einen anderen API-Endpunkt umgelagert, wie das folgende Video zeigt:

Ich bohrte also nochmal nach. Diesmal versuchte ich mein Glück auf dem offiziellen Discord von Trovo. Dort sind mehrere Admins anzutreffen. Natürlich ist sowas kein Thema, welches man in #general ansprechen sollte. Also beglückte ich den ersten Admin mit einer Direktnachricht. Ein Tag später entschied sich dieser sogar mir zu antworten. Allerdings brachte mich das kein Stück weiter.

Dreht euch nicht um, der Report geht herum

Anstelle den Report einfach an die zuständige Person zu leiten, bat mich der „Admin“ diesen an eine weitere Person zu leiten. Gesagt getan, vielleicht wirds ja beim nächsten was. Der Grey-Hat-Hacker Garkolym wurde beim Reporten von ähnlichen Sicherheitslücken sogar gebeten, diese in den öffentlichen Feedback-Channel auf Discord zu posten. Scheinbar konnte man mit dem Begriff „Bug Bounty“ schlichtweg nichts anfangen.

Screenshot von @Garkolym

Tatsächlich konnte mir der nächste Mitarbeiter die Info geben, dass die Lücke bereits geschlossen wurde. Mit dem entsprechenden Video und einer kleinen Erklärung, konnte ich jedoch belegen, dass diese nicht korrekt geschlossen sondern nur „verlegt“ wurde. Man wollte sich dem Thema nun erneut widmen.

Die Entwickler implementierten in den nächsten Tagen noch einen weiteren Fix, welcher die Lücke nun scheinbar endgültig schloss. Auch die anderen Lücken bekam man in den Griff.

Ein kleines Dankeschön

Da bei 30 Millionen US-Dollar natürlich kein Platz für ein Bug Bounty vorhanden ist, wollte man mir eine kostenlose Subscription für meinen Lieblingsstreamer schenken. Da ich keinen Lieblingsstreamer auf dieser Plattform habe, lehnte ich das Angebot dankend ab und verabschiedete mich.

Fazit

Die Einblicke in das System hinter Trovo waren spannend. Denn hinter Trovo steckt nicht nur moderne Technik, sondern auch ein Team, welches anscheinend noch vieles lernen muss. Ein millionenschweres Unternehmen, welches man ausschließlich via Discord kontaktieren kann, ist mir bisher noch nie untergekommen. Wieder ein bisschen Erfahrung gesammelt. 🙂

Bounty: –

Kommentare

  1. Schöne Arbeit.
    Irgendwo kann man ja aber auch verstehen, dass bei den 30.000.000$ dann kein vernünftiges BugBounty drin war. Stell dir mal vor, sie hätten dir ganze 1.000$ gezahlt, dann wären sie ja fast pleite! Dann stände ja grob rechnerisch eine 2 ganz vorne! Das wäre ja schrecklich!
    Trotzdem schade, dass du nicht die Free-Subscription angenommen hast, vielleicht hättest du dir ja selbst Folgen können und dadurch wenigstens mit ein bisschen Gewinn raus gehen können (auch wenn es das schon aus Prinzip nicht wert wäre)…
    Jedenfalls kenne ich jetzt ein weiteres Unternehmen, bei dem ich keine Bugs melden werde.

    Bewertung zum Artikel: 4/5 Sternen, weil die Einschlafgeschichte kein Happy-End hatte. Schade eigentlich.

Schreibe einen Kommentar

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