Datenvalidierung UTF8 mit BiDi-Steuerzeichen (TrojanSource 2.0)

15.07.2024

Ich bin heute nochmal inspiriert worden, weiter über die Trojan Source Vulnerability nachzudenken. Meiner Meinung nach bestehen hier noch Probleme - speziell bei Nutzereingaben oder Daten, die über externe Schnittstellen ampfangen werden.

Ich hatte bisher große Plattformen und dedizierte Editorkomponenten auf Verwundbarkeit durch TrojanSource-Angriffe untersucht. Ich hatte dabei völlig ganz normale GUI-Komponenten außer Acht gelassen.

Das holte ich nunmehr nach, indem in eine einfache Swing-Oberfläche in einem Java-Programm erstellte mit einem einzeiligen Texteingabefeld und einer mehrzeiligen Texteingabekomponente. Beide waren - auch in der neuesten Java-Version noch gegen solche Angriffe verwundbar. Nachdem ich meine diesbezügliche NEugierde befriedigt hatte überlegte ich, wie man dieses Verhalten eventuell für Angriffe ausnützen könnte.

Man könnte zunächst die Usability einer Anwendung beschneiden: Man stelle sich vor, dass ein Angreifer Daten in der Datenbank der Anwendung manipuliert und dort solche Unicode-Zeichen in die Felder einfügt, wie sie auch für TrojanSource-Angriffe verwendet werden. Wird dies korrekt erledigt, ändert sich an der Anzeige in der Applikation, die darauf nicht vorbereitet ist nichts. Allerdings kann nun nichtmehr erfolgreich gesucht werden, weil die Texte in der Datenbank nun nicht mehr mit etwaigen Suchbegriffen übereinstimmen.

Ein weiteres Szenario ist die Validierung eingegebener (oder über eine externe Schnittstelle empfangener) numerischer Werte:

Ich habe dazu einige Versuche angestellt und dazu nicht nur Java, sondern auch C, C++ und Python daraufhin untersucht, was passiert, wenn ein String in eine Integerzahl umgewandelt werden soll, der Zeichen aus einem TrojanSource-Angriff enthalten:

//...
	System.out.println(de.elbosso.util.Utilities.hexdump(tf.getText().getBytes()));
	java.text.NumberFormat nf=java.text.NumberFormat.getIntegerInstance();
	System.out.println(nf.parse(tf.getText()));
	System.out.println(Integer.valueOf(tf.getText()));
//...

Java Programmierer können sich auf Bordmittel verlassen - jeder der hier gezeigten Wege zum Parsen eines Strings in eine Zahl schlägt wegen nicht erlaubter Zeichen im String fehl.

 <stdio.h>
 <stdlib.h>
 <errno.h>

int main() { printf("300‮⁦400⁩⁦500\n"); int a=atoi("300‮⁦400⁩⁦500"); printf("%d\n",a); a=0; printf("sscanf: %d\n",sscanf("300‮⁦400⁩⁦500","%d",&a)); printf("%d\n",a); char * end; a=0; a=strtol ("300‮⁦400⁩⁦500", &end, 10); if (*end != '\0' || errno == ERANGE) printf("error %d\n",a); else printf("%d\n",a);

return 0; }

Mit C war es schon problematischer: nur strtol bietet die Möglichkeit, einen solchen Angriff zu erkennen - dazu muss amn aber die hier skizzierte Fehlererkennung explizit durchführen. Ansonsten verhält sich auch diese Methode exakt wie die anderen: sie liest so lange Zeichen ein und wandelt sie um, bis sie auf ein Zeichen stößt, das laut Grammatik in einer Ganzzahl nicht vorkommt und beendet das Parsen - das Ergebnis wird aus den erfolgreich eingelesenen Zeichen gebildet.

 <iostream>
 <sstream>

int main() { std::cout << "300‮⁦400⁩⁦500\n"; int i = std::stoi("300‮⁦400⁩⁦500"); std::cout << i << "\n"; i=0; if(std::istringstream("300‮⁦400⁩⁦500") >> i) std::cout << i << "\n"; else std::cout << "error " << i << "\n"; i==0; if(std::istringstream("huhu") >> i) std::cout << i << "\n"; else std::cout << "error\n"; i=0; char c; std::istringstream ss("300‮⁦400⁩⁦500"); ss >> i; if (ss.fail() || ss.get(c)) std::cout << i << "\n"; else std::cout << "error " << i << "\n"; return 0; }

C++ ist in meinen Tests der schwierigste Kandidat gewesen: Keiner der hier als Bordmittel getesteten Varianten zeigte einen Fehler auf - nicht einmal der letzte Codeabschnitt, in dem der Stream explizit nach dem Auftreten von Fehlern gefragt wird. Meine Empfehlung daher ist die gleiche, die auch das Internet gibt: lieber auch in C++ Programmen auf strtol zurückgreifen!

import string
from ast import literal_eval

print(literal_eval('300‮⁦400⁩⁦500')) print(eval('300‮⁦400⁩⁦500')) print(int('300‮⁦400⁩⁦500'))

Python hingegen schlägt sich ungefähr so gut wie Java - egal, welche der hier gezeigten drei Möglichkeiten man anwendet, um einen String in eine Ganzzahl umzuwandeln - jede wirft eine Exception, sobald versucht wird, TrojanSource-Controlcharacters in die Inputstrings zu schmuggeln.

Alle Artikel rss Wochenübersicht Monatsübersicht Codeberg Repositories Mastodon Über mich home xmpp


Vor 5 Jahren hier im Blog

  • Synchronisierung von Lorenz-Systemen III

    23.10.2020

    Nachdem ich in einem vorhergehenden Artikel auf das Problem des kleinen Parameterraums im Zusammenhang mit der Nutzung synchronisierter chaotischer Systeme hingewiesen hatte will ixch hier untersuchen, wie sensibel solche Systeme auf Abweichungen der Parameterwerte zwischen treibendem und getriebenen System reagieren

    Weiterlesen

Neueste Artikel

  • Cloud - das unentdeckte Neuland (oder FDP: Digital first, Bedenken second)...

    Nachdem die Öffentlichkeit letzte Woche wieder mal mitgekriegt haben sollte, dass die Konzentration in der Cloud Schwachsinn ist und - vielleicht nicht - die ganze Öffentlichkeit vor zwei Wochen wieder einmal herzlich gelacht hat über die, die dennoch alles in die Cloud auslagern, aber offensichtlich nicht verstehen, wie sie funktioniert - hier einige Gedanken von mir dazu...

    Weiterlesen
  • Preisgünstige Überwachungskameras

    Ich habe im vorhergehenden Artikel davon berichtet, wie ich versuchte, meinen Raspis eine neue Betriebssystemversion zu verpassen.

    Weiterlesen
  • Plugin zur Arbeit mit Markdown für NeoVim

    Ich habe neulich beschrieben, dass ich aktuell mehr und mehr bemerke, dass Dinge, für die ich in meinem NeoVim-Setup Plugins benutzt habe sehr gut auch mit Bordmitteln funktionieren.

    Weiterlesen

Manche nennen es Blog, manche Web-Seite - ich schreibe hier hin und wieder über meine Erlebnisse, Rückschläge und Erleuchtungen bei meinen Hobbies.

Wer daran teilhaben und eventuell sogar davon profitieren möchte, muss damit leben, daß ich hin und wieder kleine Ausflüge in Bereiche mache, die nichts mit IT, Administration oder Softwareentwicklung zu tun haben.

Ich wünsche allen Lesern viel Spaß und hin und wieder einen kleinen AHA!-Effekt...

PS: Meine öffentlichen Codeberg-Repositories findet man hier.