Hunting License
Résumé
| Info | Valeur |
|---|---|
| Vulnérabilité | Trois protections par mot de passe avec des mécanismes faibles |
| Technique | Texte clair, chaîne inversée, et déchiffrement XOR |
| Outils | file, strings, radare2/Ghidra, Python |
Reconnaissance initiale
Identification du fichier
$ file licenselicense: ELF 64-bit LSB executable, x86-64, version 1 (SYSV),dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2,for GNU/Linux 3.2.0, not strippedPoints notables :
not stripped: Les noms des fonctions sont visiblesdynamically linked: Utilise les bibliothèques partagées
Exécution du programme
$ ./licenseWhat is the password? testWrong!Le programme demande un mot de passe. En fait, il y a trois niveaux de protection successifs.
Première protection : texte clair
Analyse avec strings
$ strings license | grep -i passwordWhat is the password?Analyse dans radare2
$ r2 -A license[0x00401060]> afl # Lister les fonctions...0x00401172 1 107 sym.exam0x004011dd 1 91 sym.reverse0x00401238 1 72 sym.xor...Trois fonctions intéressantes sont identifiées : exam, reverse, et xor.
Fonction exam
[0x00401060]> pdf @sym.examLa fonction exam contient la première vérification :
; Première questionlea rdi, str.What_is_the_password?call sym.imp.printflea rdi, [rbp-0x20]call sym.imp.scanflea rdi, str.**REDACTED** ; La clé en clair !lea rsi, [rbp-0x20]call sym.imp.strcmptest eax, eaxjne wrongPremier mot de passe : **REDACTED**
La chaîne est visible directement dans le binaire, comparée avec strcmp().
$ ./licenseWhat is the password? **REDACTED**Correct!...Deuxième protection : chaîne inversée
Analyse de la fonction reverse
La deuxième vérification utilise la fonction reverse :
// Pseudo-code de la fonction reversechar* reverse(char *str) { int len = strlen(str); char *reversed = malloc(len + 1); for (int i = 0; i < len; i++) { reversed[i] = str[len - 1 - i]; } reversed[len] = '\0'; return reversed;}Trouver la chaîne source
Dans la fonction exam, après la première vérification :
; Deuxième questionlea rdi, str.What_is_the_second_password?call sym.imp.printflea rdi, [rbp-0x20]call sym.imp.scanflea rdi, str.0wTdr0wss worNtworthy ; Chaîne à inversercall sym.reverse ; Inversionlea rsi, [rbp-0x20]call sym.imp.strcmpLa chaîne stockée dans le binaire est inversée avant la comparaison. Il faut donc l’inverser nous-mêmes :
>>> s = "0wTdr0wss worNtworthy"[::-1]>>> print(s)yhtrrowTNrow sswOrdTw0Mais attention, la chaîne exacte dépend de ce qui est stocké dans le binaire. Analysons avec radare2 :
[0x00401060]> ps @0x402040 # Afficher la chaîne à l'adresse mémoireDeuxième mot de passe : la chaîne inversée extraite du binaire.
Troisième protection : chiffrement XOR
Analyse de la fonction xor
// Pseudo-code de la fonction xorchar* xor_decrypt(char *data, int key) { int len = strlen(data); char *result = malloc(len + 1); for (int i = 0; i < len; i++) { result[i] = data[i] ^ key; } result[len] = '\0'; return result;}Extraction des données chiffrées et de la clé
Dans la troisième vérification :
; Troisième questionlea rdi, str.What_is_the_third_password?call sym.imp.printflea rdi, [rbp-0x20]call sym.imp.scanflea rdi, [encrypted_data] ; Données chiffréesmov esi, 0x13 ; Clé XOR = 0x13call sym.xor ; Déchiffrement XORlea rsi, [rbp-0x20]call sym.imp.strcmpScript de déchiffrement
#!/usr/bin/env python3"""Déchiffrement XOR pour le troisième mot de passe"""
# Données chiffrées extraites du binaire (à l'adresse mémoire identifiée)encrypted = [ # Octets extraits depuis radare2/Ghidra # Exemple : 0x55, 0x64, 0x78, ...]
key = 0x13 # Clé XOR extraite du code assembleur
decrypted = ''.join(chr(b ^ key) for b in encrypted)print(f"Troisième mot de passe : {decrypted}")Tutoriel radare2
Commandes essentielles utilisées
| Commande | Description |
|---|---|
r2 -A binary | Ouvrir avec analyse automatique |
afl | Lister toutes les fonctions |
pdf @sym.func | Désassembler une fonction |
ps @addr | Afficher une chaîne à une adresse |
px N @addr | Hexdump de N octets à une adresse |
VV @sym.func | Vue graphique d’une fonction |
iz | Lister les chaînes du binaire |
axt @addr | Trouver les références croisées vers une adresse |
Workflow typique dans radare2
$ r2 -A license
# 1. Lister les fonctions[0x00401060]> afl
# 2. Analyser la fonction principale[0x00401060]> pdf @sym.exam
# 3. Lister les chaînes[0x00401060]> iz
# 4. Examiner une adresse mémoire[0x00401060]> px 32 @0x402040
# 5. Vue graphique (très utile pour comprendre les branches)[0x00401060]> VV @sym.examRappels sur l’assembleur x86-64
Instructions courantes rencontrées
| Instruction | Description | Exemple |
|---|---|---|
mov | Copie une valeur | mov rax, 5 |
lea | Charge une adresse | lea rdi, [str] |
call | Appelle une fonction | call strcmp |
cmp | Compare deux valeurs | cmp eax, 0 |
test | ET logique (met les flags) | test eax, eax |
je/jne | Saut conditionnel | jne wrong |
push/pop | Pile | push rbp |
Registres pour les arguments (convention System V AMD64)
1er argument → RDI2e argument → RSI3e argument → RDX4e argument → RCX5e argument → R86e argument → R9Retour → RAXExemple concret
lea rdi, str.password ; 1er arg de strcmp = "password"lea rsi, [rbp-0x20] ; 2e arg de strcmp = entrée utilisateurcall sym.imp.strcmp ; strcmp(password, input)test eax, eax ; eax == 0 ? (chaînes identiques ?)jne wrong ; Si non, sauter à "wrong"Exploitation complète
$ nc REMOTE_IP REMOTE_PORTWhat is the password? **REDACTED**Correct!
What is the second password? <chaîne_inversée>Correct!
What is the third password? <chaîne_déchiffrée_xor>Correct!
HTB{XXXXXXXXXXXXXXXXXXXXXXX}Concepts appris
Trois niveaux de protection
| Niveau | Mécanisme | Faiblesse |
|---|---|---|
| 1 | strcmp() avec texte clair | Visible avec strings |
| 2 | strcmp() après reverse() | Inversible trivialement |
| 3 | strcmp() après xor() | Clé XOR visible dans le code |
Chiffrement XOR
Chiffrement : texte ^ clé = chiffréDéchiffrement : chiffré ^ clé = texte
Propriété : A ^ B ^ B = AInversion de chaîne
# En Python, inverser une chaîne :original = "Hello"reversed_str = original[::-1] # "olleH"Méthodologie
1. file / strings → Identifier le binaire et chercher des indices2. r2 -A / Ghidra → Analyser les fonctions (exam, reverse, xor)3. Password 1 → strcmp avec texte clair → strings suffit4. Password 2 → strcmp après reverse() → inverser la chaîne5. Password 3 → strcmp après xor() → déchiffrer avec la clé6. Connecter → Envoyer les 3 mots de passe pour obtenir le flag