Rien d'extraordinaire, juste un ELF 32 bits strippé :
$ file crackme1 crackme1: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.16, stripped
On ouvre le binaire dans IDA puis on appuis sur F5
pour le decompiler Après avoir modifié les types de certaines variable et les avoir renommer on a un code qui ressemble à ça :
int __cdecl main(int argc, char **argv) { const char *good_pass; // ebx@10 const char *retour; // eax@10 const char *bad_good; // eax@11 signed int v6; // [sp+8h] [bp-2Ch]@0 int v7; // [sp+Ch] [bp-28h]@0 if ( !getuid() || !geteuid() ) { puts("you're mine :)"); v7 = 0; v6 = 19088743; reboot(4276215469); } if ( argc != 2 ) { printf("usage: %s <password>\n", *argv, v6, v7); exit(1); } if ( strlen(argv[1]) != 11 ) { puts(off_804A048); exit(1); } good_pass = s2; retour = (const char *)sub_80485DC((char **)argv[1]); if ( strcmp(retour, good_pass) ) bad_good = off_804A048; else bad_good = goodboy[0]; puts(bad_good); return 0; }
Première information : le flag fait 11 caractères. On remarque un appel à la fonction sub_80485DC
avec en paramètre notre password. Le retour de cette fonction est comparé via strcmp
avec une valeur contenue dans le programme : \x3E\x5F\x1A\x3B\x53\x52\x30\x35\x13\x09\x1E\x00
.
Regardons de plus prêt ce que fait la fonction sub_80485DC
.
void *__cdecl sub_80485DC(char *arg) { char *retour; // [sp+18h] [bp-10h]@1 signed int i; // [sp+1Ch] [bp-Ch]@1 retour = (char *)calloc(1u, 0xCu); for ( i = 0; i <= 2; ++i ) *(_DWORD *)&retour[4 * i] = *(_DWORD *)&arg[4 * i] ^ *(_DWORD *)&goodboy[0][4 * i]; return retour; }
Notre input est xoré avec la chaine Good boy :)
. Il suffit de xorer la chaîne contenue dans le programme avec Good boy :)
et le tour est joué !
def xor(chaine, key): ret = "" for i in range(len(chaine)): ret += chr(ord(chaine[i]) ^ ord(key[i%len(key)])) return ret print xor("\x3E\x5F\x1A\x3B\x53\x52\x30\x35\x13\x09\x1E", "Good boy :)")
$ python xor.py && ./crackme1 $(python xor.py) y0u_s0_L337 Good boy :)