Skip to main content Link Search Menu Expand Document (external link)

Fourchette

On a reçu ce binaire de la part de Hallebarde, avec un message qui disait:
"Vous êtes tellement mauvais qu'on vous envoie un exécutable qui donne
une information si vous arrivez à le lancer comme il faut... Si vous y
arrivez !" On l'a fait tourner plein de fois sans succès. Pourriez-vous
nous dire ce qu'il cache ?

Attention ce binaire est susceptible de faire planter votre machine.
Maniez-le avec précaution !!
    
Auteur : mh4ckt3mh4ckt1c4s#0705

Catégorie: Rétro-ingénierie

Difficulté: Difficile

Aperçu

Comme le binaire est indiqué comme dangereux, on ne le lance pas. La dangerosité est probablement liée au fork() ?

On peut l’ouvrir avec Ghidra pour avoir un aperçu de son contenu, on trouve facilement la fonction main qui donne ceci dans le décompilateur:

  _Var1 = getpid();
  iVar2 = FUN_00101490(argc,argv,_Var1);
  rand();
  rand();
  do {
    _Var3 = fork();
  } while (_Var3 != 0);
  tVar4 = time(NULL);
  uVar5 = read_inutile();
  _Var3 = getpid();
  if ((_Var3 == iVar2) && ((int)uVar5 == (int)tVar4)) {
    showflag(_Var1,_Var3,(long)(int)uVar5);
    return 0;
  }
  puts("Echec...");
  sleep(1);
  local_34 = rand();
  for (local_38 = 0; local_38 < 100000; local_38 = local_38 + 1) {
    local_34 = FUN_00101420();
  }
                    // WARNING: Subroutine does not return
  exit(local_34);

Et la fonction showflag (facile à identifier par son printf):

  n2_ = n2;
  n1_ = n1;
  local_c = param_1;
  puts(s_Succ_s_!_00102004);
  buf = calloc(8,1);
  A = (n2_ / 100000) * 10000000000;
  B = (long)(n1_ * 1000000);
  C = n2_ - A / 100000;
  local_40 = A + B + C;
  for (i = 0; i < 6; i = i + 1) {
    *(char *)((long)buf + (long)i) = (char)(local_40 >> ((5 - (char)i) * 8 & 63U));
  }
  memcpy(flag,ENCRYPTED_FLAG,44);
  i_ = 0;
  while( true ) {
    flag_len = strlen((char *)flag);
    if (flag_len <= (ulong)(long)i_) break;
    for (j = 0; j < 1341; j = j + 3) {
      flag[i_] = flag[i_] ^ *(byte *)((long)buf + (long)(i_ % 6));
    }
    i_ = i_ + 1;
  }
  printf("Flag : %s\n",flag);
  free(buf);
  sleep(1);
  kill(local_c,9);
  return;

Analyse du code

La fonction showflag semble assez simple: elle opère un XOR sur un flag chiffré présent dans le programme, via une certain clé de 6 octets.

Chaque XOR est fait 1341 / 3 = 447 fois: il suffit de le faire une fois.

On a donc un flag chiffré en XOR avec un clé de 6 octets à trouver.

Le flag chiffré est:

2060 [0]            FF, BD, D2, 5B
2064 [4]            1D, CD, D9, EF
2068 [8]            93, 45, 59, DC
206c [12]           D9, E8, B3, 1C
2070 [16]           0D, 9A, E8, CE
2074 [20]           F5, 53, 6E, D7
2078 [24]           E6, EA, 87, 77
207c [28]           51, 9D, F8, C5
2080 [32]           D5, 18, 4F, E5
2084 [36]           D8, C5, FD, 18
2088 [40]           53, 91, D6, 00

Solution

Puisque les flags sont de la forme 404CTF{..} il suffit de faire apparaître 404CTF:

enc = bytes.fromhex("""
ffbdd25b 1dcdd9ef 934559dc d9e8b31c
0d9ae8ce f5536ed7 e6ea8777 519df8c5
d5184fe5 d8c5fd18 5391d6
""")

stub = b"404CTF"

for i in range(30):
    key = [enc[i + (j - i % 6) % 6] ^ stub[(j - i % 6) % 6] for j in range(6)]
    print(i, bytes(key))
    print(bytes(b ^ key[i % 6] for i, b in enumerate(enc)))

On obtient immédiatement la solution:

15 b'\xab\x9a\xb3(=\xae'
b"T'as cru mdrrr\x00404CTF{SyMp4_l3S_f0rKs_N0n?}"

Note

Le reste du code implémentait en réalité une logique cachée permettant de déterminer la clé, vous la trouverez dans les autres write-ups.