Safari Books Online is a digital library providing on-demand subscription access to thousands of learning resources.
Im folgenden Abschnitt soll eine Technik beschrieben werden, mit der es möglich ist, den Adresswert einer Payload-Umgebungsvariable eindeutig zu bestimmen, so dass keinerlei NOP-Anweisungen innerhalb des Payloads mehr notwendig sind. Diese Technik beruht dabei auf der speziellen Funktionsweise der execve(3)-Bibliotheksfunktion. »When a process calls one of the exec functions, that process is completely replaced by the new program, and the new program starts executing at its main function. The process ID does not change across an exec because a new process is not created. exec merely replaces the current process (its text, data, heap, and stack stack segments) with a brand new programm from disk. [...] The two functions whose name ends in an e (execle and execve) allow us to pass a pointer to an array of pointers to the environment strings. The other four functions, however, use the environ variable in the calling process to copy the existing environment for the new programm.« (aus [STEVENS]). Es ist also möglich, die Umgebung des fehlerhaften Programmes genau zu bestimmen, wenn dieses mittels der execve(3)-Funktion durch den Exploit aufgerufen wird. Übergibt man einem fehlerhaften Programm mittels der execve(3)-Funktion beispielsweise nur eine einzelne Umgebungsvariable, in der der auszuführende Shellcode hinterlegt wird, so lässt sich dessen Adresse eindeutig bestimmen. Betrachtet man Abb. 1-1, so lässt sich der detaillierten Skizzierung des Stack-Aufbaus entnehmen, dass sich bei Linux-Systemen das obere Ende des Stacks in der Regel an der Adresse 0xc0000000 befindet. Davor (in Richtung niedrigerer Adresswerte) befindet sich die Endmarkierung des Stacks in Form eines dwords bestehend aus vier Null-Bytes. Vor der Endmarkierung ist wiederum der Name des entsprechenden Programmes abgelegt. Unmittelbar davor befinden sich dann die entsprechenden Strings der Umgebungsvariablen. Startet man nun ein Programm mittels der execve(3)- Funktion und übergibt diesem lediglich eine Umgebungsvariable, so lässt sich deren genaue Adresse durch folgende Rechnung exakt bestimmen: 0xc0000000 (oberes Stack-Ende) – sizeof (void *) (Endmarkierung des Stacks) – Länge des Namens des fehlerhaften Programms – Länge der entsprechenden Umgebungsvariable = Adresse der gesuchten Umgebungsvariable. Im Anschluss soll diese Technik anhand eines Beispiels konkretisiert werden.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int
main (int argc, char *argv[])
{
char buff[64];
if (argc < 2) {
printf ("Kein Argument!\n");
exit (EXIT_FAILURE);
}
strcpy (buff, argv[1]);
printf ("Eingabe: %s\n\n", buff);
return (EXIT_SUCCESS);
} |