Static Wikipedia February 2008 (no images)

aa - ab - af - ak - als - am - an - ang - ar - arc - as - ast - av - ay - az - ba - bar - bat_smg - bcl - be - be_x_old - bg - bh - bi - bm - bn - bo - bpy - br - bs - bug - bxr - ca - cbk_zam - cdo - ce - ceb - ch - cho - chr - chy - co - cr - crh - cs - csb - cu - cv - cy - da - de - diq - dsb - dv - dz - ee - el - eml - en - eo - es - et - eu - ext - fa - ff - fi - fiu_vro - fj - fo - fr - frp - fur - fy - ga - gan - gd - gl - glk - gn - got - gu - gv - ha - hak - haw - he - hi - hif - ho - hr - hsb - ht - hu - hy - hz - ia - id - ie - ig - ii - ik - ilo - io - is - it - iu - ja - jbo - jv - ka - kaa - kab - kg - ki - kj - kk - kl - km - kn - ko - kr - ks - ksh - ku - kv - kw - ky - la - lad - lb - lbe - lg - li - lij - lmo - ln - lo - lt - lv - map_bms - mdf - mg - mh - mi - mk - ml - mn - mo - mr - mt - mus - my - myv - mzn - na - nah - nap - nds - nds_nl - ne - new - ng - nl - nn - no - nov - nrm - nv - ny - oc - om - or - os - pa - pag - pam - pap - pdc - pi - pih - pl - pms - ps - pt - qu - quality - rm - rmy - rn - ro - roa_rup - roa_tara - ru - rw - sa - sah - sc - scn - sco - sd - se - sg - sh - si - simple - sk - sl - sm - sn - so - sr - srn - ss - st - stq - su - sv - sw - szl - ta - te - tet - tg - th - ti - tk - tl - tlh - tn - to - tpi - tr - ts - tt - tum - tw - ty - udm - ug - uk - ur - uz - ve - vec - vi - vls - vo - wa - war - wo - wuu - xal - xh - yi - yo - za - zea - zh - zh_classical - zh_min_nan - zh_yue - zu

Web Analytics
Cookie Policy Terms and Conditions Pufferüberlauf - Wikipedia

Pufferüberlauf

aus Wikipedia, der freien Enzyklopädie

Pufferüberläufe (engl. buffer overflow) gehören zu den häufigsten Sicherheitslücken in aktueller Software, die sich u. a. über das Internet ausnutzen lassen. Im Wesentlichen werden bei einem Pufferüberlauf durch Fehler im Programm zu große Datenmengen in einen dafür zu kleinen Speicherbereich geschrieben, wodurch dem Ziel-Speicherbereich nachfolgende Informationen im Speicher überschrieben werden.

Das kann zu einem Absturz des betreffenden Programms, zur Verfälschung von Anwendungsdaten oder zur Beschädigung von Datenstrukturen der Laufzeitumgebung des Programms führen. Durch letzteres kann die Rücksprungadresse eines Unterprogramms mit beliebigen Daten überschrieben werden, wodurch dann auch in von einem Angreifer übersandten Daten übermittelter Maschinencode mit den Privilegien des für den Pufferüberlauf anfälligen Prozesses ausgeführt werden kann. Dieser Code hat in der Regel das Ziel, dem Angreifer einen komfortableren Zugang zum System zu verschaffen, damit dieser das System dann für seine Zwecke verwenden kann. Pufferüberläufe in verbreiteter Server- und Clientsoftware werden auch von Internetwürmern ausgenutzt.

Besonders begehrtes Ziel ist bei Unix-Systemen der Root-Zugang, der dem Angreifer sämtliche Zugriffsrechte verleiht. Das bedeutet aber nicht, wie oft missverstanden, dass ein Pufferüberlauf, der „nur“ zu den Privilegien eines „normalen“ Benutzers führt, ungefährlich ist. Das Erreichen des begehrten Root-Zugangs ist oft viel einfacher, wenn man bereits Benutzerrechte hat.

Angriffe mit Pufferüberläufen sind ein wichtiges Thema in der Computersicherheit und Netzwerksicherheit. Sie können nicht nur über jegliche Art von Netzwerken, sondern auch lokal auf dem System versucht werden. Behoben werden sie in der Regel nur durch kurzfristig gelieferte Fehlerkorrekturen (Patches) der Hersteller.

Neben Nachlässigkeiten bei der Programmierung werden Pufferüberläufe vor allem durch auf der Von-Neumann-Architektur basierende Computersysteme ermöglicht, gemäß welcher Daten und Programm im gleichen Speicher liegen. Durch diese Hardwarenähe sind sie auch nur unter assemblierten oder kompilierten Programmiersprachen ein Problem. Interpretierte Sprachen sind, abgesehen von Fehlern im Interpreter, in der Regel nicht anfällig, da die Speicherbereiche für Daten immer unter vollständiger Kontrolle des Interpreters sind.

Inhaltsverzeichnis

[Bearbeiten] Programmiersprachen

Die wesentlichste Ursache für Pufferüberläufe ist die Verwendung von Programmiersprachen, die nicht die Möglichkeit bieten, Grenzen von Speicherbereichen automatisch zu überwachen, um eine Bereichsüberschreitung von Speicherbereichen zu verhindern. Hierzu gehört besonders die Sprache C, die das Hauptgewicht auf Performance (und ursprünglich Einfachheit des Compilers) legt und auf eine Überwachung verzichtet, sowie die C-Weiterentwicklung C++. Hier ist ein Programmierer teilweise gezwungen, von Hand den entsprechenden Code zu generieren, wobei oft entweder absichtlich oder aus Nachlässigkeit darauf verzichtet wird. Die Überprüfung ist häufig auch fehlerhaft implementiert, da während der Programmtests diese Programmteile meist nicht oder ungenügend getestet werden. Daneben stellt der (im Falle von C++) komplexe Sprachumfang und die Standardbibliothek sehr viele fehleranfällige Konstrukte zur Verfügung, zu denen es in vielen Fällen kaum eine Alternative gibt.

Die im professionellen Bereich häufig verwendete Programmiersprache C++ bietet theoretisch (eingeschränkte) Möglichkeiten zur automatischen Überprüfung von Feldgrenzen. Sie ist aber ursprünglich als C-Aufsatz entwickelt worden und stellt daher eine vollständige Obermenge von C inklusive der Gefahren dar. Aus Gewohnheit, Kompatibilitätsgründen zu vorhandenem C-Code und Systemaufrufen in C-Konvention sowie aus Bequemlichkeits- und Performancegründen wird von diesen Möglichkeiten aber nicht immer Gebrauch gemacht. Die Laufzeitüberprüfungen sind im Gegensatz zu Sprachen wie beispielsweise Pascal oder Ada nicht Bestandteil der Sprache. Sie sind meist in Form von in der Sprache selbst geschriebenen Bibliotheken verfügbar oder müssen gar vom Programmierer manuell erstellt werden, sodass sie ihrerseits aufwändig, fehleranfällig und schwieriger durch den Compiler zu unterstützen und damit oft laufzeitmäßig relativ „teuer“ sind.

Da die meisten Programmiersprachen auch Standardbibliotheken definieren, bedeutet die Wahl einer Sprache meist auch die Verwendung der entsprechenden Standardbibliotheken. Im Fall von C und C++ enthält die Standardbibliothek eine Anzahl von gefährlichen Funktionen, die zum Teil gar keine sichere Verwendung zulassen und zu denen zum Teil keine Alternativen bestehen.

Auf Programmiersprachenebene kann die Gefahr von Pufferüberläufen durch die Verwendung von Programmiersprachen, die konzeptionell moderner als C/C++ sind, verringert oder ausgeschlossen werden. Ein sehr viel geringeres Risiko besteht zum Beispiel in Programmiersprachen der Pascal-Familie Modula, Delphi oder Ada. Ausgeschlossen sind Pufferüberläufe beispielsweise in der Programmiersprache Java, da die Ausführung im Bytecode überwacht wird.

[Bearbeiten] Prozessoren und Programmierstil

Weitere Eigentümlichkeiten sowohl der Sprachen C und C++ sowie die Eigentümlichkeiten der am häufigsten eingesetzten Prozessoren machen das Auftreten von Pufferüberläufen wahrscheinlich. Die Programme in diesen Sprachen bestehen zum Teil aus Unterprogrammen. Diese Programme besitzen lokale Variablen.

Bei modernen Prozessoren ist es üblich, die Rücksprungadresse eines Unterprogramms und die lokalen Variablen auf einen als Stack bezeichneten Bereich zu legen. Dabei werden beim Unterprogrammaufruf zunächst die Rückkehradresse und danach die lokalen Variablen auf den Stack gelegt. Bei modernen Prozessoren wie dem Intel Pentium wird der Stack durch eingebaute Prozessorbefehle verwaltet und wächst zwingend nach unten. Werden Felder oder Zeichenketten in den lokalen Variablen verwendet, werden diese meist nach oben beschrieben. Wird die Feldgrenze nicht geprüft, kann man damit durch Überschreiten des Feldes die Rückkehradresse auf dem Stack erreichen und gegebenenfalls absichtlich modifizieren.

Das folgende Programmstück in C, das in ähnlicher Form oft verwendet wird, zeigt einen solchen Pufferüberlauf:

void input_line()
{   char line[1000];    // Feld ist eigentlich Zeiger
    if (gets(line))     // gets erhält Zeiger, keine Überprüfung
       parse_line(line);
}

Bei Prozessoren, die den Stack nach unten beschreiben, sieht der Stack vor dem Aufruf von gets (Funktion der Standard-Bibliothek von C) so aus:

Rücksprungadresse
1000. Zeichen
...
3. Zeichen
2. Zeichen
1. Zeichen \leftarrowStackpointer
Der Stack wächst nach unten, die Variable wird nach oben überschrieben

gets liest eine Zeile von der Eingabe und schreibt die Zeichen ab line[0] in den Stack. Es überprüft die Länge der Zeile nicht. Gemäß der Semantik von C erhält gets nur die Speicheradresse als Pointer, jedoch keinerlei Information über die verfügbare Länge. Wenn man jetzt 1004 Zeichen eingibt, überschreiben die letzten 4 Bytes die Rücksprungadresse (unter der Annahme, dass eine Adresse hier 4 Bytes groß ist), die man auf ein Programmstück innerhalb des Stack richten kann. In den ersten 1000 Zeichen kann man gegebenenfalls ein geeignetes Programm eingeben.

00@45eA/%A@4 ... ... ... ... ... ... ... ... ... ... ... ... .. 0A&%
Eingabe, wird von gets in den Stack geschrieben (1004 Zeichen)
modifizierte Rücksprungadresse
line, 1000. Zeichen
... ...
line, 5. Zeichen drittes Byte im Code
line, 4. Zeichen zweites Byte im Code
line, 3. Zeichen Ziel der Rücksprungadresse, Programmcodestart
line, 2. Zeichen
line, 1. Zeichen \leftarrowStackpointer
Überschreiben der Rücksprungadresse und Programmcode im Stack

Falls das Programm höhere Privilegien besitzt als der Benutzer, kann dieser unter Ausnutzung des Pufferüberlaufs durch eine spezielle Eingabe diese Privilegien erlangen.

[Bearbeiten] Gegenmaßnahmen

[Bearbeiten] Programmerstellung

Bei der Erstellung von Programmen sollte unbedingt auf die Überprüfung aller Feldgrenzen geachtet werden. Hier ist besonders die Verantwortung des Programmierers gefragt. Sofern keine ausreichenden Kenntnisse in der Programmierung unter hardwarenahen Sprachen vorhanden sind, sollte die Verwendung von Programmiersprachen, die automatisch Feldgrenzen überwachen, in Erwägung gezogen werden. Dies ist jedoch nicht immer möglich. Bei Verwendung von C++ sollte die Verwendung von Feldern im C-Stil soweit wie möglich vermieden werden.

void input_line()
{   char line[1000];                       // Feld ist eigentlich Zeiger
    if (fgets(line, sizeof line, stdin))   // fgets überprüft die Länge
       parse_line(line);
}
Gegenmaßnahme: fgets überprüft die Eingabelänge

[Bearbeiten] Überprüfung des Programmcodes

Spezielle Überprüfungswerkzeuge erlauben die Analyse des Codes und entdecken gegebenenfalls mögliche Schwachstellen. Allerdings kann der Code zur Feldgrenzenüberprüfung fehlerhaft sein, was oftmals nicht getestet wird.

[Bearbeiten] Unterstützung durch Compiler

In C und C++ steht eine sehr große Auswahl bestehender Programme zur Verfügung. Moderne Compiler wie neue Versionen des GNU C-Compilers erlauben die Aktivierung von Überprüfungscodeerzeugung bei der Übersetzung.

Sprachen wie C erlauben aufgrund ihres Designs nicht immer die Überprüfung der Feldgrenzen (Beispiel: gets). Die Compiler müssen andere Wege gehen: Sie fügen zwischen der Rücksprungadresse und den lokalen Variablen Platz für eine Zufallszahl ein. Beim Programmstart wird diese Zahl ermittelt, wobei sie jedes Mal unterschiedliche Werte annimmt. Bei jedem Unterprogrammaufruf wird in den dafür vorgesehen Bereich die Zufallszahl geschrieben. Der erforderliche Code wird vom Compiler automatisch generiert. Vor dem Verlassen des Programms über die Rücksprungadresse fügt der Compiler Code ein, der die Zufallszahl auf den vorgesehenen Wert überprüft. Wurde sie geändert, ist auch der Rücksprungadresse nicht zu trauen. Das Programm wird mit einer entsprechenden Meldung abgebrochen.

Rücksprungadresse
Zufallszahlbarriere
line, 1000. Zeichen
...
line, 3. Zeichen
line, 2. Zeichen
line, 1. Zeichen \leftarrowStackpointer
Gegenmaßnahme: Zufallszahlbarriere

Daneben kann man manche Compiler auch veranlassen, beim Unterprogrammaufruf eine Kopie der Rücksprungadresse unterhalb der lokalen Felder zu erzeugen. Diese Kopie wird beim Rücksprung verwendet, die Ausnutzung von Pufferüberläufen ist dann wesentlich erschwert:

Rücksprungadresse
line, 1000. Zeichen
...
line, 3. Zeichen
line, 2. Zeichen
line, 1. Zeichen
Kopie der Rücksprungadresse \leftarrowStackpointer
Gegenmaßnahme: Kopie der Rücksprungadresse

[Bearbeiten] Compiler und Compilererweiterungen

Für die GNU Compiler Collection existieren beispielsweise zwei verbreitete Erweiterungen, die Maßnahmen wie die oben beschriebenen implementieren:

  • Der Stack Smashing Protector von IBM, ehemals als ProPolice bekannt (Homepage, englisch).
  • Der Stack Guard, entwickelt an der Oregon Health and Science University, zwischenzeitlich bei der Linux-Distribution Immunix, jetzt bei Novell.

[Bearbeiten] Heap-Überlauf

Ein Heap-Überlauf ist ein Pufferüberlauf, der auf dem Heap stattfindet. Speicher auf dem Heap wird zugewiesen, wenn Programme dynamischen Speicher anfordern, etwa über malloc() oder den new-Operator in C++. Werden in einen Puffer auf dem Heap Daten ohne Überprüfung der Länge geschrieben und ist die Datenmenge größer als die Größe des Puffers, so wird über das Ende des Puffers hinausgeschrieben und es kommt zu einem Speicherüberlauf.

Durch Heap-Überläufe kann meist beliebiger Code auf dem Rechner ausgeführt werden, insbesondere wenn der Heap ausführbar ist. FreeBSD hat beispielsweise einen Heap-Schutz, hier ist dies nicht möglich. Sie können nur in Programmiersprachen auftreten, in denen bei Pufferzugriffen keine Längenüberprüfung stattfindet. C, C++ oder Assembler sind anfällig, Java oder Perl sind es nicht.

Siehe auch: Shellcode, Exploit

[Bearbeiten] Beispiel

#define BUFSIZE 128

char * copy_string(const char *s)
{
    char * buf = malloc(BUFSIZE); // Annahme: Längere Strings kommen niemals vor

    strcpy(buf, s); // Heap-Überlauf, falls strlen(s) > 127

    return buf;
}

Man sollte lieber folgendes verwenden:

char * buf;

buf = malloc(1 + strlen(s)); // Plus 1 wegen des terminierenden NUL-Zeichens
strcpy(buf, s);

Alternativ hilft auch die Verwendung des strncpy-Befehls (Kopieren von maximal n Zeichen):

char *buf;

if ((buf = malloc(BUFSIZE)) != NULL) { // Überprüfung des Zeigers
  strncpy(buf, s, BUFSIZE - 1);
  buf[BUFSIZE - 1] = '\0';  // Nachteil: Die Zeichenkette muss manuell terminiert werden.
}
return buf;

Einige Betriebssysteme, z. B. OpenBSD, bieten die Funktion strlcpy an, die ihrerseits sicherstellt, dass der Zielstring nullterminiert wird und das Erkennen eines abgeschnittenen Zielstrings vereinfacht.

[Bearbeiten] Siehe auch

[Bearbeiten] Literatur

[Bearbeiten] Weblinks

Static Wikipedia 2008 (no images)

aa - ab - af - ak - als - am - an - ang - ar - arc - as - ast - av - ay - az - ba - bar - bat_smg - bcl - be - be_x_old - bg - bh - bi - bm - bn - bo - bpy - br - bs - bug - bxr - ca - cbk_zam - cdo - ce - ceb - ch - cho - chr - chy - co - cr - crh - cs - csb - cu - cv - cy - da - de - diq - dsb - dv - dz - ee - el - eml - en - eo - es - et - eu - ext - fa - ff - fi - fiu_vro - fj - fo - fr - frp - fur - fy - ga - gan - gd - gl - glk - gn - got - gu - gv - ha - hak - haw - he - hi - hif - ho - hr - hsb - ht - hu - hy - hz - ia - id - ie - ig - ii - ik - ilo - io - is - it - iu - ja - jbo - jv - ka - kaa - kab - kg - ki - kj - kk - kl - km - kn - ko - kr - ks - ksh - ku - kv - kw - ky - la - lad - lb - lbe - lg - li - lij - lmo - ln - lo - lt - lv - map_bms - mdf - mg - mh - mi - mk - ml - mn - mo - mr - mt - mus - my - myv - mzn - na - nah - nap - nds - nds_nl - ne - new - ng - nl - nn - no - nov - nrm - nv - ny - oc - om - or - os - pa - pag - pam - pap - pdc - pi - pih - pl - pms - ps - pt - qu - quality - rm - rmy - rn - ro - roa_rup - roa_tara - ru - rw - sa - sah - sc - scn - sco - sd - se - sg - sh - si - simple - sk - sl - sm - sn - so - sr - srn - ss - st - stq - su - sv - sw - szl - ta - te - tet - tg - th - ti - tk - tl - tlh - tn - to - tpi - tr - ts - tt - tum - tw - ty - udm - ug - uk - ur - uz - ve - vec - vi - vls - vo - wa - war - wo - wuu - xal - xh - yi - yo - za - zea - zh - zh_classical - zh_min_nan - zh_yue - zu -

Static Wikipedia 2007 (no images)

aa - ab - af - ak - als - am - an - ang - ar - arc - as - ast - av - ay - az - ba - bar - bat_smg - bcl - be - be_x_old - bg - bh - bi - bm - bn - bo - bpy - br - bs - bug - bxr - ca - cbk_zam - cdo - ce - ceb - ch - cho - chr - chy - co - cr - crh - cs - csb - cu - cv - cy - da - de - diq - dsb - dv - dz - ee - el - eml - en - eo - es - et - eu - ext - fa - ff - fi - fiu_vro - fj - fo - fr - frp - fur - fy - ga - gan - gd - gl - glk - gn - got - gu - gv - ha - hak - haw - he - hi - hif - ho - hr - hsb - ht - hu - hy - hz - ia - id - ie - ig - ii - ik - ilo - io - is - it - iu - ja - jbo - jv - ka - kaa - kab - kg - ki - kj - kk - kl - km - kn - ko - kr - ks - ksh - ku - kv - kw - ky - la - lad - lb - lbe - lg - li - lij - lmo - ln - lo - lt - lv - map_bms - mdf - mg - mh - mi - mk - ml - mn - mo - mr - mt - mus - my - myv - mzn - na - nah - nap - nds - nds_nl - ne - new - ng - nl - nn - no - nov - nrm - nv - ny - oc - om - or - os - pa - pag - pam - pap - pdc - pi - pih - pl - pms - ps - pt - qu - quality - rm - rmy - rn - ro - roa_rup - roa_tara - ru - rw - sa - sah - sc - scn - sco - sd - se - sg - sh - si - simple - sk - sl - sm - sn - so - sr - srn - ss - st - stq - su - sv - sw - szl - ta - te - tet - tg - th - ti - tk - tl - tlh - tn - to - tpi - tr - ts - tt - tum - tw - ty - udm - ug - uk - ur - uz - ve - vec - vi - vls - vo - wa - war - wo - wuu - xal - xh - yi - yo - za - zea - zh - zh_classical - zh_min_nan - zh_yue - zu -

Static Wikipedia 2006 (no images)

aa - ab - af - ak - als - am - an - ang - ar - arc - as - ast - av - ay - az - ba - bar - bat_smg - bcl - be - be_x_old - bg - bh - bi - bm - bn - bo - bpy - br - bs - bug - bxr - ca - cbk_zam - cdo - ce - ceb - ch - cho - chr - chy - co - cr - crh - cs - csb - cu - cv - cy - da - de - diq - dsb - dv - dz - ee - el - eml - eo - es - et - eu - ext - fa - ff - fi - fiu_vro - fj - fo - fr - frp - fur - fy - ga - gan - gd - gl - glk - gn - got - gu - gv - ha - hak - haw - he - hi - hif - ho - hr - hsb - ht - hu - hy - hz - ia - id - ie - ig - ii - ik - ilo - io - is - it - iu - ja - jbo - jv - ka - kaa - kab - kg - ki - kj - kk - kl - km - kn - ko - kr - ks - ksh - ku - kv - kw - ky - la - lad - lb - lbe - lg - li - lij - lmo - ln - lo - lt - lv - map_bms - mdf - mg - mh - mi - mk - ml - mn - mo - mr - mt - mus - my - myv - mzn - na - nah - nap - nds - nds_nl - ne - new - ng - nl - nn - no - nov - nrm - nv - ny - oc - om - or - os - pa - pag - pam - pap - pdc - pi - pih - pl - pms - ps - pt - qu - quality - rm - rmy - rn - ro - roa_rup - roa_tara - ru - rw - sa - sah - sc - scn - sco - sd - se - sg - sh - si - simple - sk - sl - sm - sn - so - sr - srn - ss - st - stq - su - sv - sw - szl - ta - te - tet - tg - th - ti - tk - tl - tlh - tn - to - tpi - tr - ts - tt - tum - tw - ty - udm - ug - uk - ur - uz - ve - vec - vi - vls - vo - wa - war - wo - wuu - xal - xh - yi - yo - za - zea - zh - zh_classical - zh_min_nan - zh_yue - zu