Software-Design

Grundlagen der Sicherheit bei Embedded-Software

Seite: 4/5

Anbieter zum Thema

Schwachstellen, auf die man beim Coding achten muss

Während der Programmierung können Entwickler die Softwaresicherheit verbessern, indem sie eine Reihe bekannter Schwachstellen vermeiden.

1. Pufferüberlauf

Mit weitem Abstand ist der Pufferüberlauf die am weitesten verbreitete Gefahrenquelle, wenn man in der Sprache C programmiert. Es kann ganz einfach sein – zum Beispiel in das Element mit der Nummer 256 eines 256-teiligen Arrays Daten hineinzuschreiben.

Compiler erkennen verbotene Pufferzugriffe nicht immer als Softwarefehler.

Das kann ernsthafte Konsequenzen wie die „Code Injection“ oder die „Arc Injection“ haben – bei letzterer ändert der Angreifer den Kontrollfluss eines Programms, indem er die Rücksprungadresse auf dem Stack modifiziert. Bei der „Arc Injection“ braucht der Angreifer nicht einmal Code einzuschleusen. er kann zu irgendeiner Funktion im existierenden Code springen oder Gültigkeitsprüfungen oder Assertions überspringen.

Hier ein Beispiel einer Pufferüberlauf-Attacke: Ein eingebettetes Gerät misst die Wassertemperatur in einem Schwimmbecken und zeigt die Zeitanteile als Histogramm an, in denen das Wasser eine bestimmte Temperatur hatte.

Der Softwareentwickler baut einen Array mit 100 positiven Integerzahlen, bei denen jedes Element mit einer Gradangabe in Celsius korrespondiert: Element 0 für 0°, Element 1 für 1° und so weiter. Jedesmal, wenn der Sensor eine Messung der Wassertemperatur vornimmt, wird das korrespondierende Element des Arrays um den Wert 1 erhöht.

Um ganz sicher zu gehen, stattet der Entwickler den Temperatur-Array mit viel Spielraum aus. Er übersteigt den Temperaturbereich bei weitem, den ein menschlicher Körper aushalten würde.

Bis eines Tages der Angreifer den Sensor aus dem Wasser nimmt und mit einem Feuerzeug aufheizt. Sobald der Sensor einen Wert misst, der 100° übersteigt, verletzt die Software für das Histogramm-Update eine Speicheradresse, die hinter dem Ende des Temperatur-Arrays liegt. Wenn dort Daten liegen, hat der Angreifer die Daten korrumpiert. Steht dort Maschinencode, dann hat der Angreifer die ausführbare Software korrumpiert. In jedem Fall ist es ein schädlicher Eingriff. Bitte beachten Sie, dass dafür weder eine Internetverbindung noch eine Verbindung zu einem externen Netzwerk nötig war. Ein Feuerzeug genügte.

Wie können wir Pufferüberläufe vermeiden? Die Schwachstelle ist so weit verbreitet, dass ein mehrstufiger Ansatz am besten ist: Verhindern, Entdecken, Heilen. Im Beispiel unseres Schwimmbeckens sollten Sie explizit prüfen, dass keine Temperatur ermittelt wird, die der von Eis (unter 0°) oder heißem Dampf (über 100°) entspricht.

Verhindern Sie Pufferüberläufe auch, indem Sie gefährliche Bibliotheksfunktionen vermeiden (wie gets()) und Vorsicht bei anderen walten lassen (wie memcpy()).

Entdecken Sie Pufferüberläufe, indem Sie wie ein Anstreicher vorgehen: Erweitern Sie den Puffer an beiden Enden etwas. Füllen Sie die Erweiterungsbereiche mit ungewöhnlichem Inhalt, den ich „Anstrich“ nenne, zum Beispiel eine Falle in der Maschinensprache Ihres Prozessors. Dann prüfen Sie den „Anstrich“ wiederholt zur Laufzeit. Wenn der Anstrich überschrieben wurde, haben Sie einen Pufferüberlauf entdeckt.

2. Tricksereien mit Zeigern

Wenn ein Angreifer einen Datenzeiger modifizieren kann, dann kann der Angreifer nach eigenem Gusto an jede denkbare Stelle verweisen. Wenn ein Angreifer einen Funktionszeiger überschreiben kann, dann ist er auf einem guten Weg, seinen Code auf Ihrem Prozessor auszuführen.

3. Dynamische Speicherzuweisung

Die Verwendung dynamischer Speicherzuweisungen ist in vielen sicherheitskritischen Systemen wie zum Beispiel der Luft- und Raumfahrt verboten. Angreifer sind heiß darauf, solche Defekte zu finden, da sie eine günstige Gelegenheit bieten, die Sicherheit eines Embedded-Systems zu verletzen.

Ein besonders empfindlicher Fehler ist es, die Prüfung zu unterlassen, ob eine Anfrage zur Speicherzuweisung erfolgreich war oder nicht. Manche Mechanismen geben anstelle eines Zeigers auf einen Speicherpuffer den Wert Null aus, wenn kein verfügbarer Speicher mehr vorhanden ist. Wenn die Anwendungssoftware diesen Nullwert als Zeiger behandelt, wird sie in einen Puffer hineinschreiben, der an der Speicheradresse Null beginnt.

Viele Angreifer wären glücklich, wenn Ihre Software dies täte. Angreifer wissen, dass eingebettete Software oft eingeschränkte Speicherressourcen hat. Sie werden alles daransetzen, den Speicher auszuschöpfen, indem sie den Speicherzuweisungsmechanismus dazu zwingen, mehr Speicher als sonst üblich zu belegen – vielleicht durch Speicherlecks.

Sie können auch versuchen, Ihr Datenabfragesystem mit höheren Datenmengen oder Datenraten zu überfluten – in der Hoffnung, dass die Datenlawine Ihre Speicherkapazität erschöpft. Und dann? Wenn Ihre Software einen Speicherpuffer anfragt, aber die Prüfung unterlässt, ob die Zuweisung fehlgeschlagen ist, wird sie einen Puffer an der Adresse Null eröffnen und alles zertrampeln, was vorher dort gewesen ist.

Wenn zum Beispiel Ihre Flags für das Ein- und Ausschalten von Interrupts an dieser Stelle stehen, könnte dadurch die Verbindung zwischen der Software und den Hardware-Interfaces an der Peripherie unterbrochen werden. Das könnte dazu führen, dass Ihr System nicht mehr eingebettet ist.

4. Verunreinigte Daten

Daten, die von außen in ein eingebettetes System gelangen, darf man nicht vertrauen. Stattdessen müssen sie vor dem Gebrauch desinfiziert werden.

Das trifft auf alle Arten von Datenströmen zu, auch für die einfachsten Integerwerte. Angreifer halten Ausschau nach Extremwerten, die abnorme Effekte produzieren. Insnbesondere jagen sie nach unerwarteten Werten, also nach Situationen, in denen ein digitaler Mikroprozessor zu einem anderen Ergebnis kommen würde als ein Mensch mit Papier und Bleistift.

Sagen wir, ein Integerwert i soll den Wert 2.147.483.647 haben. Wenn ich zu diesem Wert auf Papier 1 addiere, dann bekomme ich +2.147.483.648. Aber wenn mein Mikroprozessor den Befehl i++ ausführen soll, würde -2.147.483.648 herauskommen, eine große negative Zahl. Für einen gewieften Angreifer wäre es ein Leichtes, diese Eigenart auszunutzen, um ein eingebettetes System zu verwüsten.

Eine nützliche Technik, Daten zu desinfizieren, ist das Whitelisting. Damit werden alle möglichen gültigen Werte für eine bestimmte Art von Daten beschrieben, und der Code akzeptiert nur diese Werte. Alle unerwarteten Werte werden als verunreinigt betrachtet und zurückgewiesen, bevor sie verarbeitet werden.

(ID:33374870)