Pufferüberläufe sind groß. In C ist standardmäßig nichts auf den Bereich geprüft, daher ist es sehr einfach, einen Puffer zu überschreiben. Es gibt eine Standardbibliotheksfunktion gets()
, die nicht daran gehindert werden kann, den Puffer zu überlaufen, und die fast nie verwendet werden sollte.
Es gibt einige Techniken auf Implementierungsebene, die die Ausnutzung behindern, z. B. das Verwürfeln von Heap-Blöcken. Dadurch werden jedoch Pufferüberläufe in lokalen Puffern nicht gestoppt, was häufig interessante Dinge wie das Ändern der Adresse bewirken kann, an die eine Funktion zurückkehrt.
In C gibt es keine gute allgemeine Lösung. Viele Bibliotheksfunktionen verfügen über Versionen, die die Anzahl der Schreibvorgänge begrenzen. obwohl das zu berechnen ungeschickt sein kann. Es gibt Software, die Heap-Pufferüberläufe im Test erkennen kann, solange der entsprechende Test ausgeführt wird, und Stack-Überlauf wird beim Testen häufig als Absturz angezeigt. Ansonsten geht es um sorgfältige Codierung und Codeüberprüfung.
Ein verwandtes Problem ist das Problem, in einen Puffer zu schreiben, der um ein Zeichen zu klein ist, und zu vergessen, dass eine C-Zeichenfolge mit einer Länge von n Zeichen aufgrund des '\0'
Terminators n + 1 Zeichen im Speicher benötigt . Wenn es dem Angreifer gelingt, eine Zeichenfolge ohne Terminator zu speichern, wird jede C-Funktion, die eine Zeichenfolge erwartet, so lange verarbeitet, bis sie ein Null-Byte erreicht. Dies kann dazu führen, dass mehr Informationen kopiert oder ausgegeben werden als gewünscht (oder der geschützte Speicher für einen DOS-Angriff erreicht wird) ). Die Lösung ist wiederum Sensibilisierung, Pflege und Codeüberprüfung.
Es gibt ein weiteres Risiko für die printf()
Familie. Wenn Sie jemals schreiben char * str; ... printf(str);
, bereiten Sie sich auf Probleme vor, wenn str
beim Drucken ein '%' enthalten ist. Die %n
Formatanweisung ermöglicht printf()
das Schreiben in den Speicher. Die Lösung ist printf("%s", str);
oder puts(str);
. (Verwenden Sie snprintf()
stattdessen auch den C99 sprintf()
.)
Die Verwendung von Ganzzahlen ohne Vorzeichen, insbesondere als Schleifenindizes, kann Probleme verursachen. Wenn Sie einem vorzeichenlosen Wert einen kleinen negativen Wert zuweisen, erhalten Sie einen großen positiven Wert. Das kann Dinge wie die Verarbeitung von nur N Instanzen von etwas oder in eingeschränkten Funktionen wie untergraben strncpy()
. Untersuchen Sie alle vorzeichenlosen Ganzzahlen. Möglicherweise möchten Sie dies vermeiden unsigned short
, da ein großer Wert in einem dieser Werte in einen großen positiven Wert in einem umgewandelt wird int
.
Vergessen Sie nicht, dass eine Zeichenkonstante in C tatsächlich eine ist int
. Das Schreiben von so etwas char c; while((c = getchar()) != EOF) ...
kann leicht fehlschlagen, da es EOF
in a nicht darstellbar ist char
.
Es gibt viel mehr charakteristische C-Fehler, die mir einfallen, aber diese können Sicherheitsprobleme verursachen.