Die smarte Fabrik hat viele Eintrittstore für Hacker, erst aus Fehlern zu lernen kann fatal sein und ganze Produktionen gefährden. Ein starker Eigenschutz der Shopfloor-Software über Embedded Runtime Integrity-Technologie kann Cyberangriffe unmöglich oder zumindest weniger gefährlich machen.
Die Zahl der veröffentlichten Schwachstellen und Angriffe auf IIoT Geräte ist 2021 wieder stark angestiegen, zuletzt sorgte die Open Source-Schwachstelle Log4j auch in der Industrie für Aufregung. Neben den Angriffen selbst ist auch das wachsende Bewusstsein für Cybersicherheit ein Grund für den realen und gefühlten Anstieg. Forscher sowie Systemanbieter betreiben mehr Aufwand, um IoT-Geräte zu schützen und betreiben verstärkt Penetrationstests, um zielgerichtet Schwachstellen aufzudecken und zu veröffentlichen.
Dezidiert im industriellen Umfeld wurde Ripple/20 bekannt, eine Zusammenfassung von 19 DNS-Schwachstellen in mehreren IP-Stacks, die Dutzende von Endprodukten betreffen und von JSOF-Forschern im Juni 2020 entdeckt und veröffentlicht wurden. Ein weiteres Beispiel ist Amnesia:33 – 33 Schwachstellen in vier verschiedenen TCP/IP-Stacks wurden von Forescout-Forschern im Dezember 2020 veröffentlicht [1].
Doch was kann bereits im Vorfeld gegen Schwachstellen und deren teure Folgen getan werden? Zum einen müssen IIoT-Entwickler bereits vor der Produktion bzw. Implementierung Fehler beheben und einen Selbstschutz hinzufügen. Auch nach der Installation im Feld ist Vorbeugung noch möglich, z.B. können SOC-Sicherheitsmitarbeiter (Security Operations Center) mögliche Angriffswarnungen von Geräten und Anlagen untersuchen. Doch wer den digitalen Shopfloor und ganzheitliche Industrie 4.0-Prozesse anstrebt, muss ein höheres Augenmerk auf digitale Sicherheit legen: Fortschrittliche Unternehmen setzen Incident-Response-Teams und Bug-Bounty-Programme auf und erbitten bei Forschern oder über die öffentliche Hackathons die Entdeckung von Software-Fehlern und deren Behebung.
Entwickler, die sowohl Unternehmens- wie auch IIoT-Software entwickeln, verwenden häufig SAST-, DAST- oder IAST-Tools (Static, Dynamic oder Interactive Application Security Testing), um Unternehmenssoftware zu schützen. Die Tools testen Software auf bekannte Schwachstellen und entdecken Fehler im eigenen Code. SBOM- oder SCA-Tools ermöglichen IIoT-Entwicklern zusätzlich den Scan von Softwarepakete von Drittanbietern. Diese werden oft im Objektformat bereitgestellt und können den überwiegenden Anteil eines Projekts ausmachen.
Die Hilfsmittel bilden Softwarekomponenten für die Entwickler und das Sicherheitsteam ab und ermöglichen es, vorhandene Schwachstellen im Image automatisch zu identifizieren. Sobald sie das Risiko identifiziert haben, kann es entweder durch Entfernen, Aktualisieren oder Ersetzen des fehlerhaften Softwarepakets oder durch Einführung einer anderen Sicherheitskontrolle, die das Risiko verringert, verwaltet werden. Es erleichtert auch die Überwachung der verschiedenen Komponenten der Software-Stückliste auf neue Schwachstellen, die nach der Auslieferung der Software entdeckt werden. Sie treiben Drittanbieter und Entwickler dazu an, Risiken zu identifizieren und den Code vor der Auslieferung zu korrigieren. Tabelle 1 zeigt einen Überblick nützlicher Funktionen eines Binary Scanners.
Scan-Kategorie |
Beschreibung |
---|---|
Software Bill-of-Material und Abhängigkeiten von Bibliotheken | Erstellung einer Software Bill-of-Material inklusive verwendeter Lizenzen und Abhängigkeiten |
Bekannte Schwachstellen in verwendeten Softwarekomponenten | Beinhaltet sowohl Prüfung der Software Supply Chain und Betriebssystem |
Konfigurationsrisiken in der Firmware | Unsichere Kernel Features, riskante Tools, private Schlüssel in der Firmware, mögliche Probleme der verwendeten Zertifikate (abgelaufen, schwacher Hash,…) |
Passwörter | Unsichere Passwörter, Prüfung der Passwörter gegen Wörterbücher |
Betriebssystem- und Supply-Chain Risiken | Fehlende Security Features wie DEP, Canaries, CFI,… Eingebettete URLs und Emails die es erlauben, einen Angriff zu strukturieren und zu planen |
Malwareerkennung | Scan auf gefährlichen Code aus bekannter Malware |
Projektspezifische statische Erkennung | Beispielsweise von Seriennummern, Debug Informationen die nicht im finalen Image auffindbar sein sollen |
Ein IoT-Gerät wird erst zu 100% sicher, wenn es von Strom und Internet getrennt kommunikationsunfähig in einem erdbebensicheren Metallkäfig steckt. Leider ist es dann auch unbrauchbar. Im Alltag am Shopfloor muss jeder einzelne Korrekturaufwand mit seinem Sicherheitsrisiko abgewogen werden – kann das Fehlen der Funktion geduldet werden oder ist das Risiko bis zu einem geplanten Sammel-Patch vertretbar?
Eine mögliche Lösung sollte zudem automatisch vor der Ausnutzung von kritischen (gar noch unentdeckten) Sicherheitslücken schützen, ohne dass der Entwickler dazu schwierige Speicherschutztechniken erlernen oder überhaupt Code schreiben muss, der wiederum eine neue Sicherheitslücke eröffnen könnte. Google schlägt dafür den Wechsel von der nicht-speichersicheren Programmiersprache C zu Rust vor. Doch die Migration von Legacy-Codes auf eine neue Sprache und Plattform ist teuer. Es gibt auch weniger radikale und oftmals sogar besser geeignete Lösungen.
Embedded Runtime Integrity
Embedded Runtime Integrity beispielsweise härtet die IoT-Geräte Software inklusive Drittanbieterbibliotheken automatisch ab und verhindert, dass Hacker diese während eines Produktlebenszyklus kompromittieren. Klingt magisch, ist es aber nicht. Der Eigenschutz schützt deterministisch einige Bereiche, welche die meisten Angreifer passieren, unabhängig davon, wie sie ursprünglich in das System gelangt sind. Eine eingebettete Runtime Integrity-Software verhindert damit Angriffe zur Laufzeit, von bösartigen Dateien und Skripten bis hin zu Angriffen, die Pufferüberläufe und andere In-Memory-Schwachstellen ausnutzen.
Hacker-Angriffe mehrfach blockieren
Eine Embedded Runtime Integrity-Technologie umfasst Control Flow Integrity (CFI) sowie Application Whitelisting, die Exploits von Zero-Day- und N-Day-Schwachstellen ohne Falsch-Positive verhindern. Eine Laufzeitschicht ergänzt die statische Codeanalyse und kann elaborierteste Angriffe auf vernetzte Systeme wie Netzwerkgeräte, Enterprise Edge, Automotive-ECUs und andere IIoT-Devices blockieren. Selbst wenn ein Angreifer einen mit einem neuen Angriffstyp mehrere 0-Day-Schwachstellen finden sollte, muss er schließlich Code hinzufügen, der die Persistenz aufrechterhält und durch die Kontrolle des IoT-Geräts tatsächlichen Schaden anrichtet. Die Whitelisting-Technologie blockiert diese Ausführung. Wenn der Angreifer auf Persistenz verzichtet und nur einen Speicherangriff versucht, der es ihm ermöglicht, Remote-Code auszuführen, wie etwa einen Heap- oder Stack-Überlauf, blockiert die Embedded Runtime Integrity Technologie die Ausführung des schadhaften Codes.
Speicherangriffe sind ein beliebter Weg, um eine kritische Remote-Ausführung auf einer Vielzahl von Plattformen zu erreichen. Der Speicherüberlauf oder Buffer Overflow ist ein Fehler im Programm, der es ermöglicht, einen Speicherbereich zu überschreiben. Zum Beispiel, indem Daten kopiert werden, ohne deren Größe zu überprüfen, oder numerische Rechenfehler die zu falschen Ergebnissen führen, sogenannte Integer Overflows.
Es mutet schon fast seltsam an, dass diese Sicherheitsprobleme noch immer existieren, obwohl viele IT-Ingenieure die Lücken im Laufe der Jahre mit Techniken wie ASLR (Address Space Layout Randomization) oder Stack Canaries verbessert haben. Buffer Overflows (Stack, Heap) sind eine Cyber-Angriffstechnik, die zu Remotecodeausführung oder Denial-of-Service führen kann, indem der Ausführungsfluss eines Programms geändert oder sensible Daten direkt überschrieben werden. Dies kann über unvollständige Eingabevalidierungsprozesse erreicht werden. Eine Technik des Amnesia/33-Angriffs bestand beispielsweise darin, ein DNS-Antwortpaket mit einer großen Datenmenge zu erstellen, das den Eingabespeicher überflutete und es den Angreifern ermöglichte, eigenen Code auszuführen. Schematisch würde das befallene Paket wie in Tabelle 2 aussehen. Die zusätzlichen Bytes am Ende des Pakets überschreiben die ursprünglichen Rücksendeadressen und ändern somit den Programmablauf.
Antwort auf DNS-Anfrage |
Anfrage ID | IPV4 Adresse: 4 bytes |
IP Domain: X bytes |
Überlaufbytes: zum Angreifercode springen |
---|
Abbildung 1. Schematische Darstellung eines »verschmutzten« DNS-Pakets
Der Speicherüberlaufschutz ist eine Technik, die eine unerwartete Änderung des Programmablaufs und eine anschließende Cyber-Ausnutzung erkennt und verhindert. Eine übliche Präventionstechnik dabei ist die strikte Trennung von Stack- und Benutzerdatenspeicherbereichen, die so weit gehen, dass sie in verschiedenen Speichertypen mit unabhängigen Speicheradressbereichen vorhanden sind. Dieser Ansatz erfordert ein sorgfältiges Hardwaredesign und ist möglicherweise nicht für alle IIoT-Designs anwendbar.
Zur Erkennung und Verhinderung solcher Angriffe werden softwarebasierte Ansätze, häufig ASLR oder Stack Canaries, verwendet. Ein weiterer, modernerer Ansatz ist Control Flow Integrity (CFI).
ASLR
ASLR erstellt ein zufälliges Layout des Adressraums, sodass zwei verschiedene Laufzeitinstanzen desselben Programms unterschiedliche Speicherlayouts für geladene Binärdateien sowie für Stack und Heap haben, was die Arbeit des Angreifers erschwert, denn er kann den Adressraum nicht untersuchen und einen statischen Angriff aufbauen. Diese Technik wurde jedoch durch die Verwendung von Informationsleck-Bugs und Seitenkanalangriffen vereitelt. Beim bekannten Tesla-Angriff 2020 verwendeten die deutschen Wissenschaftler einen Bug im Informationsleck, um die verschiedenen Offsets zu erkennen, die von den wichtigen Modulen im Tesla Infotainment-System verwendet wurden. Damit wurde ein dynamischer Angriff erstellt, der die erkannten, willkürlichen Offsets berücksichtigte. In anderen veröffentlichten Berichten wurden Adressoffsets durch den Seitencache geleakt – zum Beispiel der AnC-Angriff von VUsec.
Stack Canaries
Stack Canaries funktionieren tatsächlich wie ein Kanarienvogel im Bergwerk als Frühwarnsystem. Die Stack Canaries sind Werte, die vor Rückgabewerten auf den Stack geschrieben und überprüft werden, bevor der Sprung ausgeführt wird. Ein »toter« Canary, der nicht den erwarteten Werten entspricht, ist ein starker deterministischer Hinweis darauf, dass die Software angegriffen wird. Bei einem Overflow-Angriff wird dieser Wert wahrscheinlich mit einem anderen Wert überschrieben, doch der Verifizierungsprozess erkennt die Änderung und blockiert den Sprung, wodurch verhindert wird, dass der Angreifer die Kontrolle über den Programmablauf erlangt. Die verschiedenen Canary-Typen unterscheiden sich in Umfang und Komplexität ihrer Berechnung. Die einfachste Version schreibt einfach Nullen – mit der Annahme, dass Strings keine String-Enden in der Mitte enthalten können. Aufwändigere Implementierungen erstellen einen XOR des Rückgabewerts mit einem Zufallswert, der dynamisch bei jeder Ausführung generiert wird. Erweiterte Implementierungen erstellen einen Hash aus dem Funktionsnamen und der Anzahl und Art der Parameter. Das Umgehen von Stack Canaries kann entweder durch das Durchsickern des Canary-Werts unter Verwendung einer Speicherleck-Schwachstelle oder in einigen Fällen sogar durch Brute-Force-Verfahren und Spoofing eines korrekten Stack Canary-Werts erfolgen. Der Exploit könnte den gespeicherten, erwarteten Canary-Wert manipulieren und den Programmfluss dadurch doch ändern.
Die CFI-Technologie umschließt automatisch Funktionsaufrufe im System sowohl beim Aufruf als auch bei der Rückkehr mit Zeigervalidierungscode. Die Zeigervalidierung überprüft, ob die Sprungadresse zulässig ist, was die Ausnutzung des Buffer Overflows viel schwieriger macht. Das bedeutet, dass ein Angreifer beim ausgehenden Aufruf oder beim Rücksprung weder den Stack noch den Heap überlaufen kann. Jeder derartige Versuch könnte die Ausführung stoppen und den Admin durch ein Sicherheitsprotokoll benachrichtigen, sofern dies vom System unterstützt wird.
Ein starkes Angriffsmodell eines Hackers kann zu jeder Zeit willkürlich jeden Datenspeicher und die meisten Register überschreiben. Es gibt allerdings Einschränkungen. Ein Angreifer kann den Programmzähler und die reservierten Register nicht direkt überschreiben. Zusätzlich geht er davon aus, dass der Datenspeicher ein nicht-ausführbarer Speicher ist und der Code-Speicher nicht beschreibbar ist.
Aus dem RAM geblockt
Wenn es sich um eine Flash-basierte MCU handelt, und die Ausführung eines Codes aus dem RAM geblockt ist, bedient sich ein Hacker einer Technik die Return-Oriented-Programming (ROP) genannt wird. Angriffe können bestehenden Code im Flash wiederverwenden und ausgewählte Befehle ausführen, die bereits vorhanden sind – sogenannte »Gadgets«. Typischerweise wird ROP dazu verwendet, die Codeausführung aus dem RAM zu aktivieren. Bild 1 veranschaulicht einen Programmfluss unter Verwendung der ROP-Technik.
Die Karte der zulässigen Aufrufe (Control Flow Graph, Bild 2) zwischen den verschiedenen Funktionen wird heutzutage mit entsprechenden Tools im Build Prozess automatisch erstellt und erfordert keine Entwicklereingriffe oder Änderungen am Code oder der zugrunde liegenden Hardware. Der gesamte Prozess blockiert ROP, Return-to-LibC und andere dateilose Angriffe.
Microsofts CFG (Control Flow Guard) ist eine CFI-Implementierung für Windows 10 und Windows 8.1, die im November 2014 veröffentlicht wurde. Sie schützte nur Rücksendeadressen mit der bereits beschriebenen Methode. Microsoft hat auf der BlueHat-Veranstaltung 2019 [2] angekündigt, auch Vorwärtssprünge zu unterstützen und die daraus resultierende Technologie XFG (Extended Flow Guard) zu nennen.
Google, ein langjähriger Verfechter von Linux und Android, hat Anfang 2021 eine Analyse zur Prävalenz kritischer Fehler veröffentlicht: 59% der kritischen Android-Bugs [3] von Google waren speicherfehlerbedingt (Bild 3). Eine Untersuchung der Apple iOS Patches ergab, dass quartalsweise ~90% der Patches auf Speicherschwachstellen zurückzuführen waren. Deshalb ist auch ein Angriff auf Speicherschwachstellen sehr interessant für den Angreifer, und häufig sind Teile des Codes oder der Bibliothek öffentlich zugänglich, so dass zunächst kein Zugriff auf ein bestimmtes Gerät notwendig ist. Man spricht hier von Angriffen auf die Software Supply Chain – damit wird die Mühe des Hackers gleich vielfach belohnt, da er davon ausgeht, dass Software von Drittanbietern mehrfach verwendet wird – zum Beispiel ein TCP/IP Stack oder RTOS System.
Wenn Control-Flow-Integrity also für Microsoft und Google wichtig ist, sollte es auch für uns nützlich sein.
Für industrielle IoT-Systementwickler, die eingebetteten Code auf unterschiedlichen Plattformen wie einem Linux-Gateway oder Multi-Modul-RTOS End-Node entwickeln, ist es empfehlenswert eine CFI-Lösung zu integrieren, die aktuelle und zukünftige Anforderungen sowie Legacy-Plattformen abdeckt und sowohl Hardware als auch Betriebssystem-agnostisch ist.
Die CFI-Sicherheitsrichtlinie sollte während des Build-Prozesses automatisch in die Gerätefirmware eingebettet werden, ohne dass der Softwareentwickler eingreifen und zusätzlichen Integrationsaufwand betreiben muss. Erkennungs- und Präventionsentscheidungen sollen lokal auf dem IoT-Gerät getroffen werden, sodass keine Konnektivität für Updates erforderlich ist, sie jedoch für Benachrichtigungen über Angriffe verwendet werden kann – sogenannte CFI-Events.
Die eingebettete CFI-Sicherheitsrichtlinie führt eine Laufzeitintegritätsprüfung der Vorgänge durch. Das führt zu erhöhter CPU und Speicherauslastung und deshalb ist die CFI-Lösung sowohl für Legacy-Produkte als auch für Neuentwicklungen geeignet. Eine CFI-Lösung sollte demnach die CPU maximal zu 5% zusätzlich auslasten und den Speicherbedarf nur minimal erhöhen. Ein Kriterium kann sein, den Speicherbedarf bei einem Linux System um nicht mehr als 10% zu erhöhen, während bei einem Flash-basierten MCU System möglichst kein zusätzlicher RAM benötigt werden sollte.
Zuletzt sollte die CFI-Lösung keine besonderen Kenntnisse in der Entwicklungsabteilung erfordern. Die Speicherschutztechniken schützen auf deterministische Weise vor unterschiedlichen Arten von Angriffen und blockieren unbekannten Angriff im Voraus. Die folgende Tabelle zeigt eine Auswahl an CFI-Lösungen und Fokus auf bestimmte Betriebssysteme.
Softwareprojekte heute sind sehr komplex und bedienen sich zudem Code von Open Source- und Closed Source-Drittanbietern. Ein Cybersecurity Code-Review kann nicht mehr den gesamten Code abdecken, zumal dieser oft auch nicht vorliegt, eine Binary Image Analyse auf bekannte Schwachstellen findet ebenso nur die bekannten Schwachstellen – isoliert diese aber nicht. Penetration Tests finden häufig In-Memory Schwachstellen wie Buffer Overflows die von der R&D Abteilung gepatcht werden, die Kosten pro gefundene Schwachstelle sind hoch – denn jede Schwachstelle erfordert einen Change Request.
Die häufigsten Schwachstellen können mit CFI automatisch während des Build-Prozesses isoliert werden und erhöhen sogar den Schutz vor noch unbekannten Schwachstellen. Deshalb eignet sich auch CFI als »Retrofit« für bereits im Feld installierte Legacy-Systeme, welche eine OTA Funktion bereithalten, ebenso aber auch für Neuentwicklungen. Die zukünftigen Penetration Tests können sich dann vollkommen auf die richtig schwere Schwachstellenfindung konzentrieren, die zumindest mit heutigen Technologien noch nicht automatisch isoliert werden können. Während der Laufzeit des IIoT-Gerätes kann ein blockierendes CFI-Event ausgewertet werden und ein Patch zielgerichtet zur Verfügung gestellt werden. CFI isoliert die Schwachstelle, aber der Softwarefehler ist immer noch vorhanden. er kann damit zur Erhöhung der Gesamt-Produktsicherheit ein für alle Mal gefixt werden. (uh)
Literatur:
[1] Amnesia:33 Veröffentlichung - https://us-cert.cisa.gov/ics/advisories/icsa-20-343-01
[2] Advancing Windows Security – David Weston, Microsoft, Blue Hat 2019
[3] Data Driven Security Hardening – Android Security team, January 2021
[4] Karamba Security XGuard – Deterministic Embedded Device Memory Security
[5] Karamba Security VCode – Automated Supply Chain Protection with Binary Scanning