2008/07/20

Principes et mise en oeuvre d'un injection de code dans un processus en cours via le syscall PTRACE()

Yop all o/ !
Comme vous l'aurez sans doute compris dans le titre , cet article va traiter (pas trés original comme sujet j'en conviens) des injections de Shellcode dans un processus actif grace au syscall Ptrace() .

Commençons donc par une petite explication et mise en situation :

<--------------------------------------------->
Avant tout un petit mot sur l'environnement de test utilisé ici :
# uname -a
Linux localhost 2.6.22.19-desktop-2mdv #1 SMP Mon May 5 20:55:05 EDT 2008 i686 Intel(R) Pentium(R) 4 CPU 2.93GHz GNU/Linux
Le tout sans aucune modifications ,attention toutefois car il est ici nécéssaire de posséder une pile exécutable ( on joue encore une fois avec la stack ) bien qu'en y réfléchissant longuement , il peu etre possible de l'adapté sur n'importe quel OS ( d'aprés ce que j'ai pu lire sur phrack ;-) ) .
<--------------------------------------------->
-Il faut savoir que ce type d'injection est souvent utilisée par les codes malveillants afin de contourner les sécuritées mise en place sur une machine .

exemple :
Imaginons un poste de travail "sécurisé " par un firewall personnel ; en général ces programmes ont pour but de filtrer/bloquer l'accés au net pour certaines applications.
Cependant , supposons que nous voulions compromettre cette machine et faire en sorte d'obtenir un accés sortant (on peu tout aussi bien vouloir faire autre chose , mais ceci est a titre d'exemple hein ;-) ) , dans ce cas comment vas-t-on s'y prendre ..?

Sachant qu'au minimum le navigateur doit posséder un accés sortant , nous allons donc injecter notre shellcode dans la mémoire utilisée par ce processus puis faire en sorte qu'il poursuive son activité , comme si de rien n'était .
De cette façon nous pouvons utiliser les droits du navigateur et,donc avoir un accés sortant sans etre inquiété !

Pour cela il sera donc nécessaire de ne pas tuer le processus en fesant donc en sorte qu'une fois le pointeur EIP pointe sur le shellcode , l'exécute puis se replace (POP / RET) de façon a reprendre l'exécution du processus cible.

Etapes a suivre :
1- S'attacher au processus ciblé (PTRACE_ATTACH)

2-Attendre qu'il stoppe (WAITPID)

3-Récupération des registres utilisés par ce process(PTRACE_GETREGS)

4-Copie du Shellcode dans la stack (PTRACE_POKEDATA)

5-Redirection du pointeur vers le début de nore Shellcode (PTRACE_SETREGS)

6-Se détacher (PTRACE_DETACH)

Néanmoins,, il se peut que le processus ait été interrompu par le ptrace (PTRACE_ATTACH) alors qu’il exécuté un appel système.
Dans ce cas, le noyau décide de remettre l’ex écution a l’endroit ou elle a été interrompue, c’est-a-dire l’appel système. Sous Linux pour x86, un appel système est déclenché́ par l’instruction int 0x80, codée sur 2 octets.
Avant de rendre la main au processus, le noyau modifie donc le registre eip, en lui enlevant 2 octets. Or, nous ne souhaitons pas que l’exé́cution reprenne la ou ne se trouve pas notre shellcode!
Pour compenser cela, on ajoutera 2 Nops (\x90) au début du shellcode (et on oublira pas de modifier la valeur dans la boucle au passage sinon elle n'enverra pas tout le shellcode ).

Voila, on peu désormais passer a la pratique .Dans un premier temps je détaillerais donc les différentes étapes , puis je vous donnerais le code "Shell_inj" (Shellcode injector quoi -_- ) .
(Ce code est déja suffisemment commenté pour vous permettre de le comprendre facilement)

-- Nous allons , dans l'exemple suivant , injecter un dangereux shellcode (Hello , world! :-) ) dans un processus cible (ici bash sera la cible) -

On commence par récupérer son PID:
[kmkz@localhost Bureau]$ ps aux
Ce qui donnera un listing assez long (top pour etre mis ici en entier en tout cas ) .
Nous , on s'intéressera donc a ça :
kmkz 7178 0.3 0.1 4324 1920 pts/0 Ss+ 10:58 0:00 bash
Bon , on a le PID reste plus qu'a s'amuser now ! \o/
Je suppose que vous savez déja utiliser Gcc et donc ne reviendrais pas la dessus ..
Lançons le programme Shell_inj en lui passant en argument notre PID et voyons ce qui se passe :

[kmkz@localhost Bureau]$ ./inj 7178
[+] Attente d'attachement au processus 7178 ...
[+] Attachement au processus : réussi
[+] Lecture des registres:
-eip: 0xffffe410
-esp: 0xbfe478d8
[+] Shellcode copié en esp:0xbfe468d8
[+] Redirection d'eip vers le shellcode :0xbfe468da
[+] Détachement du processus 7178

[+] Injection Terminée !
Hello,World !

Bingo, notre "hello world" est bien la , en chair et en os (enfin si on veux quoi ^_^).
C'est a vous de jouer maintenant : vous savez détourner un processus en y injectant un shellcode pour en faire ce que vous voulez alors ....
___
*Here's the Shell_inj source code:
Shell_inj.c

Have Fun !

Remerciements a l'équipe de "blacks clowns" pour son article sans lequel j'aurai mis des mois avant de percuter comment m'y prendre ^^ ainsi qu'a l'équipe de dg-sc pour phrack et ses tutos de 1er choix !

3 commentaires:

Anonyme a dit…

C'est sympa mais t'en connais beaucoups des firewalls personnels sous Linux qui risquent de bloquer de maniere intempestive comme ca ? :))

Disons que les injections de code via ptrace() c'est bien pour faire un rootkit userland ou cacher une backdoor en memoire d'un autre process que l'admin n'aura peut-etre pas l'idee d'aller tuer

Et si le process qu'on infecte verifie un ptrace(PTRACE_TRACEME, 0, 0, 0) < 0 ?
Je taquine, bon article ;)

kmkz a dit…
Ce commentaire a été supprimé par l'auteur.
kmkz a dit…

Arf..Ce n'est ici qu'un exemple hein ;-) .
En tout cas merci pour la critique , elle est la bienvenue tant qu'elle est constructive et permet de rajouter ici un point important .

Puis comme tu l'as dis :

"Disons que les injections de code via ptrace() c'est bien pour faire un rootkit userland ou cacher une backdoor en memoire d'un autre process que l'admin n'aura peut-etre pas l'idee d'aller tuer"

Ben en voila une idée qu'elle est bonne \o/ pourquoi pas ce serait une exploitation intéréssante ça !
Et quand a l'admin qui n'aurais pas l'idée de tuer le process , encore faut-il qu'il le tue ,c'est clair .. .
a +