Mittwoch, 8. Februar 2012 |
Eine Formatstring-Schwachstelle entsteht, wenn Benutzereingaben
ungeprüft und ungefiltert an bestimmte C-Funktionen wie z.B.
printf() übergeben werden, die formatierten Text ausgeben
können. Diese Funktionen akzeptieren eine unterschiedliche Anzahl von
Parametern, die aus verschiedenen Datentypen wie Zahlen oder Strings
bestehen können. Der gleichzeitig übergebene Formatstring
spezifiziert, welche Daten in den Variablen enthalten sind und in welchem
Format sie dargestellt werden sollen.
Die folgende Codezeile gibt eine Meldung aus, die den als Dezimalzahl
dargestellten Wert der Variable irgendwas enthält:
printf("Der Wert von irgendwas ist %d.\n", irgendwas);
Der gefährlichste Formatierungsbefehl ist %n: Er bewirkt
keine Ausgabe der übergebenen Parameter, sondern führt dazu, das
die Anzahl der bisher geschriebenen Bytes an die Adresse geschrieben wird,
auf die der als Parameter übergebene Wert zeigt:
int irgendwas = 123;
int geschrieben = 0;
printf("Der Wert von irgendwas ist %d%n.\n", irgendwas, &geschrieben);
printf("%d Bytes wurden geschrieben.\n", geschrieben);
erzeugt folgende Ausgabe:
Der Wert von irgendwas ist 123.
30 Bytes wurden geschrieben.
Die betreffenden Funktionen können nicht erkennen, ob der Formatstring mehr Steuerbefehle enthält, als Parameter übergeben wurden. Es werden solange Parameter vom Stack geholt, bis der Formatstring abgearbeitet ist.
Kann ein Angreifer den Formatstring ganz oder teilweise manipulieren, kann er darüber Teile des Speichers überschreiben und eigenen Code einschleusen und ausführen: Er kann sowohl die Anzahl der von der Funktion ausgegebenen Bytes als auch den Pointer auf dem Stack, der mit dieser Anzahl überschrieben wird, frei wählen und dadurch z.B. eine Rücksprungadresse oder den Pointer zu einem Exception-Handler überschreiben. Der Effekt ist vergleichbar mit einem stackbasierten Pufferüberlauf, siehe About Security #5 ff.
Bei der Suche nach Formatstring-Schwachstellen wird für alle in Frage kommenden Parameter, d.h. die, die evtl. an ein externes Programm weitergeleitet werden, eine Reihe von Testwerten mit Formatstrings übergeben und danach die Webanwendung auf unnormales Verhalten überwacht. Wie im Fall von Pufferüberlauf-Schwachstellen wird sich auch hier eine Schwachstelle meist durch einen Absturz des betroffenen Programms zu erkennen geben.
Für jeden Parameter wird eine große Anzahl der
Formatierungsbefehle %n und %s eingegeben:
%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n
%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s
Da die Windows-Funktion FormatMessage die Steuerbefehle anders
als die printf-Funktionen verwendet, müssen dafür
auch die Testwerte angepasst werden:
%1!n!%2!n!%3!n!%4!n!%5!n!%6!n!%7!n!%8!n!%9!n!%10!n! usw.
%1!s!%2!s!%3!s!%4!s!%5!s!%6!s!%7!s!%8!s!%9!s!%10!s! usw.
Ggf. muss das %-Zeichen URL-kodiert als %25
übertragen werden.
%s wird als zusätzlicher Testwert verwendet, da in
manchen Fällen %n aus Sicherheitsgründen ignoriert
wird. %s führt dazu, das die betroffene Funktion jeden
Parameter vom Stack dereferenziert. Enthält das Programm eine
Formatstring-Schwachstelle, führt das sehr wahrscheinlich zu einem
Zugriffsfehler.
Nach jeder Eingabe wird die Ausgabe der Webanwendung wie bei der Suche nach Pufferüberlauf-Schwachstellen auf ungewöhnliche Reaktionen überprüft, siehe About Security #197.
Formatstring-Schwachstellen können vermieden werden, indem
Formatierungsbefehle aus den Eingaben ausgefiltert und die betroffenen
Funktionen mit gesetzten Formatierungsbefehlen aufgerufen werden. Ein
Aufruf von z.B. printf(puffer) führt dazu, das die
Variable puffer als String mit Formatierungsbefehlen
interpretiert wird. Ein Aufruf von z.B. printf("%s", puffer)
hingegen führt zur Ausgabe des Puffers, da der Formatierungsbefehl
bereits angegeben wurde.
Zum Abschluss noch einige allgemeine Bemerkungen zu Pufferüberlauf-, Integer- und Formatstring-Schwachstellen in Webanwendungen. Diese Schwachstellen treten in den in interpretierten Sprachen wie z.B. PHP geschriebenen Webanwendungen nicht auf. Wenn bekannt ist, das keine externen Programme aufgerufen werden, kann man daher auf die Suche nach ihnen verzichten.
Da es bei der Suche nach diesen Schwachstellen sehr wahrscheinlich zu Abstürzen und damit einem Denial-of-Service kommt, wird man entsprechende Tests i.d.R. auf einem Testsystem durchführen. Wenn man weiß, wie die möglicherweise betroffenen externen Programme aufgerufen werden, kann man diese auch separat testen und dabei z.B. auf die in About Security #10 beschriebenen Hilfsmittel zur Suche nach Pufferüberlauf-Schwachstellen zurückgreifen.
Hiermit ist die Suche nach Schwachstellen in kompilierten Programmen abgeschlossen. In der nächsten Woche erscheint die 200. nummerierte Folge von About Security mit einer Zusammenfassung der Entwicklungen in den vergangenen 4 Jahren. Mit der Schwachstellensuche in Webanwendungen geht es in About Security #201 weiter, dann geht es um Angriffe auf die Anwendungsarchitektur.
Wenn Sie Fragen oder Themenvorschläge haben, können Sie diese gerne an die angegebene E-Mail-Adresse senden oder im Security-Forum einbringen!