Décompression du dump
gunzip badge-dump.img.gz
En lisant le tuto fournit par le challenge pour construire son badge (https://github.com/FCSC-FR/hackropole-badge/blob/61d627868d038e7277b8fd4fc4294c639a5fc889/assembly/README.fr.md), on découvre que celui-ci est ESP32-S3-Zero. Cette information me permet de savoir comment est la table de partition, pour extraire les partitions qui m’interessent.
Extraction avec dd
J’utilise dd de cette manière :
dd if=fichier_défi of=nom_fic_sortie bs=1(pour exprimer les valeurs suivantes en octets) skip=$((premier_octets_extrait)) count=$((taille_extraction))
En me renseignant sur les mémoires flash des ESP32, et sa table de partition. J’imagine trouver le flag dans le nvs ou le spiffs.
J’ai premièrement pensé que j’allais trouvé des choses intéressantes dans le NVS (Non Volatille Storage) car ici sont stockés des paramètres persistant après rédémarage.
dd if=badge-dump.img of=nvs.bin bs=1 skip=$((0x9000)) count=$((0x5000))
Je n’ai rien trouvé d’interresant.
J’essaye donc d’extraire son SPIFFS (Serial Peripheral Interface Flash File System)
dd if=badge-dump.img of=spiffs.bin bs=1 skip=$((0x310000)) count=$((0xf0000))
En faisant un strings on tombe sur des choses intéréssantes:
strings spiffs.bin
littlefs/
presets.json
wsec.json
cfg.json7P
{"nw":{"ins":[{"psk":""}]},"ap":{"psk":"wled1234"},"if":{"mqtt":{"psk":""},"hue":{"key":"api"}},"pin":"","ota":{"pwd":"wledota","lock":false,"lock-wifi":false,"aota":true}}
On découvre que notre extraction contient un sytème de fichier LittleFS
Analyse du sytème de fichier
On va utiliser l’outil mklittlefs pour analyser notre système de fichier :
On télécharge et on compile :
git clone https://github.com/earlephilhower/mklittlefs.git
cd mklittlefs
make
On créer un répertoire pour extraire :
mkdir extracted
Puis on extrait :
./mklittlefs \
-b 4096 \
-p 256 \
-s 0xf0000 \
-u extracted \
../spiffs.bin
littlefs/lfs.c:4546:debug: Found older minor version v2.0 < v2.1
littlefs/lfs.c:4623:debug: Found pending gstate 0x000002000000000000000000
/cfg.json > ./extracted/cfg.json size: 2836 Bytes
/presets.json > ./extracted/presets.json size: 46549 Bytes
/wsec.json > ./extracted/wsec.json size: 172 Bytes
On va pouvoir analyser les 3 fichiers qui nous interessent !
On se place dans extracted :
cd extrated
En faisant un strings presets.json on remarque à la fin :
"17":{"playlist":{"ps":[1,2,3,2,4,5,6,7,8,9,10,6,9,11,12,9,12,13,6,9,3,12,7,14,15,16],"dur":[10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000],"transition":[7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7],"repeat":0,"end":0,"r":0},"on":true,"n":"flag"}}
On remarque que le preset 17 s’appelle “flag”.
Analyse de presets.json
Dans WLED les presets sont des configurations enregistrés
Je vais utiliser jq pour y voir plus claire dans les affichages.
J’aimerais maitenant connaitre les noms des autres presets :
jq '.[] | {name:.n}'
Je remarque que les autres presets s’apellent “char0” à “char15” (donc 16 caractères) et comme par hasard dans le preset 17 il y a un playlist avec avec 16 numéros. Je vais donc devoir décrypter chaque caractère pour reconstituer la playlist qui me donnera le flag.
Décryptage des char
On va analyser les 16 char :
jq '.[] | select(.id <= 16)' presets.json
On remarque que chaque char possède 8 id, ce qui est cohérent avec les 8 leds sur la photo du défi. De plus un paramètre m’interpelle car il diffère entre les leds des différents char :
bri (la brightness)
Celle-ci est toujours fixé à 1 ou 255 ce qui représente si la led est éteinte ou allumée
un ASCII tient sur 8 bits, et si chaque led allumée représentait un 1 et celles éteintes un 0 ?
On va faire une commande un peu élaborée qui va nous permettre de récupérer le binaire de chaque char :
jq -r '
to_entries[]
| select((.value.n // "") | startswith("char"))
| [
range(1;9) as $i
| if ([.value.seg[] | select(.id == $i and (.bri // 0) > 1)] | length) > 0
then "1"
else "0"
end
]
| join("")
' presets.json > resultat.txt
On vérifie que ca marche bien en convertissant le premier binaire de notre fichier en ASCII et ca marche pas, c’est un cararctère ilisible !
Mais ! Nous savons que nous somme dans un défi et que le flag doit probablement commencer par FCSC. On compare le binaire de F et notre caractère
? : 10001101
F : 1000110
Il suffit d’enlever les 1 à la fin de chacun de nos caractères.
Je vous laisse le plaisir de convertir tout vos binaires par des ASCII et de les écrire dans l’ordre de la playlist du flag (rappel [1,2,3,2,4,5,6,7,8,9,10,6,9,11,12,9,12,13,6,9,3,12,7,14,15,16]).