Solution de botanicmagic pour Guessy

intro reverse linux x86/x64

3 janvier 2025

Outil utilisé pour ce challenge : Cutter

Avant d’aller plus loin, il faut connaître le fonctionnement des décalages (opérateur pour la gauche : <<) et de XOR (opérateur ^).

Commençons par la fonction main :

int32_t main (void) {
    puts ("Give me the flag:");
    rax = s;
    // récupère l'entrée utilisateur
    fgets (rax, 0x20, *(stdin));
    rax = s;
    rdi = rax;
    // appel la fonction validate()
    validate ();
    eax = 0;
    return rax;
}

Voici la fonction validate :

int64_t validate (void) {
    *(var_10h) = rdi;
    // 1er caractère de chaine utilisateur
    rax = *(var_10h);
    // eax contient le 1er caractère
    eax = *(rax);
    if (al == 0x46) { // si le caractère est 'F'
        rax = *(var_10h);
        rax++; // incrémente la position pour le caractère suivant
        eax = *(rax);
        if (al != 0x43) { // si le caractère est différent de 'C', tchao
            goto label_0;
        }
        // 1er caractère de chaine utilisateur
        rax = *(var_10h);
        // avance de 2 caractères
        rax += 2;
        eax = *(rax); 
        if (al != 0x53) { // si le caractère est différent de 'S', tchao
            goto label_0;
        }
        rax = *(var_10h);
        // avance de 3 caractèes
        rax += 3; 
        eax = *(rax);
        if (al == 0x43) { // s'il est égal à 'C', on passe à la suite
            goto label_1;
        }
    }
label_0:
    puts ("Well it does not begin well for you.");
    goto label_2;
label_1:
    rax = *(var_10h);
    // on avance de 4 caractères
    rax += 4;
    eax = *(rax);
    if (al != 0x7b) { // si le caractère est différent de '{'
        puts ("Come on, it's not that difficult !");
    } else {
        puts ("Ok so I see we have an understanding. Let's begin the difficult part now.");
        eax = 0;
        // appel à la fonction difficult_part()
        difficult_part ();
        eax = 0;
    }
label_2:
    return rax;
}

Donc la chaine de caractères attendue dans cette première partie est :

FCSC{

Maintenant, analysons la fonction difficult_part :

uint64_t difficult_part (void) {
    puts ("Now you can try to guess the next eight characters of the flag.");
    rax = s;
    // récupère l'entrée utilisateur
    fgets (rax, 0x10, *(stdin));
    rax = s;
    rdi = rax;
    rax = strlen ();
    // si la taille est différente de 9 caractères (8 + '\n' à cause de fgets)
    if (rax != 9) {
        puts ("Well it seems that someone has trouble counting to eight.");
    } else {
        // 1er caractères de la nouvelle chaine utilisateur
        eax = *(s);
        // si le premier caractère est 'e'
        if (al == 0x65) {
            // pointe sur le caractère suivant
            eax = *((s + 0x1));
            // si le caractère est différent de '7', tchao
            if (al != 0x37) {
                goto label_0;
            }
            // incrémente la position
            eax = *((s + 0x2));
            // si le caractère à cette position est différent de '5', tchao
            if (al != 0x35) {
                goto label_0;
            }
            // incrémente la position
            eax = *((s + 0x3));
            // si le caractère à cette position est différent de '5', tchao
            if (al != 0x35) {
                goto label_0;
            }
            eax = *((s + 0x4));
            // si le caractère à cette position est différent de '2', tchao
            if (al != 0x32) {
                goto label_0;
            }
            eax = *((s + 0x5));
            // si le caractère à cette position est différent de 'c', tchao
            if (al != 0x63) {
                goto label_0;
            }
            eax = *((s + 0x6));
            // si le caractère à cette position est différent de 'f', tchao
            if (al != 0x66) {
                goto label_0;
            }
            eax = *((s + 0x7));
            // si le caractère à cette position est différent de '6', tchao
            if (al == 0x36) {
                goto label_1;
            }
            // ====================> e7552cf6 <============================
        }
label_0:
        puts ("Wrong guess.");
        goto label_2;
label_1:
        puts ("Well done, you can try to guess the next eight characters but it won't be so easy.");
        rax = s;
        fgets (rax, 0x10, *(stdin));
        rax = s;
        rdi = rax;
        rax = strlen ();
        if (rax != 9) {
            puts ("Well it seems that someone has trouble counting to eight.");
        } else {
            eax = *(s);
            // eax contient la valeur ordinale du caractère
            eax = (int32_t) al;
            // que l'on double
            eax += eax;
            // si le premier caractère est '4' (0x68 / 2 = 0x34)
            if (eax == 0x68) {
                // incrémente la position du pointeur
                eax = *((s + 0x1));
                // récupère le caractère de la nouvelle position
                eax = (int32_t) al;
                // multiplié par 2
                eax += eax;
              	// si le caractère est différent de 'c' (0xc6 / 2 = 0x63), tchao
                if (eax != 0xc6) {
                    goto label_3;
                }
                eax = *((s + 0x2));
                eax = (int32_t) al;
                eax += eax;
              	// si le caractère est différent de 'e' (0xca / 2 = 0x65), tchao
                if (eax != 0xca) {
                    goto label_3;
                }
                eax = *((s + 0x3));
                eax = (int32_t) al;
                eax += eax;
              	// si le caractère est différent de '2' (0x64 / 2 = 0x32), tchao
                if (eax != 0x64) {
                    goto label_3;
                }
                eax = *((s + 0x4));
                eax = (int32_t) al;
                eax += eax;
              	// si le caractère est différent de 'e', tchao
                if (eax != 0xca) {
                    goto label_3;
                }
                eax = *((s + 0x5));
                eax = (int32_t) al;
                eax += eax;
              	// si le caractère est différent de '5', tchao
                if (eax != 0x6a) {
                    goto label_3;
                }
                eax = *((s + 0x6));
                eax = (int32_t) al;
                eax += eax;
              	// si le caractère est différent de 'a', tchao
                if (eax != 0xc2) {
                    goto label_3;
                }
                eax = *((s + 0x7));
                eax = (int32_t) al;
                eax += eax;
              	// si le caractère est 'd', on passe à la suite
                if (eax == 0xc8) {
                    goto label_4;
                }
                // ===============> 4ce2e5ad <=================
            }
label_3:
            puts ("Wrong guess.");
            goto label_2;
label_4:
            puts ("I see you've got some skills in reversing, but can you guess the next eight ?");
            rax = s;
            fgets (rax, 0x10, *(stdin));
            rax = s;
            rdi = rax;
            rax = strlen ();
            if (rax != 9) {
                puts ("Well it seems that someone has trouble counting to eight.");
            } else {
                eax = *(s);
                eax = (int32_t) al;
              	// la valeur ordinale du 1er caractère est multipliée par 8 (2^3, (décalage de 3 bits vers la gauche)
                eax <<= 3;
                // si le caractère est égal à '0' (0x180 / 8 = 0x30 = '0')
                if (eax == 0x180) {
                    eax = *((s + 0x1));
                    eax = (int32_t) al;
                    eax <<= 3;
                    // si le caractère est différent de 'b', tchao
                    if (eax != 0x310) {
                        goto label_5;
                    }
                    eax = *((s + 0x2));
                    eax = (int32_t) al;
                    eax <<= 3;
                    // si le caractère est différent de 'b', tchao
                    if (eax != 0x310) {
                        goto label_5;
                    }
                    eax = *((s + 0x3));
                    eax = (int32_t) al;
                    eax <<= 3;
                    // si le caractère est différent de '0', tchao
                    if (eax != 0x180) {
                        goto label_5;
                    }
                    eax = *((s + 0x4));
                    eax = (int32_t) al;
                    eax <<= 3;
                    // si le caractère est différent de '9', tchao
                    if (eax != 0x1c8) {
                        goto label_5;
                    }
                    eax = *((s + 0x5));
                    eax = (int32_t) al;
                    eax <<= 3;
                    // si le caractère est différent de '5', tchao
                    if (eax != 0x1a8) {
                        goto label_5;
                    }
                    eax = *((s + 0x6));
                    eax = (int32_t) al;
                    eax <<= 3;
                    // si le caractère est différent de '4', tchao
                    if (eax != 0x1a0) {
                        goto label_5;
                    }
                    eax = *((s + 0x7));
                    eax = (int32_t) al;
                    eax <<= 3;
                    // si le caractère est 'f', on passe à la suite
                    if (eax == 0x330) {
                        goto label_6;
                    }
                    // =================> 0bb0954f <==================
                }
label_5:
                puts ("Wrong guess.");
                goto label_2;
label_6:
                puts ("I must say that I'm impressed but it's not over. Will you be able to guess the next eight characters ?");
                rax = var_28h;
                fgets (rax, 0x10, *(stdin));
                rax = var_28h;
                rdi = rax;
                rax = strlen ();
                if (rax != 9) {
                    puts ("Well it seems that someone has trouble counting to eight.");
                } else {
                    // s est la dernière chaine entrée par l'utilisateur "0bb0954f", donc ici '0'
                    edx = *(s);
                    // 1er caractère de la nouvelle chaine utilisateur
                    eax = *(var_28h);
                    // eax XOR edx
                    eax ^= edx;
                    // si eax XOR edx = 1 (car test ci-dessous al == 1), alors eax = edx ^ 0x1 = 0x30 ^ 0x1 = 0x31 = '1'
                    // donc si le caractère est '1'
                    if (al == 1) {
                      	// incrémente la position dans edx (chaine "0bb0954f", donc on va pointer sur 'b' = 0x62)
                        edx = *((s + 0x1));
                      	// incrémentation de la position de la dernière chaine utilisateur
                        eax = *((var_28h + 0x1));
                      	// eax XOR edx
                        eax ^= edx;
                      	// ici, le test al != 0x54 induit que eax XOR edx = 0x54 
                      	// d'où eax = 0x62 XOR 0x54 = 0x36 (correspond au caractère '6')
                      	// donc si le caractère est différent de '6', tchao
                        if (al != 0x54) {
                            goto label_7;
                        }
                        edx = *((s + 0x2)); // 3ème caractère de "0bb0954f" : 'b' = 0x62
                        eax = *((var_28h + 0x2));
                        eax ^= edx;
                      	// 0x62 XOR 0x55 = 0x37 = '7'
                      	// si le caractère est différent de '7', tchao
                        if (al != 0x55) {
                            goto label_7;
                        }
                        edx = *((s + 0x3)); // 4ème caractère de "0bb0954f" : '0' = 0x30
                        eax = *((var_28h + 0x3));
                        eax ^= edx;
                      	// 0x30 XOR 0x51 = 0x61, donc si le caractère est différent de 'a', tchao
                        if (al != 0x51) {
                            goto label_7;
                        }
                        edx = *((s + 0x4)); // '9' = 0x39
                        eax = *((var_28h + 0x4));
                        eax ^= edx; // 0x39 XOR 0x9 = 0x30
                      	// si le caractère est différent de '0', tchao
                        if (al != 9) {
                            goto label_7;
                        }
                        edx = *((s + 0x5)); // '5' = 0x35
                        eax = *((var_28h + 0x5));
                        eax ^= edx; // 0x35 XOR 0x7 = 0x32
                      	// si le caractère est différent de '2', tchao
                        if (al != 7) {
                            goto label_7;
                        }
                        edx = *((s + 0x6)); // '4' = 0x34
                        eax = *((var_28h + 0x6));
                        eax ^= edx; // 0x34 XOR 0x57 = 0x63
                      	// si le caractère est différent de 'c', tchao
                        if (al != 0x57) {
                            goto label_7;
                        }
                        edx = *((s + 0x7)); // 'f' = 0x66
                        eax = *((var_28h + 0x7));
                      	// si le caractère est 'f', on passe à la suite
                        if (dl == al) {
                            goto label_8;
                        }
                      	// ================> 167a02cf <================
                    }
label_7:
                    puts ("Wrong guess");
                    goto label_2;
label_8:
                    puts ("Alright, now let's go to the most difficult part of this challenge.");
                    eax = 0;
                    most_difficult_part ();
                    eax = 0;
                }
            }
        }
    }
label_2:
    return rax;
}

Maintenant, passons à la fonction most_difficult_part :

uint64_t most_difficult_part (void) {
    puts ("Can you guess the LAST character of the flag ?");
    rax = s;
    fgets (rax, 0x10, *(stdin));
    rax = s;
    rdi = rax;
    rax = strlen ();
    if (rax != 2) {
        puts ("Really ? I ask you for a single character and you give me this ?");
    } else {
        eax = *(s);
      	// si le caractère n'est pas '}', tchao
        if (al != 0x7d) {
            puts ("Oh no, you were so close !");
        } else {
            puts ("Congratulations, you've guessed the flag !");
            eax = 0;
        }
    }
    return rax;
}

Donc en combinant les différentes chaînes calculées, on en déduit le flag :

FCSC{e7552cf64ce2e5ad0bb0954f167a02cf}
$ ./guessy
Give me the flag:
FCSC{
Ok so I see we have an understanding. Let's begin the difficult part now.
Now you can try to guess the next eight characters of the flag.
e7552cf6
Well done, you can try to guess the next eight characters but it won't be so easy.
4ce2e5ad
I see you've got some skills in reversing, but can you guess the next eight ?
0bb0954f
I must say that I'm impressed but it's not over. Will you be able to guess the next eight characters ?
167a02cf
Alright, now let's go to the most difficult part of this challenge.
Can you guess the LAST character of the flag ?
}
Congratulations, you've guessed the flag !