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:

November 2024

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

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2024 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close