OVH Cloud OVH Cloud

shellcoding

20 réponses
Avatar
DeLeTe
Salut je voudrais pouvoir créer un shellcode pour freebsd .
Donc je commence par desassembler mon fichier ce qui me donne:
bash-2.05b$ objdump -d hello

hello: file format elf32-i386-freebsd

Disassembly of section .text:

08048080 <msg>:
8048080: 48 dec %eax
8048081: 65 gs
8048082: 6c insb (%dx),%es:(%edi)
8048083: 6c insb (%dx),%es:(%edi)
8048084: 6f outsl %ds:(%esi),(%dx)
8048085: 2c 20 sub $0x20,%al
8048087: 77 6f ja 80480f8 <_start+0x67>
8048089: 72 6c jb 80480f7 <_start+0x66>
804808b: 64 21 0a and %ecx,%fs:(%edx)

0804808e <_syscall>:
804808e: cd 80 int $0x80
8048090: c3 ret

08048091 <_start>:
8048091: 68 0e 00 00 00 push $0xe
8048096: 68 80 80 04 08 push $0x8048080
804809b: 68 01 00 00 00 push $0x1
80480a0: b8 04 00 00 00 mov $0x4,%eax
80480a5: e8 e4 ff ff ff call 804808e <_syscall>
80480aa: 81 c4 0c 00 00 00 add $0xc,%esp
80480b0: 68 00 00 00 00 push $0x0
80480b5: b8 01 00 00 00 mov $0x1,%eax
80480ba: e8 cf ff ff ff call 804808e <_syscall>
bash-2.05b$

Donc mon programme c'est un simple hello world:
bash-2.05b$ ./hello
Hello, world!
bash-2.05b$

Prochaine etape je veux donc créer le shellcode ce qui me donne:
bash-2.05b$ cat shellcode.c
char codeshell[] =
"\x68\x0e\x00\x00\x00\x68\x80\x80\x04\x08\x68\x01\x00\x00\x00\xb8\x04\x00\x00\x00\xe8\xe4\xff\xff\xff\x81\xc4\x0c\x00\x00\x00\x68\x00\x00\x00\x00\xb8\x01\x00\x00\x00\xe8\xcf\xff\xff\xff";

int main()
{
int *ret;
*((int *)&ret+2)=(int)codeshell;
}
bash-2.05b$ gcc shellcode.c -o shellcode
bash-2.05b$ ./shellcode
Segmentation fault (core dumped)
bash-2.05b$

Voila :(
Je me suis surement trompé pour recuperer le code hexa mais je ne sais pas
trop où ?

Il semblerait que j'ai pris des instructions en trop car:
bash-2.05b$ gdb shellcode
GNU gdb 5.2.1 (FreeBSD)
Copyright 2002 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain
conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-undermydesk-freebsd"...
(no debugging symbols found)...
(gdb) r
Starting program: /usr/home/delete/programmation/asm/shellcode/shellcode
(no debugging symbols found)...(no debugging symbols found)...
Program received signal SIGSEGV, Segmentation fault.
0x080495bd in p.0 ()
(gdb) core shellcode.core
A program is being debugged already. Kill it? (y or n) y

Core was generated by `shellcode'.
Program terminated with signal 11, Segmentation fault.
Symbols already loaded for /usr/lib/libc.so.5
Symbols already loaded for /usr/libexec/ld-elf.so.1
#0 0x080495bd in p.0 ()
(gdb)

--
Les seuls limites que nous avons sont celles que nous nous imposons !!!

10 réponses

1 2
Avatar
pornin
According to DeLeTe :
08048091 <_start>:
8048091: 68 0e 00 00 00 push $0xe
8048096: 68 80 80 04 08 push $0x8048080
804809b: 68 01 00 00 00 push $0x1
80480a0: b8 04 00 00 00 mov $0x4,%eax
80480a5: e8 e4 ff ff ff call 804808e <_syscall>


Ceci est un appel système de type write(), avec comme arguments
les valeurs 1 (c'est le file descriptor, ici la sortie standard),
0x08048080 (l'adresse des données à écrire) et 14 (le nombre d'octets
à écrire, correspondant à la taille de "Hello, world!n" [sans le 0
terminal, bien sûr]).

80480aa: 81 c4 0c 00 00 00 add $0xc,%esp


Ensuite, l'appelant enlève les arguments (les trois "push" ci-dessus).

80480b0: 68 00 00 00 00 push $0x0
80480b5: b8 01 00 00 00 mov $0x1,%eax
80480ba: e8 cf ff ff ff call 804808e <_syscall>


Puis il fait l'appel système de type _exit(), avec comme argument 0
(le code de retour).


Pour que tout ça fonctionne, il faut qu'il y ait effectivement la chaîne
de caractères "Hello World!n" en mémoire à l'adresse 0x08048080. Dans
votre autre programme, il y a des chances pour qu'à cette adresse il n'y
ait rien, d'où segfault lors de l'accès.

Si vous voulez vraiment jouer à faire de l'assembleur, il va falloir
apprendre à faire de l'assembleur. Ça ne s'improvise pas.


--Thomas Pornin

Avatar
Ducrot Bruno
On Thu, 27 Nov 2003 08:29:11 +0000 (UTC), Thomas Pornin wrote:
According to DeLeTe :
08048091 <_start>:
8048091: 68 0e 00 00 00 push $0xe
8048096: 68 80 80 04 08 push $0x8048080
804809b: 68 01 00 00 00 push $0x1
80480a0: b8 04 00 00 00 mov $0x4,%eax
80480a5: e8 e4 ff ff ff call 804808e <_syscall>


Ceci est un appel système de type write(), avec comme arguments
les valeurs 1 (c'est le file descriptor, ici la sortie standard),
0x08048080 (l'adresse des données à écrire) et 14 (le nombre d'octets
à écrire, correspondant à la taille de "Hello, world!n" [sans le 0
terminal, bien sûr]).


Non. Pas du tout. C'est un appel a une fonction. Le fait que
la fonction fasse par la suite un int 80h afin d'effectuer
le syscall est un autre debat.

Pour que tout ça fonctionne, il faut qu'il y ait effectivement lachaîne
de caractères "Hello World!n" en mémoire à l'adresse 0x08048080. Dans
votre autre programme, il y a des chances pour qu'à cette adresse il n'y
ait rien, d'où segfault lors de l'accès.


Oh! S'il n'y avait que cela... Je crains tout d'abord que le le simple
fait d'avoir un tableau global qui va contenir le code a executer soit
une mauvaise idee (ca doit se trouver dans une zone memoire marquee non
executable).

Si vous voulez vraiment jouer à faire de l'assembleur, il va falloir
apprendre à faire de l'assembleur. Ça ne s'improvise pas.


--
Ducrot Bruno.

-- Which is worse: ignorance or apathy?
-- Don't know. Don't care.


Avatar
pornin
According to Ducrot Bruno :
Non. Pas du tout. C'est un appel a une fonction. Le fait que
la fonction fasse par la suite un int 80h afin d'effectuer
le syscall est un autre debat.


Oops, pardon, en effet. Je vais trop vite. Mais on peut néanmoins
constater que l'adresse dans un "call" est relative, et que la fonction
_syscall en question est dans les trois octets précédents. Aussi, il
suffirait de rajouter ces trois octets au début pour que l'appel système
se fasse effectivement. L'adresse passée en paramètre sera quand même
invalide.


Oh! S'il n'y avait que cela... Je crains tout d'abord que le le simple
fait d'avoir un tableau global qui va contenir le code a executer soit
une mauvaise idee (ca doit se trouver dans une zone memoire marquee non
executable).


Les PC ont tendance à ne pas savoir distinguer la lecture de l'exécution
pour ce qui est des protections. Certains OS arrivent à rendre la
pile non exécutable avec une magouille sur les registres de segment
(la pile est dans un espace bien séparé) mais ça ne concerne pas les
tableaux globaux ; il y a aussi une technique pour avoir un vrai droit
d'exécution page par page indépendant du droit en lecture, mais elle a
un coût non négligeable à l'exécution, aussi je ne pense pas qu'elle
soit implémentée dans FreeBSD (on peut voir une description et des
patchs pour Linux là : http://pageexec.virtualave.net/). Donc, sur un
FreeBSD classique, un tableau global devrait être exécutable.


--Thomas Pornin

Avatar
Julien Bordet
Les PC ont tendance à ne pas savoir distinguer la lecture de l'exécution
pour ce qui est des protections. Certains OS arrivent à rendre la
pile non exécutable avec une magouille sur les registres de segment
(la pile est dans un espace bien séparé) mais ça ne concerne pas les
tableaux globaux ; il y a aussi une technique pour avoir un vrai droit


Dans OpenBSD, sur les architectures i386, on a effectivement ce qu'ils
appellent un W^X (ou exclusif entre les droits d'écrire et les droits
d'exécution).

Ceci est fait à nouveau avec une bidouille de segments, à savoir qu'on
prend une limite arbitraire dans l'adressage virtuel du processeur, et
on dit qu'en dessous de cette limite, on est en droit R|X (read et
exécute), et qu'au dessus, on est en R|W.

Le gros défaut de cette méthode est qu'on perd pas mal d'adressage, et
donc qu'on est pénalisé lorsque le système dispose de pas mal de RAM
effectivement.


Julien

Avatar
manu
Julien Bordet wrote:

Dans OpenBSD, sur les architectures i386, on a effectivement ce qu'ils
appellent un W^X (ou exclusif entre les droits d'écrire et les droits
d'exécution).


FWIW, NetBSD le fait aussi.

--
Emmanuel Dreyfus
A lire: 240 pages en français sur l'administration UNIX avec BSD
http://www.eyrolles.com/php.informatique/Ouvrages/9782212112443.php3


Avatar
Julien Bordet
FWIW, NetBSD le fait aussi.

Ouais, mais c'est nous qu'on était les premiers ;)


Avatar
manu
Julien Bordet wrote:

FWIW, NetBSD le fait aussi.
Ouais, mais c'est nous qu'on était les premiers ;)



Comme homo habilis qui etait là avant homo sapiens? >o)

--
Emmanuel Dreyfus
Un bouquin en français sur BSD:
http://www.eyrolles.com/php.informatique/Ouvrages/9782212112443.php3



Avatar
Miod Vallat
Dans OpenBSD, sur les architectures i386, on a effectivement ce qu'ils
appellent un W^X (ou exclusif entre les droits d'écrire et les droits
d'exécution).


FWIW, NetBSD le fait aussi.


FWIW rien du tout.

On en a déja parlé ici meme, et je reste sur ma position décrite en
(également disponible en
http://groups.google.fr/groups?selm=slrnbqhoh7.jrc.miod%40vetre.gentiane.org

Y a-t-il eu du nouveau depuis ?


Avatar
Ducrot Bruno
On Fri, 28 Nov 2003 18:31:33 +0000 (UTC), Thomas Pornin wrote:
According to Ducrot Bruno :
Non. Pas du tout. C'est un appel a une fonction. Le fait que
la fonction fasse par la suite un int 80h afin d'effectuer
le syscall est un autre debat.


Oops, pardon, en effet. Je vais trop vite. Mais on peut néanmoins
constater que l'adresse dans un "call" est relative, et que la fonction
_syscall en question est dans les trois octets précédents. Aussi, il
suffirait de rajouter ces trois octets au début pour que l'appel système
se fasse effectivement. L'adresse passée en paramètre sera quand même
invalide.


Oh! S'il n'y avait que cela... Je crains tout d'abord que le le simple
fait d'avoir un tableau global qui va contenir le code a executer soit
une mauvaise idee (ca doit se trouver dans une zone memoire marquee non
executable).


Les PC ont tendance à ne pas savoir distinguer la lecture de l'exécution
pour ce qui est des protections. Certains OS arrivent à rendre la
pile non exécutable avec une magouille sur les registres de segment
(la pile est dans un espace bien séparé) mais ça ne concerne pas les
tableaux globaux ; il y a aussi une technique pour avoir un vrai droit
d'exécution page par page indépendant du droit en lecture, mais elle a
un coût non négligeable à l'exécution, aussi je ne pense pas qu'elle
soit implémentée dans FreeBSD (on peut voir une description et des
patchs pour Linux là : http://pageexec.virtualave.net/). Donc, sur un
FreeBSD classique, un tableau global devrait être exécutable.



Ah. J'etais pourtant persuade que .data serait marque non-executable
pour les 386 sous Free. Merci de ta precision.

--
Ducrot Bruno.

-- Which is worse: ignorance or apathy?
-- Don't know. Don't care.


Avatar
manu
Miod Vallat wrote:

[NetBSD et W^X]
FWIW rien du tout.

On en a déja parlé ici meme, et je reste sur ma position décrite en
(également disponible en
http://groups.google.fr/groups?selm=slrnbqhoh7.jrc.miod%40vetre.gentiane.org

Y a-t-il eu du nouveau depuis ?


Il le fait pour la pile, ce qui est de loin le plus souvent exploité.
Pour le tas ca n'est pas encore fait, Chuck y travaille justement en ce
moment (cf posts sur tech-kern). Comment on exploite un buffer overflow
de tas, au fait?

--
Emmanuel Dreyfus
Publicité subliminale: achetez ce livre!
http://www.eyrolles.com/php.informatique/Ouvrages/9782212112443.php3


1 2