Un shellcode c'est une instruction en code machine confectionnée dans le but (en général) de se faire exécuter par un programme faillible dans le but de s'augmenter en privilèges, le challenge que ça représente tient en deux choses :
-Éviter un code trop grand (qui ne laisse pas de place, lors de l'exploitation d'un buffer overflow classique à l'écrasement du pointeur d'instruction par une adresse de retour)
-Le coder de manière a n'obtenir aucun null byte (\x00) puisqu'une fois exécuté ils sont interprétés comme une fin de chaîne.
Exemple sous linux avec hello :
On récupère en premier lieu le numéro du syscall qui correspond à WRITE() , cette fonction est en fait appelée nativement par des fonctions d'affichages plus connues comme puts ou printf, je me demande aussi si elles n'agissent pas comme des wrappers au final.
Ici le numéro du syscall pour WRITE() est 4.
Ensuite on va appeler EXIT() qui a pour numéro le 1.
main:Une fois compilé :
xorl %eax,%eax
xorl %ebx,%ebx
xorl %ecx,%ecx
xorl %edx,%edx
movb $0x4,%al //syscall pour write
movb $0x1,%bl //STDOUT notre console
call afficher
push $0x6f6c6c65 //Hello world en little endian
push $0x00000068
afficher:
popl %ecx //On fait remonter la chaîne
movb $0x5,%dl //Nombre de caractères dans notre chaîne
int $0x80 //Interruption, exécution du syscall
xorl %eax,%eax
movb $0x1,%al //syscall pour exit
xorl %ebx,%ebx
int $0x80 //Interruption,exécution du syscall
xtceb@xtceb-VirtualBox:~$ ./helloworld
hello
Ce qui donne en code machine :
helloxtceb@xtceb-VirtualBox:~$ objdump -d helloworldPetit problème à l'appel de "afficher" on remarque que le call nous donne des zéros de terminaisons...
helloworld: file format elf32-i386
Disassembly of section .text:
08048054 <main>:
8048054: 31 c0 xor %eax,%eax
8048056: 31 db xor %ebx,%ebx
8048058: 31 c9 xor %ecx,%ecx
804805a: 31 d2 xor %edx,%edx
804805c: b0 04 mov $0x4,%al
804805e: b3 01 mov $0x1,%bl
8048060: e8 07 00 00 00 call 804806c <afficher>
8048065: 68 65 6c 6c 6f push $0x6f6c6c65
804806a: 6a 68 push $0x68
0804806c <afficher>:
804806c: 59 pop %ecx
804806d: b2 05 mov $0x5,%dl
804806f: cd 80 int $0x80
8048071: 31 c0 xor %eax,%eax
8048073: b0 01 mov $0x1,%al
8048075: 31 db xor %ebx,%ebx
8048077: cd 80 int $0x80
Il va falloir trouver une autre façon de coder notre hello :
main:Avec objdump :
xorl %eax,%eax
xorl %ebx,%ebx
xorl %ecx,%ecx
xorl %edx,%edx
jmp message
fin:
movb $0x4,%al
movb $0x1,%bl
popl %ecx
movb $0x5,%dl
int $0x80
xorl %eax,%eax
movb $0x1,%al
xorl %ebx,%ebx
int $0x80
message:
call fin
.string "hello"
xtceb@xtceb-VirtualBox:~$ objdump -d helloworldHop, il nous reste plus qu'à rassembler nos petites instructions machine :
helloworld: file format elf32-i386
Disassembly of section .text:
08048054 <main>:
8048054: 31 c0 xor %eax,%eax
8048056: 31 db xor %ebx,%ebx
8048058: 31 c9 xor %ecx,%ecx
804805a: 31 d2 xor %edx,%edx
804805c: eb 11 jmp 804806f <message>
0804805e <fin>:
804805e: b0 04 mov $0x4,%al
8048060: b3 01 mov $0x1,%bl
8048062: 59 pop %ecx
8048063: b2 05 mov $0x5,%dl
8048065: cd 80 int $0x80
8048067: 31 c0 xor %eax,%eax
8048069: b0 01 mov $0x1,%al
804806b: 31 db xor %ebx,%ebx
804806d: cd 80 int $0x80
0804806f <message>:
804806f: e8 ea ff ff ff call 804805e <fin>
8048074: 68 65 6c 6c 6f push $0x6f6c6c65
\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xeb\x11\xb0\x04\xb3\x01\x59\xb2\x05\xcd\x80\x31\xc0\xb0\x01\x31\xdb\xcd\x80\xe8\xea\xff\xff\xff\x68\x65\x6c\x6c\x6f
On peut dès à présent le tester pour voir si il marche :
char shellcode[]="\x31\xc0\x31\xdb\x31\xc9"
"\x31\xd2\xeb\x11\xb0\x04"
"\xb3\x01\x59\xb2\x05\xcd"
"\x80\x31\xc0\xb0\x01\x31"
"\xdb\xcd\x80\xe8\xea\xff"
"\xff\xff\x68\x65\x6c\x6c\x6f";
int main()
{
int (*func)();func = (int (*)()) shellcode;(int)(*func)();
}
xtceb@xtceb-VirtualBox:~$ ./shellcode
helloxtceb@xtceb-VirtualBox:~$
.string "c la klas!"
RépondreSupprimer