Si ma mémoire est bonne, il s’agit de la préqual RCE100. Plusieurs corrections ont déjà été données comme ici ou . Il s’agissait en pratique d’attaquer un logiciel qui faisait une validation off-line d’un mot de passe pour l’utiliser ensuite à distance.

Sauf que souvent, alors que l’on part obviously sur un bon brute-force, j’ai vu beaucoup de solutions commencer par réimplémenter l’algorithme en C[1]. Certaines personnes font cela vite et bien, mais je serais le premier à me gauffrer[2]. Du coup je pars pour la méthode la plus directe, prendre la routine désassemblée et l’injecter directement dans le programme ad hoc.

Le listing suivant m’a presque été offert sur un plateau, tout du moins l’exécutable une fois extrait de son packer et la bonne adresse.

  • listing: Désassemblage de la routine de compression
  41ec50:	51                   	push   %ecx
  41ec51:	53                   	push   %ebx
  41ec52:	8b cf                	mov    %edi,%ecx
  41ec54:	56                   	push   %esi
  41ec55:	be ef be ad de       	mov    $0xdeadbeef,%esi
  41ec5a:	33 d2                	xor    %edx,%edx
  41ec5c:	8d 59 01             	lea    0x1(%ecx),%ebx
  41ec5f:	90                   	nop
  41ec60:	8a 01                	mov    (%ecx),%al
  41ec62:	83 c1 01             	add    $0x1,%ecx
  41ec65:	84 c0                	test   %al,%al
  41ec67:	75 f7                	jne    0x41ec60
  41ec69:	2b cb                	sub    %ebx,%ecx
  41ec6b:	74 32                	je     0x41ec9f
  41ec6d:	8d 49 00             	lea    0x0(%ecx),%ecx
  41ec70:	0f be 04 3a          	movsbl (%edx,%edi,1),%eax
  41ec74:	69 f6 06 16 27 38    	imul   $0x38271606,%esi,%esi
  41ec7a:	69 c0 fe af 86 5b    	imul   $0x5b86affe,%eax,%eax
  41ec80:	2b c6                	sub    %esi,%eax
  41ec82:	8b cf                	mov    %edi,%ecx
  41ec84:	8b f0                	mov    %eax,%esi
  41ec86:	83 c2 01             	add    $0x1,%edx
  41ec89:	8d 41 01             	lea    0x1(%ecx),%eax
  41ec8c:	8d 64 24 00          	lea    0x0(%esp),%esp
  41ec90:	8a 19                	mov    (%ecx),%bl
  41ec92:	83 c1 01             	add    $0x1,%ecx
  41ec95:	84 db                	test   %bl,%bl
  41ec97:	75 f7                	jne    0x41ec90
  41ec99:	2b c8                	sub    %eax,%ecx
  41ec9b:	3b d1                	cmp    %ecx,%edx
  41ec9d:	72 d1                	jb     0x41ec70
  41ec9f:	8b c6                	mov    %esi,%eax
  41eca1:	5e                   	pop    %esi
  41eca2:	5b                   	pop    %ebx
  41eca3:	59                   	pop    %ecx
  41eca4:	c3                   	ret 
 

À l’aide d’un peu de sed/awk, on traite cette sortie pour pouvoir l’intégrer dans un asm volatile. Plusieurs choses auxquelles on fait attention:

  • la syntaxe;
  • les arguments, ici edi sert à pointer vers la chaîne à compresser et eax le résultat;
  • les sauts, l’adressage est ici absolu dans l’espace virtuel du coup il faut les convertir en relatif.

L’alphabet utilisé a été construit en regardant le clavier, tout simplement. Pour la suite, on insère cela dans huit boucles, on rajoute quelques printf pour suivre le déroulement et on lance.

  • listing: Programme utilisé pour trouver la solution
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
 
int main (int argc, char * argv [])
{
	char pwd [9];
	pwd [0] = pwd [1] = pwd [2] = pwd [3] = pwd [4] = pwd [5] = pwd [6] = pwd [7] = pwd [8] = '\0';
	int i0, i1, i2, i3, i4, i5, i6, i7;
	char * printable = "1234567890azertyuiopqsdfghjklmwxcvbnAZERTYUIOPQSDFGHJKLMWXCVBN,?;.:/!§%$£=+&#{}()[]<>-|\\@ ";
	int plen = strlen (printable);
	int res;
 
	for (i7 = 0; i7 < plen; i7++)
	{			printf ("O"); fflush (0);
	for (i6 = 0; i6 < plen; i6++)
	{
	for (i5 = 0; i5 < plen; i5++)
	{			printf ("o"); fflush (0);
	for (i4 = 0; i4 < plen; i4++)
	{
	for (i3 = 0; i3 < plen; i3++)
	{			printf ("."); fflush (0);
	for (i2 = 0; i2 < plen; i2++)
	{
	for (i1 = 0; i1 < plen; i1++)
	{
	for (i0 = 0; i0 < plen; i0++)
	{
 
__asm__ __volatile__ (
"\n  push   %%ecx"
"\n  push   %%ebx"
"\n  mov    %%edi,%%ecx"
"\n  push   %%esi"
"\n  mov    $0xdeadbeef,%%esi"
"\n  xor    %%edx,%%edx"
"\n  lea    0x1(%%ecx),%%ebx"
"\n  nop"
"\nlbl0x41ec60:"
"\n  mov    (%%ecx),%%al"
"\n  add    $0x1,%%ecx"
"\n  test   %%al,%%al"
"\n  jne    lbl0x41ec60"
"\n  sub    %%ebx,%%ecx"
"\n  je     lbl0x41ec9f"
"\n  lea    0x0(%%ecx),%%ecx"
"\nlbl0x41ec70:"
"\n  movsbl (%%edx,%%edi,1),%%eax"
"\n  imul   $0x38271606,%%esi,%%esi"
"\n  imul   $0x5b86affe,%%eax,%%eax"
"\n  sub    %%esi,%%eax"
"\n  mov    %%edi,%%ecx"
"\n  mov    %%eax,%%esi"
"\n  add    $0x1,%%edx"
"\n  lea    0x1(%%ecx),%%eax"
"\n  lea    0x0(%%esp),%%esp"
"\nlbl0x41ec90:"
"\n  mov    (%%ecx),%%bl"
"\n  add    $0x1,%%ecx"
"\n  test   %%bl,%%bl"
"\n  jne    lbl0x41ec90"
"\n  sub    %%eax,%%ecx"
"\n  cmp    %%ecx,%%edx"
"\n  jb     lbl0x41ec70"
"\nlbl0x41ec9f:"
"\n  mov    %%esi,%%eax"
"\n  pop    %%esi"
"\n  pop    %%ebx"
"\n  pop    %%ecx"
: "=a" (res) : "D" (pwd));
 
	if (res == 0xc4b1801c)
		printf ("[candidat '%s' (%u) Ok!]", pwd, res);
 
//		printf ("[%s] %i %i %i %i %i %i %i %i \n", pwd, i0, i1, i2, i3, i4, i5, i6, i7);
 
		pwd [0] = printable [i0];
	}
		pwd [1] = printable [i1];
	}
		pwd [2] = printable [i2];
	}
		pwd [3] = printable [i3];
	}
		pwd [4] = printable [i4];
	}
		pwd [5] = printable [i5];
	}
		pwd [6] = printable [i6];
	}
		pwd [7] = printable [i7];
	}
 
	return 0;
}

Je sais plus quelle était la solution. ;)

Notes

[1] j’ai même vu faire en C++

[2] surtout en situation de compétition