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}.