Auteur de la solution : @Dowan35
Contexte du challenge
On nous fournit une capture de mémoire vive (dump RAM) d’une machine Linux. L’objectif est de trouver l’adresse physique (phys) et l’adresse virtuelle (virt) de la première instruction du noyau Linux (_stext).
Le flag attendu est au format FCSC{phys-virt}, avec des adresses formatées sur 64 bits (ex: FCSC{0x0123456789abcdef-0xfedcba9876543210}).
Raisonnement/méthodologie
1 : Le piège des outils classiques (Volatility)
Face à un fichier .mem, un premier réflexe est d’utiliser Volatility 3.
Cependant, en lançant une commande de base comme vol -f intro.mem linux.pslist, Volatility renvoie une erreur : Unsatisfied requirement plugins.Kmsg.kernel.symbol_table_name.
En effet, Volatility a besoin d’un profil précis (une table de symboles ou fichier ISF) correspondant exactement à la version du noyau Linux de la machine pour mapper la mémoire. Sans ce fichier (non fourni dans l’énoncé), Volatility est aveugle.
On doit donc faire une analyse statique brute..
2 : Recherche d’indices en clair dans la mémoire
Puisque le challenge contient “kaslr” (Kernel Address Space Layout Randomization), on s’attend à ce que le noyau ait été chargé à une adresse aléatoire au démarrage.
La mémoire vive contient souvent les logs de démarrage du noyau (dmesg), qui sont stockés en clair. On peut utiliser l’outil strings pour extraire tout le texte lisible du dump.
Nous cherchons spécifiquement des indices sur le décalage (offset) appliqué par le KASLR :
strings intro.mem | grep "Kernel Offset"
Résultat :
Kernel Offset: 0x%lx from 0x%lx (relocation range: 0x%lx-0x%lx)
Kernel Offset: disabled
C’est ici qu’on a un plot twist du challenge : Kernel Offset: disabled. Le KASLR n’est pas activé sur cette machine, le noyau a donc été chargé à ses adresses par défaut, compilées en dur.
3 : Connaître les adresses par défaut de Linux (x86_64)
Puisque le KASLR est inactif, nous n’avons plus besoin de calculer de décalage. Il suffit de connaître l’architecture mémoire standard d’un noyau Linux 64 bits.
L’adresse virtuelle (virt) : Sur l’architecture x86_64, la zone mémoire dédiée au code du noyau (Kernel Text Mapping) commence toujours par défaut à l’adresse 0xffffffff81000000. C’est là que se trouve la fonction _stext.
L’adresse physique (phys) : Au moment du boot, le noyau décompressé est copié en mémoire physique à un décalage standard de 16 MiB (Mébioctets), ce qui donne en hexadécimal l’adresse 0x1000000.
4 : Le formatage du Flag
L’énoncé précise une règle stricte : « Les adresses sont toutes sur 64 bits, au format hexadécimal avec préfixe 0x ». Une adresse sur 64 bits doit comporter exactement 16 caractères hexadécimaux après le 0x.
virt = 0xffffffff81000000 (Déjà sur 64 bits, 16 caractères).
phys = 0x1000000 (Seulement 7 caractères). Il faut rajouter des zéros (padding) pour remplir les 64 bits. phys devient donc : 0x0000000001000000.
5 : Solution
En combinant nos deux adresses correctement formatées, on obtient notre flag :
FCSC{0x0000000001000000-0xffffffff81000000}
Sources
KASLR (Kernel Address Space Layout Randomization) : Mécanisme de sécurité qui place le noyau à une adresse aléatoire en mémoire pour empêcher les attaques par corruption de mémoire : https://docs.kernel.org/arch/x86/x86_64/mm.html
Architecture mémoire x86_64 sous Linux : Pour comprendre l’adresse 0xffffffff81000000 et la dispo de la mémoire virtuelle : https://www.kernel.org/doc/Documentation/x86/x86_64/mm.txt
“config PHYSICAL_START hex “Physical address where the kernel is loaded” if (EXPERT || CRASH_DUMP) default “0x1000000” " : https://github.com/torvalds/linux/blob/master/arch/x86/Kconfig (lignes 1992)
Analyse brute avec strings : strings est une commande Unix qui permet de chercher des suites de caractères imprimables dans des fichiers binaires. C’est l’outil de base quand des analyseurs avancés ne peuvent pas être utilisés.