Writeup #LeHACK 2019, 103spx
Autre challenge réussi à la sueur de mon front, ce challenge était beaucoup plus intéressant et m’a donné un peu de fil à retordre. Voyons donc comment je m’en suis sorti.
Le fichier à récupérer s’appelle « USB_a_analyser », sans extension, il fait 247Mo. File nous donne une première indication de ce à quoi on a affaire :
1 2 |
$ file USB_a_analyser USB_a_analyser: DOS/MBR boot sector, code offset 0x52+2, OEM-ID "NTFS ", sectors/cluster 8, Media descriptor 0xf8, sectors/track 62, heads 8, dos < 4.0 BootSector (0x80), FAT (1Y bit by descriptor); NTFS, sectors/track 62, sectors 507903, $MFT start cluster 4, $MFTMirror start cluster 31743, bytes/RecordSegment 2^(-1*246), clusters/index block 1, serial number 06d84ef355f47cf91 |
On a vraisemblablement affaire à une image d’un disque, mais les choses se compliquent quand on tente de faire l’inventaire détaillé des partitions :
1 2 3 4 5 6 7 |
$ sudo fdisk -l ./USB_a_analyser Disque ./USB_a_analyser : 248 MiB, 260046848 octets, 507904 secteurs Unités : secteur de 1 × 512 = 512 octets Taille de secteur (logique / physique) : 512 octets / 512 octets taille d'E/S (minimale / optimale) : 512 octets / 512 octets Type d'étiquette de disque : dos Identifiant de disque : 0x00000000 |
J’attaque un basique « strings », et je vois un message intéressant :
1 2 3 4 5 6 7 8 9 |
Si un jour je relis ce message, le mot de passe utilis pour chiffrer mon plus grand secret tait "vgrohhfyek0wkfi5fv13anexapy3sso6" et j'av s utilis openssl. En revanche, j'ai effac par erreur le fichier contenant mon plus grand secret (voir s'il existe des techniques de la mort pour le retrouver mon fichier secret.xz sha256(0fb08681c2f8db4d3c127c4c721018416cc9f9b369d5f5f9cf420b89ee5dfe4e) de 136 octets) et de toute fa on, impossible de me rappeler de l'algo utilis -_- (donc si je le retrouve... il faudra aussi retrouver l'algo pour utiliser ce mot de passe). |
Beaucoup d’informations ici, on sait donc qu’il faut récupérer un fichier qui a été chiffré avec openssl avec le mot de passe mentionné. Certes on a pas le nom du fichier, ni l’algorithme utilisé, mais on s’en préoccupera plus tard. Dans ma trousse à outils il y a donc binwalk et foremost, qui se font un plaisir d’analyser le contenu d’un fichier pour en extraire d’autres. J’ai déjà pu extraire des photos cachées dans d’autres photos. Ils me trouvent des pages web avec photos de mobylettes (le nom du challenge n’est pas là par hasard), mais rien qui ressemble à un fichier chiffré avec openssl. Rien d’autre dans les strings, ce qui implique que le fichier n’est pas stocké en clair.
Le fichier semble contenir une ou plusieurs partitions, j’entreprends alors de chercher comment faire pour les monter directement depuis le fichier dans un dossier temporaire. Comme je l’ai dit la difficulté c’est que fdisk ne me donne pas de détails sur les offsets à indiquer pour le montage, et toutes mes recherches pointent sur le fait qu’il faut cette information. C’est alors que Djerfy me glisse une suggestion : « t’as essayé volatility ? »
A là base c’est une suite d’outils en python pour extraire quantité d’informations sur des systèmes majoritairement Windows, ce qui n’est pas si con puisque le fichier contient des partitions NTFS et FAT32. Je ne connaissais pas, je m’empresse d’installer, lis un peu la doc et l’aide embarquée, et j’en viens à ça :
1 2 3 4 5 6 7 8 9 10 11 |
$ volatility -f ./USB_a_analyser mftparser --output=body -D ./vol_extract --output-file=extract.body $cat extract.body (...) 0|[MFT STD_INFO] message.txt (Offset: 0x14000)|64|---a-----------|0|0|0|1562415259|1562415034|1562415159|1562415159 0|[MFT FILE_NAME] Peugeot103SPXFILI.jpg (Offset: 0x14400)|65|---a-----------|0|0|0|1562415159|1562415159|1562415159|1562415159 0|[MFT STD_INFO] Peugeot103SPXFILI.jpg (Offset: 0x14400)|65|---a-----------|0|0|0|1562415159|1562370380|1562415159|1562415159 0|[MFT FILE_NAME] .Trash-1000\files\secret.xz (Offset: 0x14800)|66|---a-----------|0|0|136|1562415159|1562414956|1562415159|1562415159 0|[MFT STD_INFO] .Trash-1000\files\secret.xz (Offset: 0x14800)|66|---a-----------|0|0|136|1562415159|1562414956|1562415256|1562415159 0|[MFT FILE_NAME] Peugeot 103 SPX : tous les modèles de 1987 à 2003 | Actualités de la mobylette par Mobylette Mag_files (Offset: 0x14c00)|67|---a---------D-|0|0|0|1562415169|1562415169|1562415169|1562415169 0|[MFT STD_INFO] Peugeot 103 SPX : tous les modèles de 1987 à 2003 | Actualités de la mobylette par Mobylette Mag_files (Offset: 0x14c00)|67|---a-----------|0|0|0|1562415222|1562415170|1562415170|1562415169 (...) |
Mais c’est gentil de lui donner un tel nom ! On a donc un fichier secret.xz, supprimé comme l’indiquait l’indice original car dans un dossier « .Trash-1000 », il a été mis dans la corbeille (l’auteur aurait donc pu le récupérer, mais ça serait moins drôle pour nous). Par contre, alors que je passe l’option -D je n’arrive pas à récupérer le moindre fichier, rien dans le dossier « vol_extract » créé pour ce besoin. Rageant…
J’en vient à tenter le tout pour le tout : je monte directement le fichier dans un dossier avec le type ntfs. Ma surprise fut totale quand j’ai vu la commande se terminer sans erreur :
1 2 3 4 5 6 7 8 9 |
$ l tmp/.Trash-1000/files/ total 201K drwxrwxrwx 1 root root 4,0K 06.07.2019 14:14 ./ drwxrwxrwx 1 root root 0 06.07.2019 14:14 ../ drwxrwxrwx 1 root root 4,0K 06.07.2019 14:13 "CERT-FR – Centre gouvernemental de veille, d'alerte et de réponse aux attaques informatiques_files"/ drwxrwxrwx 1 root root 4,0K 06.07.2019 14:12 'Peugeot 103 — Wikipédia_files'/ -rwxrwxrwx 1 root root 33K 06.07.2019 14:13 "CERT-FR – Centre gouvernemental de veille, d'alerte et de réponse aux attaques informatiques.html"* -rwxrwxrwx 1 root root 151K 06.07.2019 14:12 'Peugeot 103 — Wikipédia.html'* -rwxrwxrwx 1 root root 136 06.07.2019 14:09 secret.xz* |
Eh oui, notre secret.xz est bien là. Je le copie donc sur mon disque, et l’extrait. Le fichier a bien été chiffré avec openssl :
1 2 |
$ file secret secret: openssl enc'd data with salted password |
Nous voilà donc à la phase finale : identifier l’algo utilisé pour chiffrer le secret. Le souci, c’est que ça va être trop compliqué d’aborder ça de manière artisanale :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
$ openssl help Standard commands asn1parse ca ciphers cms crl crl2pkcs7 dgst dhparam dsa dsaparam ec ecparam enc engine errstr gendsa genpkey genrsa help list nseq ocsp passwd pkcs12 pkcs7 pkcs8 pkey pkeyparam pkeyutl prime rand rehash req rsa rsautl s_client s_server s_time sess_id smime speed spkac srp storeutl ts verify version x509 Message Digest commands (see the `dgst' command for more details) blake2b512 blake2s256 gost md4 md5 mdc2 rmd160 sha1 sha224 sha256 sha3-224 sha3-256 sha3-384 sha3-512 sha384 sha512 sha512-224 sha512-256 shake128 shake256 sm3 Cipher commands (see the `enc' command for more details) aes-128-cbc aes-128-ecb aes-192-cbc aes-192-ecb aes-256-cbc aes-256-ecb aria-128-cbc aria-128-cfb aria-128-cfb1 aria-128-cfb8 aria-128-ctr aria-128-ecb aria-128-ofb aria-192-cbc aria-192-cfb aria-192-cfb1 aria-192-cfb8 aria-192-ctr aria-192-ecb aria-192-ofb aria-256-cbc aria-256-cfb aria-256-cfb1 aria-256-cfb8 aria-256-ctr aria-256-ecb aria-256-ofb base64 bf bf-cbc bf-cfb bf-ecb bf-ofb camellia-128-cbc camellia-128-ecb camellia-192-cbc camellia-192-ecb camellia-256-cbc camellia-256-ecb cast cast-cbc cast5-cbc cast5-cfb cast5-ecb cast5-ofb des des-cbc des-cfb des-ecb des-ede des-ede-cbc des-ede-cfb des-ede-ofb des-ede3 des-ede3-cbc des-ede3-cfb des-ede3-ofb des-ofb des3 desx idea idea-cbc idea-cfb idea-ecb idea-ofb rc2 rc2-40-cbc rc2-64-cbc rc2-cbc rc2-cfb rc2-ecb rc2-ofb rc4 rc4-40 seed seed-cbc seed-cfb seed-ecb seed-ofb sm4-cbc sm4-cfb sm4-ctr sm4-ecb sm4-ofb |
On le voit dans la partie « Cipher commands », y’a du monde, je ne me vois pas tout faire à la main un par un. Et rien dans le contenu du fichier ne permet de guider un type d’algo plutôt qu’un autre.
J’ai donc extrait la liste de ces cipher commands, organisées dans un fichier, et j’ai là aussi tapé un script à l’arrache pour faire le boulot :
1 2 3 |
cat script.sh #!/bin/bash +x for i in $(cat cipherlist.txt); do openssl $i -in secret -out "secret.${i}" -d -k vgrohhfyek0wkfi5fv13anexapy3sso6 ; done |
J’ai en résultat, un fichier par cipher. Alors y’a beaucoup de fichiers, et malgré une taille identique pour beaucoup d’entre eux, la somme de contrôle me dit qu’ils sont tous différents. Je me rabats donc sur un classique mais toujours efficace grep afin de pouvoir identifier mon vainqueur :
1 2 |
$ grep lh_ secret.* secret.aes-192-ecb:flag : lh_6c31ba64e522b5f9326b7bee0abef6547f60d214 |
Et voilà 🙂
Yo,
Très sympa, ça commence à me donner envie de m’y mettre. Un truc que j’ai pas pigé, à quoi correspond lh_ ?
Tcho !
C’est le format du flag qu’il y avait lors de l’événement LeHack https://lehack.org/fr
rootme, vulnhub, les sources d’exercices ne manquent pas 🙂
Tu avais aussi testdisk pour récupérer les fichiers. C’est immédiat avec ce tool.
ben j’ai eu justement un souci avec testdisk, même en lui passant le disque entier il n’a rien vu :/
Avec FTK Imager j’ai fait le chall en 10min même pas. Excellent outil.
Aaaah, une 103SPX avec refroidissement liquide, ça vait plus de gueule que les scooters non ?
Bonjour,
Merci pour ce retour top top,
Peux-tu mettre le fichier source ? 🙂
Je suis en train de finir d’écrire encore deux/trois trucs, et il y a des chances que je pousse un repo git (ou encore, je sais pas trop) avec les fichiers dedans. Avec mon collègue on essaie aussi d’inventorier les writeup de tous les challenges, c’est déjà sur un repo github (je le laisse faire la com’ pour le coup), si ça se trouve on rajoutera les fichiers dedans, si c’est pas trop gros (l’image NTFS fait 250Mo :/)