what you don't know can hurt you
Home Files News &[SERVICES_TAB]About Contact Add New

how-to-create-shellcode.txt

how-to-create-shellcode.txt
Posted Jul 8, 2010
Authored by Jonathan Salwan | Site shell-storm.org

Whitepaper called How to create a shellcode on Linux / x86.

tags | paper, x86, shellcode
systems | linux
SHA-256 | be8ad7a3a06855a46d70be336cf0396e40311d917b41a72c66e17cc4f8048afc

how-to-create-shellcode.txt

Change Mirror Download
  Title:    How to create a shellcode on Linux x86 ?
Author: Jonathan Salwan <submit ! shell-storm.org>
Web: http://www.shell-storm.org/ | http://twitter.com/shell_storm
Date: 2010-05-30
Language: French

Original version: http://howto.shell-storm.org/files/howto-1.php




I - Présentation des shellcodes
===============================

Un shellcode est une chaîne de caractères qui représente un code binaire exécutable capable de lancer
n'importe quelle application sur la machine. La plupart du temps un shellcode ouvre un shell pour
avoir un accès complet sur la machine. Généralement, les shellcodes sont injectés dans la mémoire de
la machine via l'exploitation d'une faille type dépassement de tampon (buffer overflow).


II - Comprendre les bases
=========================

1 - Les appels systèmes

Un appel système (en anglais, system call, abrégé en syscall) est une fonction fournie par le noyau
d'un système d'exploitation. Suivant les Os nos syscall seront appelés différemment.

Exemple d'appel système fréquemment utilisé:
open, write, read, close, chmod, chown ...

Sur la majorité des systèmes d'exploitations, les appels système peuvent être utilisés comme de
simples fonctions écrites en C. Par exemple pour l'appel système chown:

extern int chown (__const char *__file, __uid_t __owner, __gid_t __group)

Chaque appel système à une adresse, qui est attribuée par le système d'exploitation et qui lui est
propre. Par exemple sous linux avec le kernel 2.6.31 l'adresse du syscall chown est 0xb6.
Comment connaître cette adresse ? Une simple commande comme ci-dessous permet d'avoir l'adresse
du syscall. Les adresses dans unistd_x.h sont en decimales.


Pour un système 32 bits

jonathan@archlinux [ shellcode ]# cat /usr/include/asm/unistd_32.h | grep chown
#define __NR_lchown 16
#define __NR_fchown 95
#define __NR_chown 182
#define __NR_lchown32 198
#define __NR_fchown32 207
#define __NR_chown32 212
#define __NR_fchownat 298


Pour un système 64 bits

jonathan@archlinux [ shellcode ]# cat /usr/include/asm/unistd_64.h | grep chown
#define __NR_chown 92
__SYSCALL(__NR_chown, sys_chown)
#define __NR_fchown 93
__SYSCALL(__NR_fchown, sys_fchown)
#define __NR_lchown 94
__SYSCALL(__NR_lchown, sys_lchown)
#define __NR_fchownat 260
__SYSCALL(__NR_fchownat, sys_fchownat)


Comme vous pouvez le constater, si l'os est sous 32 ou 64 bits, l'adresse des syscalls change.



III - Ecrire son premier shellcode
==================================

En premier lieu nous allons créer un shellcode simple, qui va nous permettre d'effectuer une pause.
Pour ça nous allons appeler la fonction _pause dont l'adresse est 29 ce qui donne 0x1d en hexadecimal
(sous 32 bits).


jonathan@archlinux [ ~ ]$ cat /usr/include/asm/unistd_32.h | grep pause
#define __NR_pause 29


Une fois qu'on connait l'adresse du syscall, il nous reste plus qu'à connaître, ce qu'on doit mettre
dans les registres.
Pour cela référez vous à cette page => http://www.shell-storm.org/shellcode/files/syscalls.html

Nous pouvons constater que pour _pause nous n'avons pas besoin de remplir les registres, juste un
appel suffit, ce qui va donc est très court à programmer.


jonathan@archlinux [ shellcode ]$ cat pause.s
xor %eax,%eax
mov $29,%al
int $0x80
jonathan@archlinux [ shellcode ]$ as -o pause.o pause.s
jonathan@archlinux [ shellcode ]$ ld -o pause pause.o
ld: warning: cannot find entry symbol _start; defaulting to 08048054
jonathan@archlinux [ shellcode ]$ ./pause
^C
jonathan@archlinux [ shellcode ]$


Expliquation
============

xor %eax,%eax <= On met le registre eax à 0 pour éviter les segments faults
mov $29,%al <= On place 29 (l'adresse du syscall) dans le registre al
int $0x80 <= On exécute


Maintenant nous allons l'écrire C. Pour cela nous devons connaître l'équivalence des fonctions asm en
hexadecimales ce qui va par la suite être notre shellcode.

Comment avoir les équivalences en hexadecimal ?
C'est simple, nous utilisons tout simplement l'outil objdump, ce qui donne:


jonathan@archlinux [ shellcode ]$ objdump -d ./pause

pause: file format elf32-i386


Disassembly of section .text:

08048054 <.text>:
8048054: 31 c0 xor %eax,%eax
8048056: b0 1d mov $0x1d,%al
8048058: cd 80 int $0x80
jonathan@archlinux [ shellcode ]$


Et voilà, donc en C le code sera:


jonathan@archlinux [ shellcode ]$ cat pause_c.c
#include<stdio.h>

void main(void)
{
char shellcode[] = "\x31\xc0\xb0\x1d\xcd\x80";

(*(void(*)()) shellcode)();

}
jonathan@archlinux [ shellcode ]$ gcc -o pause_c pause_c.c
jonathan@archlinux [ shellcode ]$ ./pause_c
^C
jonathan@archlinux [ shellcode ]$

Votre premier shellcode fonctionne correctement.

Maintenant nous allons étudier la fonction _write. Référons nous encore au site que j'ai soumis
plus haut.

Info registre:
==============
%eax = 4
%ebx = unsigned int
%ecx = const char *
%edx = size


Nous allons tous simplement écrire jonathan, regardons ce que donne les sources:

jonathan@ArchLinux [shellcode]$ cat write.s
;_write
xor %eax,%eax <= Pour éviter les segmentfaults
xor %ebx,%ebx <= // //
xor %ecx,%ecx <= // //
xor %edx,%edx <= // //

movb $0x9,%dl <= on place la taille de notre mot dans dl(edx) donc jonathan + \n | 8+1=9
pushl $0x0a <= on commence à empiler notre line feed (\n) = 0x0a
push $0x6e616874 <= naht
push $0x616e6f6a <= onaj
movl %esp,%ecx <= on envoie %esp dans %ecx le registre qui contient la constante char de _write
movb $0x1,%bl <= ici 1 pour %ebx,
movb $0x4,%al <= et ici le syscall de _write donc 4
int $0x80 <= on exécute

;_exit
xor %ebx,%ebx <= %ebx = 0
movb $0x1,%al <= %eax = 1 (syscall de _exit)
int $0x80 <= on exécute


Compilons et exécutons notre programme:

jonathan@ArchLinux [shellcode]$ as -o write.o write.s
jonathan@ArchLinux [shellcode]$ ld -o write write.o
ld: warning: cannot find entry symbol _start; defaulting to 08048054
jonathan@ArchLinux [shellcode]$ ./write
jonathan
jonathan@ArchLinux [shellcode]$

Ecrivons notre shellcode en C pour cela, un petit objdump sera utile.

jonathan@ArchLinux [shellcode]$ objdump -d write

write: file format elf32-i386


Disassembly of section .text:

08048054 <.text>:
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: b2 09 mov $0x9,%dl
804805e: 6a 0a push $0xa
8048060: 68 74 68 61 6e push $0x6e616874
8048065: 68 6a 6f 6e 61 push $0x616e6f6a
804806a: 89 e1 mov %esp,%ecx
804806c: b3 01 mov $0x1,%bl
804806e: b0 04 mov $0x4,%al
8048070: cd 80 int $0x80
8048072: 31 db xor %ebx,%ebx
8048074: b0 01 mov $0x1,%al
8048076: cd 80 int $0x80
jonathan@ArchLinux [shellcode]$

On retrouve bien à droite les sources de notre code en asm puis l'équivalence des instructions en
hexadecimal.

jonathan@ArchLinux [shellcode]$ cat write_c.c
#include <stdio.h>

void main(void)
{
char shellcode[] = "\x31\xc0\x31\xdb\x31\xc9"
"\x31\xd2\xb2\x09\x6a\x0a"
"\x68\x74\x68\x61\x6e\x68"
"\x6a\x6f\x6e\x61\x89\xe1"
"\xb3\x01\xb0\x04\xcd\x80"
"\x31\xdb\xb0\x01\xcd\x80";

fprintf(stdout,"Lenght: %d\n",strlen(shellcode));
(*(void(*)()) shellcode)();
}

Compilons et exécutons notre shellcode.

jonathan@ArchLinux [shellcode]$ gcc -o write_c write_c.c
jonathan@ArchLinux [shellcode]$ ./write_c
Lenght: 36
jonathan
jonathan@ArchLinux [shellcode]$

Et voila cela fonctionne parfaitement. Shellcode _write(1,"jonathan\n",9) + _exit(0) pour une taille de 36 bytes.



IV - Références
===============

[x] - http://www.shell-storm.org

[1] - http://fr.wikipedia.org/wiki/Shellcode

[2] - /usr/include/asm/unistd_32.h

Login or Register to add favorites

File Archive:

April 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Apr 1st
    10 Files
  • 2
    Apr 2nd
    26 Files
  • 3
    Apr 3rd
    40 Files
  • 4
    Apr 4th
    6 Files
  • 5
    Apr 5th
    26 Files
  • 6
    Apr 6th
    0 Files
  • 7
    Apr 7th
    0 Files
  • 8
    Apr 8th
    22 Files
  • 9
    Apr 9th
    14 Files
  • 10
    Apr 10th
    10 Files
  • 11
    Apr 11th
    13 Files
  • 12
    Apr 12th
    14 Files
  • 13
    Apr 13th
    0 Files
  • 14
    Apr 14th
    0 Files
  • 15
    Apr 15th
    30 Files
  • 16
    Apr 16th
    10 Files
  • 17
    Apr 17th
    22 Files
  • 18
    Apr 18th
    45 Files
  • 19
    Apr 19th
    8 Files
  • 20
    Apr 20th
    0 Files
  • 21
    Apr 21st
    0 Files
  • 22
    Apr 22nd
    11 Files
  • 23
    Apr 23rd
    68 Files
  • 24
    Apr 24th
    23 Files
  • 25
    Apr 25th
    16 Files
  • 26
    Apr 26th
    0 Files
  • 27
    Apr 27th
    0 Files
  • 28
    Apr 28th
    0 Files
  • 29
    Apr 29th
    0 Files
  • 30
    Apr 30th
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close