Résolution de défis SSHCTF en ingénierie inverse

0x01 Vérifiez votre IDA

Concept clé : Utilisation basique d'IDA Pro

Pour résoudre ce défi, ouvrez le fichier dans IDA, accédez à la fenêtre des fonctions, recherchez la fonction main, puis appuyez sur F5 pour générer le pseudo-code. Le flag y est directement visible.

0x02 Baby XOR

Concept clé : Opération XOR

Pas de protection anti-débogage. Chargez le binaire dans IDA, localisez la fonction main et décompilez-la. Examinez les variables pour identifier la clé et les données chiffrées.

La clé aSshctfX0rKey contient la chaîne 'sshctf&X0R_key', et le tableau byte_40B040 contient des valeurs hexadécimales. Le programme applique une opération XOR avec un décalage supplémentaire pour les indices pairs.

Voici une implémentation C++ alternative pour décoder le flag :

#include <iostream>
#include <string>

int main() {
    int donnees[] = {50, 32, 50, 32, 50, 32, 79, 1, 77, 39, 18, 0, 71, 23, 22, 44, 34, 83, 20, 57, 5, 43, 125, 38, 37, 14, 40, 27, 4, 0, 14, 60, 35, 60, 107, 42, 71, 36, 40, 25, 4, 72, 15, 20, 7};
    int cle[] = {115, 115, 104, 99, 116, 102, 38, 88, 48, 82, 95, 107, 101, 121};
    int taille_donnees = sizeof(donnees) / sizeof(donnees[0]);
    int taille_cle = sizeof(cle) / sizeof(cle[0]);
    std::string resultat;

    for (int i = 0; i < taille_donnees; ++i) {
        if (i % 2 == 0) {
            donnees[i] ^= 0x12;
        }
        donnees[i] ^= cle[i % taille_cle];
        resultat += static_cast<char>(donnees[i]);
    }

    std::cout << resultat << std::endl;
    return 0;
}

Exécution du code produit le flag : SSHCTF{You_k0nw_X0r_1s_the_best_EZ_revers1ng}.

0x03 Baby Crack

Concept clé : Décalage de bits et opérations bit à bit

Le binaire est analysé dans IDA. La fonction sub_401550 génère une séquence de nombres pseudo-aléatoires à partir de la graine 0xDEADBEEF. Les opérations incluant des décalages et des XOR avec la clé SSHCTFkey.

Pour reproduire les nombres aléatoires, utilisez ce code C :

#include <stdio.h>
#include <stdlib.h>

int main() {
    unsigned int graine = 0xDEADBEEF;
    srand(graine);
    for (int i = 0; i < 37; ++i) {
        printf(",%u", rand() % 255);
    }
    return 0;
}

Résultat obtenu : 232,90,117,135,98,176,175,24,8,123,84,245,112,135,139,71,23,72,4,144,110,181,55,140,156,151,75,136,53,253,7,32,95,73,116,219,63.

Ensuite, déchiffrez le tableau byte_40F040 avec ce script Python modifié :

cle = "SSHCTFkey"
chiffre = [201, 34, 74, 60, 108, 98, 249, 249, 111, 177, 146, 73, 118, 241, 190, 203, 137, 113, 40, 169, 115, 82, 249, 180, 94, 254, 243, 132, 199, 61, 235, 137, 117, 190, 106, 61, 19, 125]
cle_numerique = [ord(c) for c in cle]
aleatoire = [232, 90, 117, 135, 98, 176, 175, 24, 8, 123, 84, 245, 112, 135, 139, 71, 23, 72, 4, 144, 110, 181, 55, 140, 156, 151, 75, 136, 53, 253, 7, 32, 95, 73, 116, 219, 63]

for i in reversed(range(37)):
    alea_val = aleatoire[i]
    temp = chiffre[i] ^ ((i & 0x12) | (cle_numerique[i % len(cle_numerique)] & 0x3F))
    if ((alea_val & temp) | ~(alea_val | temp) | 7) > 63:
        chiffre[i] = temp
    chiffre[i] ^= chiffre[i + 1]
    decalage = cle_numerique[alea_val % len(cle_numerique)] % 8
    chiffre[i] = (chiffre[i] >> (8 - decalage)) | (chiffre[i] << decalage) & 0xFF

print("".join(chr(v) for v in chiffre))

Exécution donne le flag : SSHCTF{N0w_y0u_Kn0w_B1twise_op3r@t0rs}.

0x04 Apprenons la cryptographie

Concept clé : Chiffrement AES et encodage Base64

Le binaire contient une clé 9e015a9f82d367bc et une chaîne encodée en Base64. La fonction Cry_Encrypt utilise AES en mode ECB pour chiffrer le flag.

Pour déchiffrer, utilisez ce script Python avec la bibliothèque pycryptodome :

from Crypto.Cipher import AES
import base64

cle_aes = b'9e015a9f82d367bc'
chiffre_base64 = 'KKN+NK5ZWN4xr4kM1+qq+2wJKUEEaiWmITgnvi2VaXfjscLoN2sbUObWbnc45pZr'
donnees_chiffrees = base64.b64decode(chiffre_base64)
decrypteur = AES.new(cle_aes, AES.MODE_ECB)
flag_dechiffre = decrypteur.decrypt(donnees_chiffrees)
print(flag_dechiffre)

Le flag obtenu est SSHCTF{Crypt0_1n_R3v3rs3_1s_so000oo0_Imp0rt@nt!}.

0x05 Code auto-modifiant (SMC)

Concept clé : Self-Modifying Code

Dans IDA, la fonciton sub_140001280 utilise VirtualProtect pour modifier le code à l'exécution. Placez un point d'arrêt après l'appel à VirtualProtect, puis recompilez la section 0x1400011C0 à 0x14000127E dans le débogueur.

Après recompilation, la fonction révèle une opération XOR avec 0x23. Décodez la chaîne chiffrée :

chiffre = b'EOBDXZFP|V|GL|JW^'
print("".join(chr(b ^ 0x23) for b in chiffre))

Résultat : flag{yes_u_do_it}.

0x06 Labyrinthe

Concept clé : Résolution de labyrinthe

Le programme contient un tableau représentant trois labyrinthes de 15x15. Les valeurs 0, 1, 3, 4 indiquent obstacles, chemins, position actuelle et sortie. Les contrôles sont w (haut), s (bas), a (gauche), d (droite).

Pour le premier labyrinthe, le chemin est ddsssddddsssdss, pour le second dddddsssddddsssaassssddds, et pour le troisième ddssddwddssssssdddssssdddss.

Le flag est le hash MD5 de la concaténation des chemins. Calculez-le avec :

import hashlib

chemin1 = 'ddsssddddsssdss'
chemin2 = 'dddddsssddddsssaassssddds'
chemin3 = 'ddssddwddssssssdddssssdddss'
chemins = chemin1 + chemin2 + chemin3
hash_md5 = hashlib.md5(chemins.encode('utf-8')).hexdigest()
print(f'SSHCTF{{{hash_md5}}}')

Le flag généré est SSHCTF{md5_hash}, où md5_hash est le résultat calculé.

Étiquettes: IDA_Pro XOR_Cipher AES_Encryption Base64 Self_Modifying_Code

Publié le 13 juillet à 18h39