Bufferoverloop

Uit Wikipedia, de vrije encyclopedie
Ga naar: navigatie, zoeken

Een bufferoverloop (Engels: buffer overflow) is een foutief gedrag van een computerprogramma dat probeert data te schrijven in een tijdelijke gegevensruimte, maar buiten de grenzen van deze buffer schrijft. Dit veroorzaakt doorgaans onvoorspelbare problemen in de werking van het programma, tenzij de bufferoverloop nauwkeurig wordt ontworpen om een bepaald effect te bereiken.

Fouten in zulke programma's, bovendien nog meer in het geval van besturingssystemen, worden soms misbruikt door wormen, virussen en hackers om ongeoorloofde toegang te krijgen tot computersystemen.

Geschiedenis[bewerken]

Een van de eerste teksten over de bufferoverloop, "Smashing the stack for fun and profit", werd geschreven door Aleph One, in het E-zine Phrack. Hierin wordt uitgelegd hoe men in een slecht geschreven C-programma de buffer kan laten overlopen en de controle over het programma kan overnemen door het manipuleren van de stack.

Implicaties[bewerken]

Een bufferoverloop zorgt ervoor dat er gegevens worden overschreven die niet overschreven mogen worden, voornamelijk het return-adres. In het beste geval leidt dit tot een programmacrash, in het slechtste geval tot een overname door het programma door iets dat gegevens levert aan het programma. Het is daarom belangrijk programma's te maken die geen bufferoverloop veroorzaken.

Oorzaken[bewerken]

De oorzaak van een bufferoverloop kan het best weergegeven worden met een stukje voorbeeldcode in C:

#include <stdio.h>

int main (int argc, char *argv[])
{
    char grote_buffer [1024]; // buffer van 1024 bytes
    gets(grote_buffer);       // verkrijg string van toetsenbord
    overloop(grote_buffer);   // roep kwetsbare functie aan
    return 0;
}

int overloop(char *groot)
{
    char kwetsbaar[100];      // overlopende buffer [100 bytes]
    strcpy(kwetsbaar,groot);  // kopieer grote_buffer naar kwetsbaar
    return 0;                 // verlaat functie
}


Bovenstaand stuk code voert de volgende acties uit:

  1. Lees toetsenbordinvoer in grote_buffer
  2. Roep functie overloop
  3. Kopieer invoer naar kwetsbaar (100 bytes)
  4. Verlaat functie
  5. Verlaat programma

De fout ligt bij stap 3. Omdat grote_buffer groter is dan kwetsbaar, zal bij het kopiëren het stuk van grote_buffer dat niet in kwetsbaar past achter kwetsbaar geschreven worden. Dit valt alleen te merken als de toetsenbordinvoer groter dan 100 bytes is.

Omdat kwetsbaar geen globale variabele is wordt deze op de stack opgeslagen. En achter kwetsbaar staat daar het terugkeeradres van functie overloop. Dit is een getal dat aangeeft waarnaar moet worden teruggekeerd als de functie is afgelopen. Door het terugkeeradres te overschrijven kan dus het programmaverloop aangepast worden. Als men bijvoorbeeld 200 a's invoert zal geprobeerd worden terug te springen naar adres 0x61616161 (61 is de hexadecimale weergave van "a").

Misbruik[bewerken]

Om succesvol misbruik van een bufferoverloop te maken moet er eigen code worden uitgevoerd, soms het 'egg' (ei) genoemd. Deze code kan bijvoorbeeld in de toetsenbordinvoer zitten. Het is echter moeilijk de locatie van de invoer op de stack te bepalen. Hiervoor is echter een oplossing: na de terugkeer van de functie bevat de stack pointer (esp) het adres na waar het terugkeeradres stond. Als je dus de code na het terugkeeradres plaatst, en het terugkeeradres naar een jmp esp/call esp laat wijzen, zal de code uitgevoerd worden.

Criteria waaraan moet worden voldaan[bewerken]

Het terugkeeradres moet natuurlijk wel op de juiste plek staan. Het makkelijkste is om een rij opvolgende tekens te gebruiken (abcdefg...) en dan te kijken waarnaartoe wordt teruggekeerd. Ook moet de code natuurlijk wel iets zinnigs uitvoeren; het gebruikelijkste is een zogenaamde shellcode die de exploiter een commandline-interface biedt om het systeem te besturen.

Het terugkeeradres en de shellcode mogen beide niet de getallen 0x00, 0x0A, 0x0C en 0x1A bevatten, omdat het kopiëren van tekenreeksen hier stopt.

Voorkomen[bewerken]

Een bufferoverloop is te voorkomen door de maximumlengte van de te kopiëren tekenreeksen te controleren alvorens data te schrijven.

Zie ook[bewerken]