Zum hauptinhalt springen

zerforschung

Learnu oder: Meine App, die hat drei LĂŒcken đŸŽ¶

Dieser Artikel ist der zweite Teil der “Back-To-School-Serie”.

Hausaufgaben – ein leidiges Thema, das so ziemlich alle in sehr schlechter Erinnerung haben oder noch alltĂ€glich ertragen mĂŒssen. Viele SchĂŒler*innen versuchen deshalb, möglichst wenige davon zu machen und die Hausaufgaben solidarisch untereinander zu teilen. Doch was alles schief gehen kann, wenn man versucht, daraus ein GeschĂ€ftsmodell zu machen, das zeigen wir euch jetzt.

Die GrĂŒnder*innen unserer heutigen App wollten aus dem Teilen von Hausaufgaben ein Startup machen und haben sich eine Marktplatz-App fĂŒr Hausaufgaben ausgedacht: learnu1.

Learnu will alle SchĂŒler*innen glĂŒcklich machen: Die einen mĂŒssen keine Hausaufgaben mehr machen, sondern können sie in der App einkaufen. Bezahlen können sie entweder mit echtem Geld (5€ im Monat fĂŒr Zugang zu allen Aufgaben) – oder mit ihrer Zeit und Werbung gucken.

Und die anderen können, wenn sie sich sowieso schon an den Schreibtisch setzten, Geld damit verdienen. FĂŒr hochgeladene Hausaufgaben gibt es In-App-Credits (“Learnus”), die gegen Gutscheine eingetauscht werden können.

Von kein Plan zu kaputter App

Kurz nach dem eigenen Abi, zum Start des Studiums 2020, haben die GrĂŒnder*innen die Idee dann umgesetzt. Und das kam gut an – die App wurde von mehr als 500.000 SchĂŒler*innen genutzt.

Doch wie sie selbst zugeben, kannten sich die GrĂŒnder*innen nicht gut genug mit App-Entwicklung aus und haben die App deshalb entwickeln lassen. Sie selbst haben also die SicherheitslĂŒcken, die wir hier beschreiben, gar nicht fabriziert – aber sie haben andere mit der Entwicklung beauftragt, ohne die Code-QualitĂ€t selbst prĂŒfen zu können. Und das kaputte Ergebnis dann an SchĂŒler*innen verkauft.

Denn leider wurde die App technisch so schlecht umgesetzt, dass am Ende die Daten von rund 500.000 Accounts öffentlich zugÀnglich waren. Dazu gehören:

  • Vor- und Nachname, die bei der Registrierung als Klarname abgefragt werden
  • Username innerhalb der App
  • E-Mail-Adresse
  • Stadt und Schule
  • alle gestellten Fragen
  • alle abgerufenen Antworten

Doch bevor wir das entdeckten, mussten wir uns die App erstmal genau anschauen.

đŸ•”

Dazu haben wir uns, wie immer, erstmal die App installiert und einen Machine-in-the-Middle-Proxy eingerichtet. Mit diesem können wir den Datenverkehr zwischen App und Server mitlesen. Dazu schaltet sich der Proxy dazwischen und behauptet jeweils, die entsprechende Gegenstelle zu sein.

Schaubild wie eine App auf unserem Smartphone mit einem Proxy auf unserem Computer und dieser mit dem Server kommuniziert

Um sicherzustellen, dass ein Angreifer so etwas nicht machen kann, ĂŒberprĂŒft eine App, dass der Server ein gĂŒltiges Zertifikat hat, sich also ausweisen kann.

Normalerweise fragt eine App dazu das Betriebssystem, ob dieses Zertifikat gĂŒltig ist. Das Betriebssystem hat eine lange Liste von Stellen, die gĂŒltige Zertifikate ausstellen dĂŒrfen2 und schaut, ob das Zertifikat von einer Stelle auf dieser Liste ausgestellt wurde.

Das ist fĂŒr uns super, denn dann können wir uns selbst auf diese Liste schreiben. Damit vertraut unser Handy dann auch allen Zertifikaten, die wir selbst ausgestellt haben.

Die Learnu-App ist jedoch mit dem Framework Flutter entwickelt worden. Flutter greift nicht auf die Liste des Betriebssystems zurĂŒck, sondern bringt eine eigene mit. Das liegt vor allem daran, dass Flutter-Apps auf verschiedenen Betriebssystemen funktionieren sollen, aber jedes Betriebssystem einen anderen Weg hat, die Liste mit den Zertifikaten abzufragen. Also ist es einfacher, eine eigene Liste mitzubringen, als fĂŒr jedes Betriebssystem eine andere Abfrage zu implementieren.

Das klingt erstmal gut, stellt uns jedoch vor ein Problem: Wir können nicht unser Test-Handy nutzen, wo wir uns bereits auf die Liste gesetzt haben, sondern mĂŒssen die Liste in der Learnu-App selbst anpassen. Das ist nichts, was uns dauerhaft abhalten kann, aber erschwert unsere Arbeit kurzfristig.

Let’s get binary

Daher schauen wir uns erstmal den Code der App genauer an. Der ist natĂŒrlich nicht öffentlich einsehbar. Deshalb mĂŒssen wir die App auf den Computer herunterladen, sie dekompilieren und können dann den BinĂ€rcode anschauen. Dort haben wir erstmal wild rumgestochert und schnell diese Stelle gefunden:

Screenshot des BinĂ€rcode, mit einem Texteditor geöffnet – markiert ist der String “admin.learnuapp.net/api”

Wenn irgendwo “Admin” steht, klingt das fĂŒr uns natĂŒrlich direkt spannend – und wir öffnen die Webseite im Browser, wo wir direkt auf https://admin.learnuapp.net/login weitergeleitet werden. Ein Hoffnungsschimmer, dass wir hier nicht weiterkommen: Die Zugangsdaten unseres Accounts aus der App funktionieren schonmal nicht.

Learnu, öffne dich

Aber aus Erfahrung wissen wir auch: Wenn es die Unterseite /login gibt, dann gibt es sehr wahrscheinlich auch die Unterseite /register. Und zack – wir sind auf dem Registrierungsformular fĂŒr neue Accounts. Hmmm, vielleicht können wir uns da ja einen Admin-Account anlegen? AusgefĂŒllt und abgesendet 
 uuuund fehlgeschlagen. Immerhin. Doch die Fehlerseite ist sehr detailiert:

Screenshot der Fehlerseite, auf der alle Variablen dargestellt werden u.A. das Datenbank-Passwort

Die Fehlermeldung kommt vom PHP-Framework Laravel, mit dem die API programmiert wurde. Und diese Fehlermeldung zeigt uns alle Konfigurations-Variablen an – also unter anderem die Zugangsdaten zur Datenbank.

🚧 Achtung, Baustelle 🚧

Doch warum sehen wir all das? Nun, Learnu hat ihre Website im Debug-Modus gelassen. Dies ist ein spezieller Modus, der die Entwicklung erleichtert – unter anderem, indem sehr ausfĂŒhrliche Fehlermeldungen angezeigt werden.

Deshalb sollte der Debug-Modus aber auf keinen Fall im normalen Betrieb aktiviert sein. Sonst kann nĂ€mlich genau das passieren: Unbefugte bekommen ausfĂŒhrliche Fehlermeldungen zu sehen. Die Laravel-Dokumentation warnt sogar extra davor:

For local development, you should set the APP_DEBUG environment variable to true. In your production environment, this value should always be false. If the variable is set to true in production, you risk exposing sensitive configuration values to your application’s end users.

Doch diese Warnung hat Learnu wohl nicht gesehen oder ignoriert.

🎭

Die auf der Fehlerseite sichtbaren Datenbank-Zugangsdaten brachten uns zum GlĂŒck nicht viel, da die Datenbank nicht öffentlich erreichbar ist. Allerdings steht in der Fehlermeldung auch das JWT_SECRET, also ein geheimer Code, mit dem wir unbeschrĂ€nkt und beliebig Authentifizierungs-SchlĂŒssel generieren können. Mit diesen SchlĂŒsseln können wir uns als jede*r beliebige Nutzer*in ausgeben – und der Server glaubt uns, weil wir ja einen korrekten Authentifizierungs-SchlĂŒssel haben3.

🚹 “Fahrzeugpapiere und API-Dokumentation, bitte.”

Wir können uns jetzt also als jeder beliebige User ausgeben – wir wissen aber noch nicht, wie man mit der Programmierschnittstelle (API) des Servers kommuniziert. Doch nach etwas Raten landen wir auf “https://admin.learnuapp.net/docs”. Dort findet sich eine Dokumentation, wie die API funktioniert. Vermutlich liegt diese dort fĂŒr die Entwickler*innen, um im Zweifelsfall schnell nachgucken zu können.4 Und auch wir freuen uns, so eine API-Dokumentation zu haben. Denn so haben wir schnell einen Überblick, wie diese funktioniert und können anfangen, die API auszuprobieren.

Unsere erste Anlaufstelle war, wie auch schon bei Scoolio, der Profil-Endpunkt unter https://admin.learnuapp.net/api/users/{USER_ID}/profile. Leider entdeckten wir hier schon das erste Problem, denn die Antwort sieht in etwa so aus (diese hier haben wir uns natĂŒrlich ausgedacht):

{
  "status": true,
  "message": "User profile received successfully.",
  "data": {
    "id": 91213,
    "fullname": "Anna Maier",
    "username": "Anna",
    "email": "anna.maier.1312@gmail.com",
    "created_date": "2021-01-12 13:12:13",
    "modified_date": "2021-03-11 13:12:13",
    "biography": "đŸłïžâ€đŸŒˆ",
    "city_id": "db21a7bf-60bc-4070-89c6-ba1d12605b01",
    "school_id": "ebf94c15-bbc1-4d48-9dae-2452516dc277",
    "avatar": null,
    "subscribers_count": 2,
    "subscriptions_count": 0,
    "is_subscribed": false
  }
}

Die Nutzer*innen-Accounts bei Learnu sind aufsteigend durchnummeriert, wie wir es schon von unzÀhligen anderen Apps kennen. Aber ist es nicht möglich, beliebig viele Profile auf einmal abzurufen, denn es gibt eine Abruflimitierung von einem Profil pro Sekunde. Allerdings entdecken wir in der Doku auch noch einen Such-Endpunkt, der zu jeder 3-stelligen Buchstabenkombination alle passenden Profile ausgibt. Suchen wir zum Beispiel nach ann (https://admin.learnuapp.net/api/users/search/list?username=ann), sieht die Antwort in etwa so aus:

{
  "status": true,
  "message": "Search list of users received successfully.",
  "data": [
    {
      "id": 91213,
      "fullname": "Anna Maier",
      "username": "Anna",
      "email": "anna.maier.1312@gmail.com",
      "is_premium": 0,
      "is_active": 1,
      "created_date": "2021-01-12 13:12:13",
      "modified_date": "2021-03-11 13:12:13",
      "content_count": 0,
      "forum_count": 0,
      "earnings_count": 0,
      "biography": "đŸłïžâ€đŸŒˆ",
      "city_id": "db21a7bf-60bc-4070-89c6-ba1d12605b01",
      "school_id": "ebf94c15-bbc1-4d48-9dae-2452516dc277",
      "avatar": null
    },
    {
      "id": 23420,
      "fullname": "Anna-Marie MĂŒller",
      "username": "Anna2",
      "email": "anna.marie.2342@hotmail.com",
      "is_premium": 0,
      "is_active": 1,
      "created_date": "2021-01-12 13:12:13",
      "modified_date": "2021-03-11 13:12:13",
      "content_count": 0,
      "forum_count": 0,
      "earnings_count": 0,
      "biography": "homework is for me? đŸ„ș👉👈",
      "city_id": "db21a7bf-60bc-4070-89c6-ba1d12605b01",
      "school_id": "ebf94c15-bbc1-4d48-9dae-2452516dc277",
      "avatar": null
    },
    

  ]
}

Da wir auch eine Suche pro Sekunde durchfĂŒhren können, bedeutet das: Um die halbe Million DatensĂ€tze herunterzuladen, brĂ€uchten wir nicht 500.000 Sekunden (etwa 6 Tage), sondern nur noch etwa 18.0005 Sekunden, also 5 Stunden.

Open Source wider Willen

Nun können wir alle Profile abrufen und uns als beliebige andere Personen ausgeben, mehr als genug um es zu melden. Also geht das ĂŒbliche Prozedere los: Wir schreiben unseren Report, um ihn dann an das CERT-Bund beim BSI, den Hersteller und die zustĂ€ndige Landesdatenschutzbehörde zu schicken.

Doch nachdem die Website bereits schlecht konfiguriert und noch im Entwicklungsmodus ist, haben wir den Verdacht, dass vielleicht noch mehr Dinge falsch konfiguriert sind.

Wir vermuten also, dass vielleicht die .git/index-Datei öffentlich abrufbar sein könnte. Das ist eine interne Datei des Versionskontrollsystems, das fĂŒr die Entwicklung von Learnu genutzt wurde. Darin stehen alle Dateien, die die Entwickler*innen mit git verwalten, also (fast) alle Quelltextdateien des Learnu-Servers. Das ist eine altbekannte SicherheitslĂŒcke und es empfiehlt sich, den .git/-Ordner nicht öffentlich zugĂ€nglich zu machen6.

FĂŒr uns ist das sehr nĂŒtzlich: So wissen wir nĂ€mlich, welche anderen Code-Dateien es auf dem Webserver gibt, zum Beispiel die Datei https://admin.learnu.net/config/mail.php. Die können wir natĂŒrlich auch abrufen, denn auch dieser Teil war falsch konfiguriert.7 Darin befanden sich Zugangsdaten zu einem Anbieter, ĂŒber den learnu Mails versendet hat. Da auch der Code mit Konfigurationsdateien definitiv nicht von außen zugĂ€nglich sein sollte, mĂŒssen wir also den Report nochmal ergĂ€nzen und schicken ihn endgĂŒltig ab.

Fazit

Obwohl die Datenbank diesmal also nicht aus dem Internet erreichbar war, kamen wir trotzdem an alle Daten. Deshalb: Konfiguriert eure Webserver ordentlich. Gebt nur Dateien aus, die auch ausgegeben werden sollen, also weder PHP-Files noch den .git Ordner noch die Konfiguration des Webservers selbst. Lasst eure Web-Frameworks nicht im Entwicklungsmodus laufen. Und stellt – verdammt nochmal – nur die personenbezogenen Daten ĂŒber die Programmierschnittstelle bereit, die die App auch wirklich braucht!

Pulling the plug 🔌

Immerhin: Nachdem wir wiederholt nachfragten und teilweise im 15-Minuten-Takt anriefen, ist die Plattform mittlerweile offline – und bleibt das nach Aussage der beiden GrĂŒnder auch. Wir beglĂŒckwĂŒnschen die GrĂŒnder von Learnu zu der Erkenntnis, dass es besser ist, die App nicht weiterzubetreiben und zur Entscheidung, die App dauerhaft offline zu lassen. Damit haben sie ihre Datenschutzprobleme konsequenter und dauerhafter gelöst als manch andere.

Doch Fakt ist: Die App ist mit den Daten ihrer Nutzer*innen extrem nachlĂ€ssig umgegangen. Wenn die GrĂŒnder in ihrem Podcast lapidar sagen “Who cares – es war eine super Erfahrung” – mĂŒssen wir antworten: Wir caren! Und wir finden es unverantwortlich und frech, mit den Daten von SchĂŒler*innen zu spielen, nur um das Ego zu pushen.

Die Learnu-GrĂŒnder*innen hingegen finden ihr Vorgehen sogar so geil, dass sie ein eigenes “Startup Programm fĂŒr SchĂŒler*innen” namens YoungUp gestartet haben. Dort kann man dann “in verschiedensten Bereichen Erfahrung sammeln und Verantwortung ĂŒbernehmen.” Wir hĂ€tten uns ja gewĂŒnscht, dass die beiden Verantwortung fĂŒr die Daten ihrer Kund*innen ĂŒbernommen hĂ€tten.

Dass es so weit gekommen ist, liegt aber nicht nur an den beiden, sondern ist Ergebnis eines kaputten Systems. Das entschuldigt zwar das Verhalten der beiden nicht, aber so werden auch einige grĂ¶ĂŸere Probleme sichtbar:

Liberallala

Das erste Problem ist das gesellschaftliche DrĂ€ngen auf einen lĂŒckenlosen und möglichst aufpolierten Lebenslauf: Abi und Auslandsaufenthalt gelten als erstrebenswert – und am besten noch möglichst frĂŒh ein eigenes Startup grĂŒnden.

Nicht falsch verstehen: Mit einer guten Idee (und dem entsprechenden fachlichen Background) kann es super cool sein, etwas zu grĂŒnden! Dabei kann man viel lernen – und sogar einen positiven Beitrag fĂŒr die Gesellschaft leisten.

Doch wer sein eigenes “Business” nur um des “Business” und des Lebenslaufs willen grĂŒnden will, sollte sich das gut ĂŒberlegen – vor allem, wenn es dabei um die Daten fremder Leute geht. Denn dann ist das nicht mehr nur eine nette Spielerei, bei der man auch mal Fehler machen darf, um daraus zu lernen – hier geht es um ein echtes Risiko fĂŒr die betroffenen Nutzer*innen.

Aber ich bin doch klein, ich brauche keinen Datenschutz đŸ„ș

Hier kommen wir zum zweiten Problem: Viele Startups denken, die Spielregeln gelten fĂŒr sie nicht. Schon scoolio hat uns erzĂ€hlt, dass sie als Startup nicht die Möglichkeit hĂ€tten, sichere Software zu bauen. Dabei ist sichere Software und Datenschutz keine nette Zugabe, die man vielleicht mal einbauen kann, wenn gerade Geld und Zeit ĂŒbrig sind — und seien wir ehrlich, das sind sie nie. Denn die DSGVO gilt auch fĂŒr Startups. Wenn ein Produkt reif genug ist, um Kund*innen-Daten speichern zu können, dann muss es auch reif genug sein, diese fĂŒr sich zu behalten.

Nach uns die Sintflut

Ein drittes Problem: Die Konsequenzen fĂŒr andere werden ignoriert. Denn wenn die GrĂŒnder von ihrem Vorbild Mark Zuckerberg und dessen Ignoranz (“The biggest risk you can take is not taking any risks”) schwĂ€rmen, mĂŒssen wir fragen, ob das die richtigen Vorbilder sind. Wenn das Vorbild ein Unternehmen ist, das wissentlich Nutzer*innen manipuliert, Hass und Hetze schĂŒrt und vieles mehr, dann braucht man sich nicht wundern, wenn ihnen der Schutz der persönlichen Daten anderer egal ist.

Wann immer es um “digitale Innovation” geht, muss klar sein: Nur weil etwas digital ist, ist es nicht automatisch gut. Unsere Gesellschaft muss dringend lernen, neue Apps oder Plattformen nicht blind zu bejubeln – sondern sie zu hinterfragen und zu prĂŒfen. Trotzdem ist auch klar: Diese Aufgabe kann nicht bei den einzelnen Nutzer*innen liegen.

👀

Deshalb ist das vierte Problem: Fehlende Kontrolle durch die zustÀndigen Stellen.

Durch die DSGVO gibt es eine grĂ¶ĂŸtenteils sehr gute Rechtsgrundlage fĂŒr Datenschutz. Diese muss aber auch durchgesetzt werden. Unsere Zusammenarbeit mit den Datenschutzbehörden ist stets sehr gut gewesen, aber diese fangen oft erst an zu arbeiten, nachdem wir (und andere) von extern die Probleme gefunden und an sie herangetragen haben.

Und um das zu Ă€ndern braucht es mehr Leute, Ressourcen und Kompetenzen in den Datenschutzbehörden. Diese mĂŒssen endlich auch von sich aus nach solchen Problemen Ausschau halten und bei VerstĂ¶ĂŸen empfindliche Strafen verhĂ€ngen können.

Timeline

  • 2021-10-18 – Meldung an CERT-Bund, LDI NRW und Learnu
  • 2021-10-20 – Aufgrund ausgebliebener Reaktion: nochmalige Nachfrage des CERT-Bund bei Learnu
  • 2021-10-20 ab 12:30 Uhr – mehrere Anrufversuche bei Learnu
  • 2021-10-20 13:53 Uhr – Learnu bestĂ€tigt die gemeldeten LĂŒcken zu ĂŒberprĂŒfen
  • 2021-10-20 ~23 Uhr – bei routinemĂ€ĂŸiger ÜberprĂŒfung stellen wir fest, dass Learnu offline ist
  • 2021-10-29 – Nachfrage des CERT-Bund bei uns ob die LĂŒcken geschlossen wurden, da keine weitere Reaktion von Learnu
  • 2021-10-29 15:09 Uhr – letzte Fristsetzung fĂŒr Learnu unsererseits, zum 03.11.2021 12:00 UTC
  • 2021-10-29 – Telefonat mit Learnu, BestĂ€tigung dass Learnu offline bleibt
  • 2021-11-11 – Veröffentlichung dieses Blogposts

Wenn ihr zerforschung unterstĂŒtzen wollt, findet ihr hier Möglichkeiten: https://zerforschung.org/unterstuetzen/

Titelbild basierend auf “France in XXI Century - Future School” aus der Bilderreihe En L’An 2000.

Das Bild enthÀlt folgende Creative Commons lizensierten Werke:


  1. Der Name setzt sich laut den GrĂŒnder*innen aus den Begriffen “lernen” (“learn”), “verdienen” (“earn”) und “du” (“u”) zusammen. đŸ€Ą ↩︎

  2. Liste der standardmĂ€ĂŸig vertrauten Zertifizierungsstellen in Windows und iOS / macOS ↩︎

  3. Die Authentifizierungs-SchlĂŒssel hier sind natĂŒrlich JSON-Web-Tokens, die wir jetzt mit dem Secret signieren und validieren können. ↩︎

  4. Das ist auch eigentlich gar kein Problem, wenn die API ausreichend geschĂŒtzt ist. Und wenn die API nicht genug geschĂŒtzt ist, dann ist Security by Obscurity auch keine Lösung. ↩︎

  5. 26 hoch 3 = 17576 ↩︎

  6. https://en.internetwache.org/dont-publicly-expose-git-or-how-we-downloaded-your-websites-sourcecode-an-analysis-of-alexas-1m-28-07-2015/ ↩︎

  7. PHP ist eine interpretierte Sprache, das bedeutet, dass der Server beim Abruf der Seite den Code ausfĂŒhrt und nur das Ergebnis an den Browser liefert. DafĂŒr muss der Webserver allerdings so konfiguriert sein, dass .php Dateien an den PHP-Interpreter ĂŒbergeben werden statt sie direkt auszuliefern. ↩︎