J'ai participé en équipe sous le nom de The Magic Modbus (vous comprendrez en lisant la suite de cet article) au wargame de la Nuit du Hack et aux challenges Intrinsec.
> Les règles sont simples : trouvez les *flags* cachés dans les challenges pour gagner des points. Plus vous êtes rapide pour valider un *flag*, plus vous gagnez de points. Les flags sont des chaînes de caractères commençant par `ndh2k17`.
* [Wargame NDH XV - Write-Up Radio Three ](https://blog.tclaverie.eu/posts/wargame-ndh-xv---write-up-radio-three/) par [Elykar](https://tclaverie.eu/) (fr)
On commence le challenge par la ligne suivante, une connexion TCP sur le port 8001 sur un serveur d'Intrinsec :
```raw
nc ndh.intrinsec.com 8001
```
Lors de la connexion, on a le prompt suivant :
```raw
Welcome soldier, hope that you speak base64 fluently !
b64_Snake >>>
```
On sait donc que l'on va devoir communiquer en base64 avec un shell python.
Cependant le fait de convertir une simple expression python en base64 cause l'erreur suivante :
```raw
You should tell this to the marshal.
```
Après plusieurs essais, nous nous penchons sur la classe [marshal](https://docs.python.org/2/library/marshal.html) qui permet de serializer des objets. On aboutit alors à la fonction d'encodade suivante :
Pour la suite, nous nous sommes basés sur le [Write-Up du Breizh-Camp 2016 d'Intrinsec](https://securite.intrinsec.com/2016/05/17/breizhctf-2016-write-up-pyjail-1-2-3/).
En recherchant les instructions sur Google, on comprend qu'il s'agit d'une architecture MIPS. En s'intéressant à ce que notre gestionnaire de paquet nous propose sur MIPS :
Pour commencer, nous avons suivi [la documentation de la bibliothèque](https://pymodbus.readthedocs.io/en/latest/index.html), particulièrement [l'exemple d'un client synchrone](https://pymodbus.readthedocs.io/en/latest/examples/synchronous-client.html) pour se familiariser avec la bibliothèque.
Nous n'avons pas trouvé tout de suite des informations intéressantes, nous avons donc utilisé le code d'un [Scraper Modbus fourni par la documentation](https://pymodbus.readthedocs.io/en/latest/examples/modbus-scraper.html) qui nous a permis de trouver des valeurs qui se convertissaient bien en ascii. Ce dernier ne récupérant que 8 caractères, nous n'avions pas le flag entier. Nous avons par contre modifié le parser pour afficher l'appel exact réalisé.
Le flag était donc stocké dans un *input register*, peu importe *l'unit* et il fallait récupérer les valeurs depuis 0, jusqu'à 21. Ensuite on convertit le tableau de bytes en tableau de char que l'on transforme en string.
Nous avons commencé par extraire l'image, un fichier jpg. Nous avons regardé si des informations n'étaient pas cachées dedans en changeant la luminance, ou ajoutées à la fin du fichier mais rien.
En revenant sur l'analyse du fichier PDF en lui même, nous découvrons plusieurs polices au nom étrange (Comic Sans Kev2, Comic Sans Gad). Nous les extrayons avec l'outil pdf-parser.py mais rien de concluant.
Au final, nous finissons pas tenter l'outil `pdftotext` qui permet d'extraire le texte d'un PDF. Nous trouvons alors un indice, le texte suivant n'est pas affiché dans le PDF :
Pour ce challenge, nous partions de l'image suivante :
[![Image de départ](/assets/images/posts/ndh-chall_soeasy.png)](/assets/images/posts/ndh-chall_soeasy.png)
Aucun outil particulier n'a été nécessaire pour ce challenge à part The Gimp.
On reconnait un empilement de text étiré en bas à gauche de l'image ainsi que plusieurs nombres. Ils semblent indiquer dans quel ordre lire les différents textes étirés, qui sont donc tournés selon un certain angle.
Je commence donc part isoler ce bout de l'image et à y appliquer les différentes rotations (outil sélection et rotation de Gimp) :
Ensuite, on peut soit baisser son écran pour lire le texte, soit redimensionner les images (outil de mise à l'échelle). L'idée étant de réduire la hauteur et d'augmenter la largeur :
On suppose donc que le fichier à trouver est un fichier PNG. Cependant, il y a beaucoup trop de fichiers pour les vérifier un à un manuellement. J'ai fait le choix d'automatiser la recherche avec python :
Ce dernier, sans indication est trop compliqué à résoudre à la main. En regardant les données exif des fichiers générés, on trouve sa position dans le puzzle :
Il aurait été judicieux d'écrire un script pour reconstituer l'image à partir de ces données exif. Pour ma part, j'ai utilisé Gimp avec une grille en 30x30 aimantée. Une fois le QR Code reconstitué, ce dernier nous renvoit vers [un lien Pastebin](https://pastebin.com/raw/F1Y26KDJ) qui contient des informations encodées en base64. On peut décoder ces informations pour retrouver le binaire original comme suit :
On comprend alors que le fichier est une image PNG. En l'ouvrant, il est possible de lire une phrase avec des mots en couleur. En réduisant la luminance dans GIMP sous Teintes-Saturation, certaines lettres et chiffres apparaissent d'une couleur différente :
Nous connaissons les deux éléments suivants : 7 puis underscore. Nous retrouvons donc les deux octets manquants qui permettent de compléter notre clé de décodage. Ensuite, il suffit de recommencer au début de la clé pour déchiffrer la suite.
Notre équipe a fini 8ème du Wargame, une très bonne surprise. Nous espérons pouvoir retenter l'aventure l'année prochaine, et qui sait, faire mieux ?