Für Code Injection muss das Gerät irgendwelche Daten bekommen, in denen Code steht, der dann falsch interpretiert und versehentlich ausgeführt wird.
Also:
- Daten bekommen
- "falsch" auswerten/validieren
- ausführen
Der Klassiker Buffer Overflow hat fehlende Längenprüfung (2) und die geschriebenen Daten werden dann vom Prozessor ausgeführt (3). Braucht natürlich eine Von-Neumann-Architektur.
Klassische SQL-Injection ist eine Webanfrage (1), in der Daten stehen, die in eine DB sollen. Die Daten werden vom Programm unzureichend überprüft, so dass SQL-Escape-Codes unbemerkt bleiben (2). Der SQL-Server führt das dann aus (3).
Shell-Injection bzw. OS-Command Injection geht ähnlich (1). Fehlerhaft kann der Webserver (CGI) oder das Programm sein (2), Ausführung dann durch die Shell (3).
Es kommt in allen Stufen sehr drauf an, wie komplex die Geräte sind.
Es braucht auf jeden Fall eine Schnittstelle, über die das Gerät Daten bekommt (1). Das kann z.B. eine Netzwerkschnittstelle oder eine serielle Schnittstelle sein. Das kann aber auch ein Datenspeicher sein, aus dem irgendwas gelesen werden soll, z.B. eine Konfig-Datei auf einem Dateisystem. Oder ein binärer Konfig-Struct im EEprom/Flash.
Wenn ein Gerät hunderttausend Features hat, zahlreiche Protokolle unterstützt oder weitreichend anpassbar ist, dann werden sich mehr solche Vektoren finden, als bei einem einfachen Gerät.
Jetzt braucht es die fehlerhafte Auswertung/Überprüfung (2). Parser sind notorisch unsicher implementiert. Ein Grund dafür ist, dass oft nur nach bestimmten Zeichen gesucht wird und nicht alle Fehlermöglichkeiten abgefangen werden. Um einen "richtigen" Parser (wie lex&yacc) zu bauen, fehlt oft der Speicher, aber auch die Zeit und Sachkenntnis.
Sind die Daten komplex, kommt oft eine fertige Bibliothek zum Einsatz. Z.B. der Netzwerk- oder USB-Stack, auf Applikationsebene z.B. ein XML-Parser. Aufgrund der Verbreitung sind da Fehler seltener bzw. hoffentlich schon behoben. Problematischer sehe ich Erweiterungsfeatures, die man nicht kennt oder an die man nicht denkt. Beispielsweise XXE. Oder die log4j-Schwachstelle vor ein paar Jahren, die erstaunlich viele Geräte betroffen hat, wo man kein Java erwartet hätte.
Zum Schluss die Ausführungsumgebung (3). Bei einem Bare-Metal-System geht nur Maschinencode. Vorteilhaft für den Angreifer ist, dass Embedded-Systeme i.d. Regel weder ASLR noch NX-Bits haben.
Gibt es einen eingebauten Interpreter oder eine Scriptsprache, kann ich mir mehr Angriffsmöglichkeiten vorstellen. Ehrlicherweise weiß ich aber nicht, ob es z.B. bei uPython oder Lua schon entsprechende Probleme gab.
Embedded heißt aber nicht immer Bare-Metal. Viele Mikrokontroller werden mit einem kleinen (Echtzeit-) OS benutzt.
Je nachdem, wo du die Grenze zu embedded ziehen willst kann aber auch ein Linux dabei sein.
Ich weiß, dass ich dir damit nicht unmittelbar helfen konnte. Ich hoffe aber, dass die Systematisierung dir hilft, die Suche ein bisschen einzugrenzen.
Generell: der Embedded-Bereich ist vielseitig. Wilde/unerwartete Konstruktionen wird man hier häufiger sehen als z.B. bei Webentwicklern.
Ich hatte neulich den Fall, da hat jemand eine Cortex-M0-Virtualisierung gebaut, die dann auf einem M4 lief. Da war Code-Injection quasi Entwicklungsziel.