Pufferkopie ohne Überprüfung der Eingabegröße ('Klassischer Buffer Overflow')
Beschreibung
Der klassische Buffer Overflow ist eine Schwachstelle, die auftritt, wenn ein Programm Daten in einen Puffer kopiert, ohne vorher zu prüfen, ob die Daten in die zugewiesene Größe des Puffers passen. Dies geschieht typischerweise, wenn Funktionen wie strcpy(), gets(), sprintf() oder memcpy() ohne ordnungsgemäße Grenzenprüfung verwendet werden. Wenn die Eingabedaten die Pufferkapazität überschreiten, werden angrenzende Speicherstellen überschrieben, was potenziell Daten beschädigt, das Programm zum Absturz bringt oder beliebige Code-Ausführung ermöglicht. Diese Schwachstellenklasse war für zahlreiche hochkarätige Sicherheitsverletzungen verantwortlich und bleibt trotz jahrzehntelänger Aufklärung ein kritisches Problem in C/C++-Anwendungen.
Risiko
Buffer Overflows gehören zu den gefährlichsten Schwachstellen in der Software-Sicherheit. Angreifer können sie ausnutzen, um Funktions-Rücksprungadressen zu überschreiben und die Programmausführung auf eingeschleusten Shellcode umzuleiten. Stack-basierte Overflows ermöglichen zuverlässige Code-Ausführung durch Return-Oriented Programming (ROP) und andere Techniken, die moderne Schutzmaßnahmen wie DEP/NX umgehen. Heap-Overflows können Speicherverwaltungsstrukturen für ähnliche Effekte beschädigen. Selbst mit Exploit-Mitigierungen verursachen Buffer Overflows häufig Denial-of-Service durch Abstürze. Kritische Systeme, die in C/C++ geschrieben sind, einschließlich Betriebssysteme, Netzwerkdienste und Embedded-Geräte, bleiben gefährdet. Der Morris-Wurm (1988), Code Red (2001) und Heartbleed (2014) nutzten alle pufferbezogene Schwachstellen aus.
Lösung
Verwenden Sie sichere String-Handling-Funktionen mit expliziter Grenzenprüfung: strncpy(), snprintf(), strlcpy() oder plattformspezifische sichere Alternativen wie strcpy_s(). Besser noch, verwenden Sie Sprachen mit automatischer Grenzenprüfung (Rust, Go, Java) oder C++-Container (std::string, std::vector), die Speicher sicher verwalten. Aktivieren Sie Compiler-Schutzmaßnahmen: Stack-Canaries (-fstack-protector), ASLR, DEP/NX und Control Flow Integrity (CFI). Verwenden Sie statische Analysetools (Coverity, PVS-Studio) und dynamische Analyse (AddressSanitizer, Valgrind), um Buffer Overflows während der Entwicklung zu erkennen. Validieren Sie alle Eingabegrößen vor dem Kopieren. Erwägen Sie die Verwendung von speichersicheren Wrappern oder Bibliotheken.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Verfügbarkeit | Bereich: Verfügbarkeit Buffer Overflows verursachen häufig Abstürze und Denial-of-Service, wenn beschädigter Speicher zu ungültigem Speicherzugriff oder beschädigtem Kontrollfluss führt. |
| Integrität | Bereich: Integrität Angreifer können Programmdaten modifizieren, Speicherstrukturen beschädigen oder den Programmausführungsfluss durch sorgfältig gestaltete Overflow-Eingaben ändern. |
| Vertraulichkeit | Bereich: Vertraulichkeit Speicherbeschädigung kann sensible Daten in angrenzenden Speicherstellen offenlegen oder Informationsoffenlegung durch kontrollierte Überlesungen ermöglichen. |
| Zugriffskontrolle | Bereich: Code-Ausführung Erfolgreiche Ausnutzung ermöglicht beliebige Code-Ausführung mit den Privilegien des anfälligen Prozesses, was potenziell zu vollständiger Systemkompromittierung führt. |
Beispielcode + Lösungscode
Anfälliger Code
#include <stdio.h>
#include <string.h>
// ANFÄLLIG: strcpy ohne Grenzenprüfung
void vulnerable_login(char *username) {
char buffer[64];
// Angriff: Benutzername > 64 Bytes überschreibt Stack
strcpy(buffer, username); // Keine Grenzenprüfung!
printf("Willkommen, %s\n", buffer);
}
// ANFÄLLIG: gets() ist immer unsicher
void get_input() {
char input[100];
gets(input); // Niemals gets() verwenden! Keine Grenzenprüfung.
}
// ANFÄLLIG: sprintf ohne Größenbegrenzung
void format_message(char *user_data) {
char buffer[256];
sprintf(buffer, "Benutzer sagte: %s", user_data); // Overflow wenn user_data > ~244 Zeichen
}
Korrigierter Code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// SICHER: Verwendung von strncpy mit expliziter Größe
void safe_login(const char *username) {
char buffer[64];
strncpy(buffer, username, sizeof(buffer) - 1);
buffer[sizeof(buffer) - 1] = '\0'; // Null-Terminierung sicherstellen
printf("Willkommen, %s\n", buffer);
}
// SICHER: Verwendung von fgets anstelle von gets
void safe_get_input() {
char input[100];
if (fgets(input, sizeof(input), stdin) != NULL) {
// Nachfolgendes Newline entfernen falls vorhanden
input[strcspn(input, "\n")] = '\0';
}
}
// SICHER: Verwendung von snprintf mit Größenbegrenzung
void safe_format_message(const char *user_data) {
char buffer[256];
snprintf(buffer, sizeof(buffer), "Benutzer sagte: %s", user_data);
// snprintf kürzt automatisch und terminiert mit Null
}
// BEST: Verwendung dynamischer Allokation mit Größenvalidierung
char* safe_copy(const char *input, size_t max_len) {
size_t len = strnlen(input, max_len);
char *buffer = malloc(len + 1);
if (buffer == NULL) {
return NULL;
}
memcpy(buffer, input, len);
buffer[len] = '\0';
return buffer;
}
// Kompilieren mit: gcc -fstack-protector-strong -D_FORTIFY_SOURCE=2 -O2
Ausgenutzt in der Praxis
Morris-Wurm (Internet, 1988)
Der Morris-Wurm nutzte einen Buffer Overflow in der Unix fingerd-Service-Funktion gets() aus und wurde zu einem der ersten großen Internet-Würmer. Er infizierte etwa 6.000 Computer (10% des damaligen Internets), verursachte weitreichende Störungen und führte zur Gründung von CERT.
Code-Red-Wurm (Microsoft IIS, 2001)
Code Red nutzte einen Buffer Overflow in der ISAPI-Erweiterungsverarbeitung des Microsoft IIS-Webservers aus und infizierte über 350.000 Server innerhalb von 14 Stunden. Der Wurm verunstaltete Websites und startete DDoS-Angriffe gegen das Weiße Haus, was geschätzte Schäden von 2,6 Milliarden Dollar verursachte.
Heartbleed (OpenSSL, 2014)
Obwohl technisch ein Buffer-Over-Read (CWE-125), demonstrierte Heartbleed in OpenSSL die Auswirkungen von Puffer-Schwachstellen in massivem Ausmaß. Der Fehler legte bis zu 64KB Serverspeicher pro Anfrage offen und ließ private Schlüssel, Session-Cookies und Passwörter von Millionen von Servern weltweit durchsickern.
Tools zum Testen/Ausnutzen
-
AddressSanitizer (ASan) — Laufzeit-Speicherfehlerdetektor, der Buffer Overflows, Use-after-Free und andere Speicherfehler erkennt.
-
Valgrind — Speicher-Debugging- und Profiling-Tool, das Buffer Overflows und Speicherlecks erkennt.
-
American Fuzzy Lop (AFL++) — Coverage-geführter Fuzzer, der effektiv bei der Entdeckung von Buffer-Overflow-Schwachstellen ist.
-
pwntools — CTF-Framework und Exploit-Entwicklungsbibliothek zum Erstellen von Buffer-Overflow-Exploits.
CVE-Beispiele
-
CVE-2021-44228 — Obwohl eine Code-Injection, bezogen auf unsichere Eingabeverarbeitung beim Logging.
-
CVE-2014-0160 — Heartbleed OpenSSL Buffer-Over-Read, der Serverspeicher offenlegt.
-
CVE-2019-14287 — sudo-Pufferverarbeitungsfehler, der Privilegieneskalation ermöglicht.
Referenzen
-
MITRE. "CWE-120: Buffer Copy without Checking Size of Input." https://cwe.mitre.org/data/definitions/120.html
-
OWASP. "Buffer Overflow Attack." https://owasp.org/www-community/attacks/Buffer_overflow_attack
-
CERT. "Secure Coding in C and C++." https://wiki.sei.cmu.edu/confluence/display/c/SEI+CERT+C+Coding+Standard