github twitter email
Schwachstelle in COVID-19 App
Apr 1, 2020
5 minutes read

Über die App

Am 21.03.20 wurde die COVID-19 Patienten-App im App Store und Play Store veröffentlicht. Die offizielle Beschreibung lautet: “Über die COVID-19 Patienten-App werden Patienten, die auf COVID-19 untersucht wurden, in Echtzeit über ihr Testergebnis informiert. Sobald der Befund verfügbar ist, erhält der Patient eine Push-Notification und kann das Ergebnis in der App einsehen” (Quelle). Patienten erhalten von ihrer Arztpraxis einen QR-Code (bzw. ID-Nummer) und können so auf die Ergebnisse mithilfe der App zugreifen. Die App ist eine gemeinsame Entwicklung der Telekom und BS Software Development.

Überprüfung & Schwachstelle

Also startete ich das Remote Virtual Interface Tool, dass es erlaubt Datenpaket von iOS Geräten mitzuschneiden: sudo rvictl -s [Identifier meines iPhones]. Anschließend startete ich den Paketmitschnitt in Wireshark auf dem neu erstellten Interface rvi0 und gab eine fiktive ID-Nummer in der App ein. Etwas überrascht stellte ich fest, dass für den Transport der Daten TLSv1 verwendet wurde. Gerade aufgrund der Tatsache, dass es sich um eine medizinische Anwendung handelt, wurde ich skeptisch. Wireshark Ein kurzer Blick auf den SSL Report von SSL Labs bestätige den Verdacht: Das genutzte Zertifikat war selbstsigniert, abgelaufen und ohne Domaineintrag, der Server unterstützt ausschließlich TLS 1.0 sowie veraltete und als unsicher geltende Cipher Suites. SSL Labs Report Also richtete ich Burp Suite als Proxy meines iPhones ein - ohne die Burp Suite Root CA zu installieren - und gab erneut eine ID-Nummer ein: Tatsächlich wurden die Daten anstandslos übertragen, obwohl der App gerade ein durch Burp Suite signiertes Zertifikat präsentiert wurde. Offensichtlich wurde das Zertifikat nicht gepinnt bzw. überprüft, sodass die App jedes beliebige für den Transport akzeptiert.

Dies ermöglicht das Ausspähen & Manipulieren des Datenverkehrs für einen Angreifer mit Zugriff auf den Datenverkehr.

Die eigentliche Prüfung, ob die eingegebene ID-Nummer gültig ist, fand per HTTP Basic Auth statt: Base64-codiert wurden ID-Nummer, Geräte-ID, das Standardpasswort COVID_STANDARDPASSWORT und einige andere Daten über die vermeintlich sichere Verbindung an den Server versandt.

Nachfolgend der Mitschnitt einer Anfrage mit ID-Nummer 123456789 aus App Version 1.1.0:

GET /datasnap/rest/DSAdmin/GetPlatformName/ HTTP/1.1
Host: 80.158.3.72
Content-Type: text/plain;charset=UTF-8
Connection: close
Accept: application/JSON
If-Modified-Since: Mon, 1 Oct 1990 05:00:00 GMT
User-Agent: Embarcadero URI Client/1.0
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Authorization: Basic UUNfQ09NTVVOSUNBVE9SMTIzNDU2Nzg5OnsidXNlck5hbWUiOiIxMjM0NTY3ODkiLCJwYXNzd29yZCI6IkNPVklEX1NUQU5EQVJEUEFTU1dPUlQiLCJkZXZpY2VJRCI6IjZiMDkyZmEyZGI1MGMzNzNlOWRmYmVkMWJkYmU5N2Y2NDYyYWU1NjQzYWNlNDNiNmM5ZGUzMTUwOGMwMWI1YmMiLCJjbGllbnRWZXJzaW9uIjoiNDFfMjAwMzI3IiwibG9naW5SZXF1ZXN0IjoiTFJfTG9naW4iLCJkZXZpY2VDb21tZW50IjoiMTIzNDU2Nzg5IiwiYW53ZW5kdW5nR1VJRCI6InsxNzZENzIyMy05RTIwLTQ1RjQtQkNDMi0yRDk1QUE4QTcyRkR9IiwicmVnaXN0ZXJEZXZpY2VJZk5vdEtub3duIjp0cnVlLCJ1c2VUb3VjaCI6ZmFsc2UsInNhdmVMb2dpbiI6ZmFsc2UsImRldmljZUdVSURPbGQiOiI2YjA5MmZhMmRiNTBjMzczZTlkZmJlZDFiZGJlOTdmNjQ2MmFlNTY0M2FjZTQzYjZjOWRlMzE1MDhjMDFiNWJjIiwiYmV0cmllYnNzeXN0ZW0iOiJJT1MiLCJuZXdVc2VyTmFtZSI6IiIsIm5ld1VzZXJNYWlsIjoiIiwibmV3VXNlclBob25lIjoiIiwibmV3VXNlckZpZWxkMSI6IiIsIm5ld1VzZXJGaWVsZDIiOiIiLCJuZXdVc2VyRmllbGQzIjoiIiwib25lVGltZVRva2VuIjoiIiwiZUVOUiI6IiIsInB1c2hzQWxsb3dlZCI6ZmFsc2V9

Decodiert man den HTTP-Header Authorization mit Base64 ist die eingegebene ID-Nummer mehrfach lesbar:

QC_COMMUNICATOR123456789:{"userName":"123456789","password":"COVID_STANDARDPASSWORT","deviceID":"6b092fa2db50c373e9dfbed1bdbe97f6462ae5643ace43b6c9de31508c01b5bc","clientVersion":"41_200327","loginRequest":"LR_Login","deviceComment":"123456789","anwendungGUID":"{176D7223-9E20-45F4-BCC2-2D95AA8A72FD}","registerDeviceIfNotKnown":true,"useTouch":false,"saveLogin":false,"deviceGUIDOld":"6b092fa2db50c373e9dfbed1bdbe97f6462ae5643ace43b6c9de31508c01b5bc","betriebssystem":"IOS","newUserName":"","newUserMail":"","newUserPhone":"","newUserField1":"","newUserField2":"","newUserField3":"","oneTimeToken":"","eENR":"","pushsAllowed":false}

In der Anwort wird dann, neben der Information, dass das System auf win32 läuft, eine Session-ID dssession gesetzt, die bei weiteren Anfragen zur Authentifizierung dient.

HTTP/1.1 200 OK
Connection: close
Content-Type: application/json
Content-Length: 20
Date: Tue, 31 Mar 2020 22:29:38 GMT
Pragma: dssession=998046.584957.599223,dssessionexpires=49999969
Server: DatasnapHTTPService/2011

{"result":["win32"]}

Demonstration im Video

Update

Ab Version 1.1.1 wurde dann eine lokale Syntaxprüfung des Code implementiert. Mit den Demo-Codes konnte die Untersuchung allerdings fortgesetzt werden. Ferner wurden serverseitige Änderungen vorgenommen.

Beispiel mit Demo-Code 2203-7E12D1A5-B4C9-457E-A45B-AA4825CCB69B am 01.04.2020:

QC_COMMUNICATOR2203-7E12D1A5-B4C9-457E-A45B-AA4825CCB69B:{"userName":"2203-7E12D1A5-B4C9-457E-A45B-AA4825CCB69B","password":"COVID_STANDARDPASSWORT","deviceID":"6b092fa2db50c373e9dfbed1bdbe97f6462ae5643ace43b6c9de31508c01b5bc","clientVersion":"41_200331","loginRequest":"LR_Login","deviceComment":"2203-7E12D1A5-B4C9-457E-A45B-AA4825CCB69B","anwendungGUID":"{176D7223-9E20-45F4-BCC2-2D95AA8A72FD}","registerDeviceIfNotKnown":true,"useTouch":false,"saveLogin":false,"deviceGUIDOld":"6b092fa2db50c373e9dfbed1bdbe97f6462ae5643ace43b6c9de31508c01b5bc","betriebssystem":"IOS","newUserName":"","newUserMail":"","newUserPhone":"","newUserField1":"","newUserField2":"","newUserField3":"","oneTimeToken":"","eENR":"","pushsAllowed":false,"privacyPolicyAccepted":true,"useRandomKey":true,"clientCert":""}

Außerdem fällt auf, dass einige neue Parameter - darunter useRandomKey hinzugefügt wurde. In der darauf folgenden Anfrage werden User-ID, eine weitere Session-ID sowie ein Schlüssel übertragen, der, nachdem deverlängert wurde. Außerdem scheint dieser nun zufällig generiert zu werden, während dieser vorher immer AVIFMNLC122R2X2HU202ULN0022THJDL betrug.

GET /datasnap/rest/TFFunctionsDatabase/apiGetSessionInfo/DMasdNDjd$dasxFnndMDFASMS/ HTTP/1.1
Host: 80.158.3.72
Content-Type: text/plain;charset=UTF-8
Pragma: dssession=998046.584957.599223
Accept: application/JSON
If-Modified-Since: Mon, 1 Oct 1990 05:00:00 GMT
User-Agent: Embarcadero URI Client/1.0
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: close
[...]
{"result":[{"SESSIONID":"1789","KEY":"Y0RKVFFnTnJKc1haS1dHZThtQzA1ZEkvMVlpeW0yek5nSjkwOVlWUmhSYTh5WHp6bXRJbElmVWRp\r\nY3BXUE9rTHRKbjJiV2swMWk4blA3eUpRTGsvOVE9PQ==","RIGHTS":"{\"UserState\":\"3\",\"UserID\":\"1789\",\"DeviceState\":\"4\",\"DeviceID\":\"0\",\"UserQuestion\":\"\",\"UserAnswer\":\"\",\"Kategorie\":\"\",\"Anzeigename\":\"\",\"Benutzerrechte\":[],\"Geraeterechte\":[],\"Gruppen\":[]}"}]}

Werden mehrere Anfragen mit verschlüsseltem Inhalt an den Server gestellt, auf die der Server zum aktuellen Zeitpunkt aber nicht antwortet (500 Internal Server Error).

GET /datasnap/rest/TFFunctionsDatabase/apiGetDB/communicator/tzb%2BjBBfdD%2Bn2eIQl1oyXKFw72Fm%2F8Dy8dTFpmDx1G3w%2BUqOusWbb0tFa6C0UQGmaXJiOvxuUDdeQYnqD80OQJnGCR2peOjs3aHUsKshkRlgjdYxtzMwjjJPL5bvUiv4oq8HOJZwh5D95Upz2NqqbLJp6fZgSC8%2Bh6KfIUjAjsQ=/ HTTP/1.1
Host: 80.158.3.72
Content-Type: text/plain;charset=UTF-8
Pragma: dssession=762704.758902.473935
Accept: application/JSON
If-Modified-Since: Mon, 1 Oct 1990 05:00:00 GMT
User-Agent: Embarcadero URI Client/1.0
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: close

Anfällig für diese Schwachstelle sind Versionen der COVID-19 App kleiner oder gleich Version 1.1.2 (iOS) vom 01.04.2020 bzw. 4120.3.30 (Android) vom 31.03.2020.

Lösung

Zum aktuellen Zeitpunkt (01.04.2020, 13:00 Uhr) ist kein Update für die App verfügbar. Der Hersteller habe aber bereits eine neue Version im App Store und Play Store eingereicht und betroffenen Versionen sei der Zugriff auf den Server entzogen worden (vgl. c’t deckt auf: Corona-App der Telekom ist katastrophal unsicher).

Update vom 01.04.2020

Im Google Play Store ist nun (~18:00 Uhr) Version 4120.3.32 erschienen, mit dem Zugriff auf den Server wieder möglich ist und die genannten Sicherheitsmängel behebt. Es ist nicht länger möglich, ein selbstsigniertes Zertifikat zu verwenden. Für iOS ist bisher noch kein Update verfügbar. Bei niedrigere Versionen erscheint eine Fehlermeldung, wobei die ID-Nummer trotzdem unsicher übertragen wird. Im App Store ist nun (~23:03 Uhr) Version 1.1.2 erschienen, in der weiterhin die Nutzung mit einem selbstsignierten Zertifikat möglich ist.

Update vom 02.04.2020

Ebenfalls konnte ich in einem netten Telefonat mit dem Geschäftsführer von BS Software Development Einblicke in den Entwicklungsprozess erhalten und mich davon überzeugen, dass mit Hochdruck an der Schließung der Lücke gearbeitet werde. Außerdem erschien gegen 18:30 Uhr ein Update für iOS (Version 1.1.3), mit dem nun die Gültigkeit des Zertifikats überprüft wird, sodass die App nun nicht mehr selbstsignierten Zertifikaten vertraut. Aufgrund des fehlenden Certificate- bzw. Public Key-Pinnings lassen sich weiterhin Zertifikate, die durch Burp Suites Root-CA ausgestellt wurden und vertraut werden, unter iOS einspielen.

Datum Status
31.03.2020 12:24 Uhr Meldung an Heise c’t
31.03.2020 13:59 Uhr Erster Kontakt durch Herrn Eikenberg
31.03.2020 18:09 Uhr Herr Eikenberg bestätigt, dass Telekom und Entwicklerfirma informiert sind
31.03.2020 ~20:30 Uhr Durch Let´s Encrypt ausgestelltes Zertifikat ist aktiv
31.03.2020 ~22:00 Uhr TLS 1.0 deaktiviert & TLS 1.2 aktiviert
01.04.2020 ~18:00 Uhr RC4 deaktiviert & Forward Secrecy aktiviert (siehe SSL Report), Update (4120.3.32) im Play Store verfügbar
01.04.2020 ~23:30 Uhr Update (1.1.2) im App Store verfügbar
02.04.2020 ~18:30 Uhr Update (1.1.3) im App Store verfügbar

Vielen Dank an c’t, die die Kommunikation mit Deutsche Telekom und BS Software Development übernommen haben und einen Artikel hierzu veröffentlichten sowie das Geschehen in Ausgabe 09/2020 erläuterten! Außerdem lobe ich ausgesprochen schnelle Reaktion auf der Schwachstelle durch den Hersteller.


Back to posts