Wissen | Was ist ein Buffer Overflow?

von Thomas


Erstellt am 23.07.2022


SO-DIMM

In diesem Artikel vermittel ich euch umfassendes Wissen zum Buffer Overflow. Ein Buffer Overflow ist eine Sicherheitslücke, mit der auf Arbeitsspeicher lesend oder schreibend zugegriffen werden kann, der für das ausführende Programm eigentlich abgeschottet sein sollte.

Speicherverwaltung Betriebssysteme

In modernen Betriebssystemen hat sich die virtuelle Speicherverwaltung durchgesetzt. Dabei ist es üblich, dass einem Prozess durch eine Memory Management Unit (MMU) der virtuelle Speicher, welcher größer als der physikalisch vorhandene Speicher sein kann, zugewiesen wird. Für den ausgeführten Prozess ist der virtuell zur Verfügung stehende Speicher ein logisch zusammenhängender physikalischer Speicher. Physikalisch sind die Speicherräume aber alles andere als beieinander, wodurch es zu Fehlern kommen kann, wenn ein Prozess außerhalb seines von der MMU zugewiesenen Speicher schreibt oder liest - der Buffer Overflow. Die häufigste Variante sind heutzutage der Stack-Buffer Overflow und Heap-Buffer Overflow.

Speicherverwaltung bei modernen Computern
Speicherverwaltung bei modernen Computern

Wie kommt es zu einem Buffer Overflow?

Computersysteme sind meist so komplex aufgebaut, dass ein Prozess diverse Unterprogramme aufruft. Nach dem Aufruf, benötigt der Programmcode die eigentliche Rücksprungadresse, wo das Programm vor dem Unterprogramm-Aufruf weiter ausgeführt werden soll. Bei geschickter Wahl des Eingabestroms, welcher von einem Unterprogramm unter Umständen benötigt wird, kann die Rücksprungadresse gezielt überschrieben werden. Ist das einem Angreifer gelungen, ermöglicht dieses Vorgehen möglicherweise Shellcode auszuführen.

Buffer Overflow führt Shellcode aus
Quelle: https://www.acunetix.com/blog/web-security-zone/what-is-buffer-overflow/

Eine weitere fatale Möglichkeit ist, dass Passwörter durch einen Buffer Overflow überschrieben werden können.

Buffer Overflow
Durch mangelnde Längenüberprüfung kann in beispielsweise C außerhalb des vorgesehnen Speichers geschrieben werden.

Das gezeigte Bild kann ganz einfach mit folgendem C-Code selbst getestet werden. Achtet darauf, beim compilieren mit gcc die Option, -fno-stack-protector zu verwenden. Denn der gcc verhindert solche simplenen Buffer Overflow mittlerweile:

#include 
#include 

int main(void)
{
    /* Der Buffer für das Passwort wird auf sechs Zeichen festgelegt */
    char buffer[6];
    /* Die Variable wird unmittelbar nach dem Buffer auf den Stack gelegt */
    int pass = 0;

    printf("Password eingeben : \n");
    gets(buffer);

    if(strcmp(buffer, "secret"))
    {
        printf ("Falsches Password \n");
    }
    else
    {
        printf ("Password korrekt \n");
        pass = 1;
    }

    if(pass)
    {
        printf ("Hallo Root User \n");
    }

    return 0;
}

Dadurch, dass die Variable pass unmittelbar nach dem buffer definiert wird, liegt sie auch unmittelbar nach dem buffer auf dem Stack. Werden nun sieben Zeichen eingegeben überschreibt das siebte Zeichen die Variable pass auf dem Stack. Durch Längenüberprüfung der Eingabe von gets lässt sich das Problem vermeiden.

Buffer Overflow Beispiel
Das Programm akzeptiert jedes Passwort, was länger als sechs Zeichen ist.

Gegenmaßnahmen Buffer Overflow

Die NIST schreibt in Ihrem Report von 2011, dass die meisten Systeme auf Grund der schlechten Implementierungsphase unsicher sind. So sind laut dem Bericht die meisten Sicherheitslücken auf die Programmiersprachen C,C++ und Java zurückzuführen. Die Programmiersprachen bringen zwar Vorteile mit sich, da sie hardwareorientiert und in Bezug auf die Laufzeit mit zu den schnellsten Programmiersprachen gehören. Der Nachteil ist, dass die manuelle Verwaltung des Arbeitsspeichers Aufgabe der Programmierer ist und teilweise schlecht beziehungsweise gar nicht implementiert wird. Aus diesen Gründen kann bereits die Wahl der Programmiersprache, welche für das Softwaresystem genutzt werden soll, die Sicherheit signifikant erhöhen oder verschlechtern. Ein positiv Beispiel sind die Sprachen Ada, C# und Rust, welche Typensicherheit gewährleisten und bei der Speicherverwaltung auf syntaktische und semantische Prüfung setzten Dadurch ist kein Buffer Overflow möglich. Anzumerken ist, dass die Sicherheitsmechanismen bewusst von Programmieren umgangen werden können und dann keinen entsprechenden Schutz mehr bieten.