Analyse Approfondie de Trafic Réseau : Déchiffrement SMB et RDP pour un Défi CTF

L'analyse de paquets réseau est une compétence fondamentale en cybersécurité, souvent mise à l'épreuve lors de compétitions de type Capture The Flag (CTF). Ce document détaille une approche méthodique pour déchiffrer et interpréter des flux de données complexes, notamment les protocoles SMB et RDP, afin de découvrir des informations cachées.

Phase 1 : Identification et Extraction des Hachages NTLMv2

Le point de départ de ce défi est un fichier de capture de trafic (.pcapng). Une inspection initiale révèle l'utilisation du protocole SMB (Server Message Block), souvent associé à des mécanismes d'authentification NTLM. L'observation de messages d'authentification NTLM SSP (Security Support Provider) indique une tentative de connexion. Cependant, le trafic est chiffré, probablement par TLS, rendant l'analyse directe des données difficile.

Pour contourner le chiffrement, l'objectif est d'extraire le hachage NTLMv2, qui peut ensuite être craqué pour obtenir un mot de passe. Ce mot de passe servira de clé pour déchiffrer le reste du trafic TLS.

Le format d'un hachage NTLMv2 est généralement le suivant : utilisateur::domaine:challenge_serveur:NTProofStr:blob_client.

L'outil tshark, la version en ligne de commande de Wireshark, est idéal pour extraire ces composants avec précision depuis le fichier .pcapng. Nous ciblons les messages NTLMSSP de type 3 (authentification) pour les informations client et de type 2 (challenge) pour le challenge serveur.

Pour extraire les informations utilisateur, domaine, NTProofStr et la réponse NTLM complète (incluant le blob) :

tshark -n -r dy.pcapng -Y 'ntlmssp.messagetype == 0x00000003' -T fields -e ntlmssp.auth.username -e ntlmssp.auth.domain -e ntlmssp.ntlmv2_response.ntproofstr -e ntlmssp.auth.ntresponse

Pour obtenir le challenge du serveur :

tshark -n -r traffic.pcapng -Y 'ntlmssp.messagetype == 0x00000002' -T fields -e ntlmssp.ntlmserverchallenge

En combinant les données extraites (par exemple, tom::172.16.105.129:c1dec53240124487:ca32f9b5b48c04ccfa96f35213d63d75:010100000000000040d0731fb92adb01221434d6e24970170000000002001e004400450053004b0054004f0050002d004a0030004500450039004d00520001001e004400450053004b0054004f0050002d004a0030004500450039004d00520004001e004400450053004b0054004f0050002d004a0030004500450039004d00520003001e004400450053004b0054004f0050002d004a0030004500450039004d0052000700080040d0731fb92adb0106000400020000000800300030000000000000000100000000200000bd69d88e01f6425e6c1d7f796d55f11bd4bdcb27c845c6ebfac35b8a3acc42c20a001000000000000000000000000000000000000900260063006900660073002f003100370032002e00310036002e003100300035002e003100320039000000000000000000), le hachage NTLMv2 est prêt pour un processus de cassage. L'utilisation d'outils de cassage de hachages (comme Hashcat ou John the Ripper, non détaillés ici) permet de révéler le mot de passe : babygirl233.

Ce mot de passe peut ensuite être utilisé dans Wireshark ou un autre analyseur de trafic pour déchiffrer le trafic TLS, révélant ainsi les sessions de protocole de bureau à distance (RDP).

Phase 2 : Analyse du Trafic RDP Déchiffré

Une fois le trafic TLS déchiffré, une nouvelle analyse du fichier .pcapng mis à jour révèle des flux RDP. L'examen de ces paquets montre une abondance d'événements de souris et de codes de balayage (scancodes) de clavier, suggérant une interaction utilisateur avec un système distant via RDP.

L'objectif est d'extraire la séquence des frappes clavier. Pour ce faire, nous pouvons de nouveau utiliser tshark pour filtrer spécifiquement les scancodes RDP :

tshark -n -r decrypted_traffic.pcapng -Y 'rdp.fastpath.scancode.keycode' -T fields -e rdp.fastpath.scancode.keycode > scancodes.txt

Le fichier scancodes.txt contiendra une liste de codes hexadécimaux représentant les touches pressées. Pour les traduire en caractères lisibles, un script Python est nécessaire, s'appuyant sur un mappage standard des scancodes.

Voici un exemple de script Python pour décoder ces scancodes :

# Mappage des codes de balayage (scancodes) vers les caractères correspondants
# Ce mappage est basé sur une disposition de clavier US standard.
MAP_SCANCODES = {
    0x01: 'Esc', 0x02: '1', 0x03: '2', 0x04: '3', 0x05: '4',
    0x06: '5', 0x07: '6', 0x08: '7', 0x09: '8', 0x0A: '9',
    0x0B: '0', 0x0C: '-', 0x0D: '=', 0x0E: '\b', # Backspace
    0x0F: '\t', # Tab
    0x10: 'Q', 0x11: 'W', 0x12: 'E', 0x13: 'R', 0x14: 'T',
    0x15: 'Y', 0x16: 'U', 0x17: 'I', 0x18: 'O', 0x19: 'P',
    0x1A: '[', 0x1B: ']', 0x1C: '\n', # Entrée
    0x1D: 'Ctrl', 0x1E: 'A', 0x1F: 'S', 0x20: 'D', 0x21: 'F',
    0x22: 'G', 0x23: 'H', 0x24: 'J', 0x25: 'K', 0x26: 'L',
    0x27: ';', 0x28: '\'', 0x29: '`', 0x2A: 'Shift',
    0x2B: '\\', 0x2C: 'Z', 0x2D: 'X', 0x2E: 'C', 0x2F: 'V',
    0x30: 'B', 0x31: 'N', 0x32: 'M', 0x33: ',', 0x34: '.',
    0x35: '/', 0x36: 'Shift', 0x37: '*', 0x38: 'Alt',
    0x39: ' ', # Espace
    0x3A: 'Caps Lock', 0x3B: 'F1', 0x3C: 'F2', 0x3D: 'F3',
    0x3E: 'F4', 0x3F: 'F5', 0x40: 'F6', 0x41: 'F7', 0x42: 'F8',
    0x43: 'F9', 0x44: 'F10', 0x45: 'Num Lock', 0x46: 'Scroll Lock',
    0x47: 'Home', 0x48: 'Up Arrow', 0x49: 'Page Up',
    0x4A: 'Keypad -', 0x4B: 'Left Arrow', 0x4C: 'Keypad 5',
    0x4D: 'Right Arrow', 0x4E: 'Keypad +', 0x4F: 'End',
    0x50: 'Down Arrow', 0x51: 'Page Down', 0x52: 'Insert',
    0x53: 'Delete', 0x57: 'F11', 0x58: 'F12'
}

def decrypter_scancodes(fichier_scancodes):
    """
    Lit les codes de balayage depuis un fichier et les traduit en une chaîne de caractères.
    Les codes répétitifs sont ignorés pour simuler une frappe unique.
    """
    frappes_deja_vues = []
    try:
        with open(fichier_scancodes, "r", encoding="utf-8") as f_in:
            for ligne in f_in:
                code_hex = ligne.strip()
                if code_hex:
                    frappes_deja_vues.append(code_hex)
    except FileNotFoundError:
        print(f"Erreur : Le fichier '{fichier_scancodes}' n'a pas été trouvé.")
        return ""

    texte_decode = []
    dernier_code_hex_traite = None

    for code_hex_actuel in frappes_deja_vues:
        if code_hex_actuel != dernier_code_hex_traite:
            try:
                valeur_int = int(code_hex_actuel, 16)
                caractere = MAP_SCANCODES.get(valeur_int)
                if caractere:
                    texte_decode.append(caractere)
            except ValueError:
                # Ignorer les entrées non hexadécimales
                pass
            dernier_code_hex_traite = code_hex_actuel
            
    return "".join(texte_decode)

# Exécution du script
resultat_scancodes = decrypter_scancodes("scancodes.txt")
print(resultat_scancodes)

En exécutant ce script avec le fichier scancodes.txt, on obtient une séquence de caractères qui représente les frapes au clavier. Dans ce cas particulier, une autre chaîne numérique est révélée : 9347013182.

Phase 3 : Déchiffrement Final

Le défi culmine avec un ficheir compressé flag.7z, lui-même chiffré. Il est courant que les mots de passe soient composés de plusieurs éléments découverts au cours du défi.

En combinant le premier mot de passe obtenu par le cassage NTLMv2 (babygirl233) et la séquence numérique extraite des frappes RDP (9347013182), nous formons un mot de passe composite : babygirl2339347013182.

Ce mot de passe permet de décompresser le fichier flag.7z, révélant enfin le drapeau : flag{fa32a0b2-dc26-41f9-a5cc-1a48ca7b2ddd}.

Étiquettes: CTF AnalyseTrafic SMB NTLMv2 RDP

Publié le 13 juillet à 09h52