Le HackSecuReims est organisé tous les ans à Reims par l'université de Reims Champagne-Ardennes. Je me suis rendu à l'édition 2023 avec HackademINT, et j'ai pu me pencher sur divers challenges. Très peu d'équipes étant parvenues à résoudre les challenges d'analyse de vidage mémoire (nommés Memdump 1, 2, 3 et 4), j'ai écrit ce write-up pour partager mes solutions après en avoir discuté avec le créateur du challenge.
Un peu de reconnaissance
Comme son nom l'indique, le challenge consiste à analyser le vidage mémoire d'une machine compromise. Nous allons donc commencer par rechercher des informations de base pour pouvoir réellement travailler.
Memdump ➜ ls
HSR2023.dmp.xz
Memdump ➜ unxz HSR2023.dmp.xz
Memdump ➜ ls -lh
-rw-r--r-- 1 smyler smyler 1,0G 25 mars 11:52 HSR2023.dmp
Memdump ➜ strings HSR2023.dmp | sort | uniq > strings_ascii
Memdump ➜ strings -e l HSR2023.dmp | sort | uniq > strings_utf-16
Memdump ➜ grep -R Linux . | head
grep: ./HSR2023.dmp : fichiers binaires correspondent
./strings_ascii: $Linux::usermod::file_group, $Linux::usermod::file_gshadow are not in the
./strings_ascii: $Linux::usermod::file_passwd, $Linux::usermod::file_shadow,
./strings_ascii: [[ $userland == @(Linux|GNU/*) ]] && userland=GNU
./strings_ascii: $(warning 'SUBDIRS' was removed in Linux 5.3)
./strings_ascii:[ 0.059835] TOMOYO Linux initialized
./strings_ascii:0-0 Linux [kernel]
./strings_ascii:[ 0.255696] ACPI: Added _OSI(Linux-Dell-Video)
./strings_ascii:[ 0.255697] ACPI: Added _OSI(Linux-HPI-Hybrid-Graphics)
./strings_ascii:[ 0.255697] ACPI: Added _OSI(Linux-Lenovo-NV-HDMI-Audio)
./strings_ascii:[ 0.656953] Linux agpgart interface v0.103
Memdump ➜ grep -R HSR{ . | head
grep: ./HSR2023.dmp : fichiers binaires correspondent
./strings_ascii:[200~echo -n "HSR{F4k3_Fl4gs_b3caus3_strings|grep_are_not_your_friend_f0r_this_ch
all}"
./strings_ascii:3caus3_strings|grep_are_not_your_friend_f0r_this_chall}HSR{Fil3_In_M3m0ry_F0r3ns1
cs}HSR{Fil3_In_M3m0ry_F0r3ns1cs}HSR{FIl3_In_M3m0ry_F0r3ns1cs}HSR{Fil3_in_M3m0ry_F0r3ns1cs}HSR{Fil
3_in_m3m0ry_F0r3ns1cs}HSR{Fil3_in_m3m0ry_f0r3ns1cs}HSR{Fil3_in_M3m0ry_f0r3ns1cs}HSR{Fil3_In_M3m0r
y_f0r3ns1cs}HSR{FIl3_in_M3m0ry_F0r3ns1cs}HSR{FIl3_in_m3m0ry_F0r3ns1cs}HSR{FIl3_in_m3m0ry_f0r3ns1c
s}HSR{FIl3_in_M3m0ry_f0r3ns1cs}total 5800
./strings_ascii:echo -n "HSR{F4k3_Fl4gs_b3caus3_strings|grep_are_not_your_friend_f0r_this_chall}"
./strings_ascii:echo -n "HSR{FE.r) $(OUTPUT_OPTION) $<
./strings_ascii:echo -n "HSR{Fil3_in_m3m0ry_f0r3ns1cs}"
./strings_ascii:echo -n "HSR{Fil3_in_m3m0ry_F0r3ns1cs}"
./strings_ascii:echo -n "HSR{Fil3_in_M3m0ry_f0r3ns1cs}"
./strings_ascii:echo -n "HSR{Fil3_in_M3m0ry_F0r3ns1cs}"
./strings_ascii:echo -n "HSR{Fil3_In_M3m0ry_f0r3ns1cs}"
./strings_ascii:echo -n "HSR{Fil3_In_M3m0ry_F0r3ns1cs}"
Nous sommes donc visiblement en présence d'une machine Linux disposant d'1GO de ram,
et l'auteur semble avoir anticipé notre malice et nous met en garde contre l'inutilité d'utiliser strings
et grep
via un faux flag: HSR{F4k3_Fl4gs_b3caus3_strings|grep_are_not_your_friend_f0r_this_ch all}
.
Le HSR{Fil3_in_M3m0ry_F0r3ns1cs}
n'est pas non plus un flag valide, mais nous indique que nous allons probablement
devoir extraire un fichier de la mémoire.
Construction des profils
Nous allons donc devoir construire un profil volatility pour le noyau Linux utilisé. Nous pouvons pour cela commencer par obtenir sa bannière :
Memdump ➜ vol3 -f HSR2023.dmp banners.Banners
Volatility 3 Framework 1.0.0
Progress: 100.00 PDB scanning finished
Offset Banner
0xc800200 Linux version 5.10.0-21-amd64 (debian-kernel@lists.debian.org) (gcc-10 (Debian 10
.2.1-6) 10.2.1 20210110, GNU ld (GNU Binutils for Debian) 2.35.2) #1 SMP Debian 5.10.162-1 (2023-
# 01# -2# 1)
Nous pourrions construire notre profil dans un conteneur, mais mon script habituel ne marchait pas avec cette version récente de Debian, j'ai donc choisi de le faire avec une machine virtuelle. Au vu de la version relativement récente de la date de construction du noyau, nous téléchargeons donc un ISO Debian que nous installons dans Virtualbox.
Une fois notre VM prête, un rapide uname -a
nous indique que nous travaillons déjà avec le noyau souhaité.
Il nous faut cependant installer quelques paquets supplémentaires afin de disposer des informations de débogage du noyau
et des outils dont nous aurons besoin.
debian@debian:~$ uname -a
Linux debian 5.10.0-21-amd64 #1 SMP Debian 5.10.162-1 (2023-01-21) x86_64 GNU/Linux
debian@debian:~$ sudo apt install \
linux-headers-5.10.0-21-amd64 \
linux-image-5.10.0-21-amd64-dbg \
git \
build-essential \
dwarfdump \
make \
zip \
golang
Volatility 2
On peut ensuite cloner le dépôt de volatility 2 et construire module.dwarf
:
debian@debian:~$ git clone https://github.com/volatilityfoundation/volatility
Clonage dans 'volatility'...
remote: Enumerating objects: 27411, done.
remote: Total 27411 (delta 0), reused 0 (delta 0), pack-reused 27411
Réception d'objets: 100% (27411/27411), 21.10 Mio | 2.62 Mio/s, fait.
Résolution des deltas: 100% (19758/19758), fait.
debian@debian:~ cd volatility/volatility/tools/linux
debian@debian:~/volatility/tools/linux$ make
make -C //lib/modules/5.10.0-21-amd64/build CONFIG_DEBUG_INFO=y M="/tmp/volatility/tools/linux"
modules
make[1]: on entre dans le répertoire «/usr/src/linux-headers-5.10.0-21-amd64»
CC [M] /home/debian/volatility/tools/linux/module.o
MODPOST /home/debian/volatility/tools/linux/Module.symvers
WARNING: modpost: missing MODULE_LICENSE() in /tmp/volatility/tools/linux/module.o
CC [M] /home/debian/volatility/tools/linux/module.mod.o
LD [M] /home/debian/volatility/tools/linux/module.ko
make[1]: on quitte le répertoire «/usr/src/linux-headers-5.10.0-21-amd64»
dwarfdump -di module.ko > module.dwarf
make -C //lib/modules/5.10.0-21-amd64/build M="/tmp/volatility/tools/linux" clean
make[1]: on entre dans le répertoire «/usr/src/linux-headers-5.10.0-21-amd64»
CLEAN /home/debian/volatility/tools/linux/Module.symvers
make[1]: on quitte le répertoire «/usr/src/linux-headers-5.10.0-21-amd64»
debian@debian:~$ cd
debian@debian:~$ zip $(lsb_release -i -s)_$(uname -r)_profile.zip volatility/tools/linux/module.d
warf /usr/lib/debug/boot/System.map-5.10.0-21-amd64
adding: volatility/tools/linux/module.dwarf (deflated 91%)
adding: usr/lib/debug/boot/System.map-5.10.0-21-amd64 (deflated 80%)
Petite note sur d'éventuelles difficultés
Le noyau et la distribution étant relativement récents, il y a quelques précautions à prendre :
- La
System.map
n'est plus installé par défaut, il faut installerlinux-image-<version>-dbg
en plus delinux-image-<version
- Une foie installée, la vraie
System.map
ne se trouve plus dans/boot
mais dans/lib/debug/boot/
.
Volatility 3
On peut en profiter pour également construire des symbols de débogage pour Volatility 3 :
debian@debian:~$ git clone https://github.com/volatilityfoundation/dwarf2json
Clonage dans 'dwarf2json'...
remote: Enumerating objects: 112, done.
remote: Counting objects: 100% (41/41), done.
remote: Compressing objects: 100% (27/27), done.
remote: Total 112 (delta 20), reused 27 (delta 12), pack-reused 71
Réception d'objets: 100% (112/112), 53.95 Kio | 154.00 Kio/s, fait.
Résolution des deltas: 100% (39/39), fait.
debian@debian:~$ cd dwarf2json/
debian@debian:~/dwarf2json$ go mod download github.com/spf13/pflag
debian@debian:~/dwarf2json$ go build;…−∕
debian@debian:~/dwarf2json$ ./dwarf2json linux --elf /usr/lib/debug/vmlinux-5.10.0-21-amd64 > ~/v
mlinux-5.10.0-21-amd64.json
Installation des profils
Il nous suffit maintenant de sortir les fichiers que nous venons de générer de la VM et de les copier aux bons endroits :
- Volatility 2 :
<répertoire de volatility 2>/volatility/plugins/overlays/linux/Debian_5.10.0-21-amd64_profile.zip
- Volatility 3 :
<répertoire de volatility 3>/symbols/vmlinux-5.10.0-21-amd64.json
Premier flag
Volatility 2 et 3 ont chacun leurs avantages et leurs inconvénients, et j'aime utiliser un mélange des deux.
Memdump ➜ vol3 -f HSR2023.dmp linux.bash.Bash
Volatility 3 Framework 2.4.0
Progress: 100.00 Stacking attempts finished
PID Process CommandTime Command
1016 bash 2023-03-14 20:17:10.000000 ip a
1016 bash 2023-03-14 20:17:10.000000 ping 1.1.1.1
1016 bash 2023-03-14 20:17:10.000000 UH��HH��t讖��H��]饖��D
1016 bash 2023-03-14 20:17:10.000000 mkdir .ssh
1016 bash 2023-03-14 20:17:10.000000 su
1016 bash 2023-03-14 20:17:10.000000 history
1016 bash 2023-03-14 20:17:10.000000 AUA��ATA�
1016 bash 2023-03-14 20:17:10.000000 su
1016 bash 2023-03-14 20:17:13.000000 su
1020 bash 2023-03-14 20:17:19.000000 git clone https://github.com/volatilityfoundatio
n/volatility.git
1020 bash 2023-03-14 20:17:19.000000 apt install terminator
1020 bash 2023-03-14 20:17:19.000000 apt install make gcc zip git dwarfdump linux-hea
ders-$(uname -r)
1020 bash 2023-03-14 20:17:19.000000 history
1020 bash 2023-03-14 20:17:19.000000 apt install chromium firefox-esr geany
1020 bash 2023-03-14 20:17:22.000000 ls -l
1020 bash 2023-03-14 20:17:28.000000 history
1020 bash 2023-03-14 20:17:47.000000 git clone https://github.com/volatilityfoundatio
n/dwarf2json
1020 bash 2023-03-14 20:17:47.000000 apt-cache search linux-image |grep dbg
1020 bash 2023-03-14 20:17:48.000000 apt install linux-image-$(uname -r)-dbg
1020 bash 2023-03-14 20:17:48.000000 echo -n "RmxhZyBpcyA6IEhTUntNM20wcnlfRjByM25zMWN
zXzN2M3J5X1QxbWV9"
1020 bash 2023-03-14 20:17:48.000000 apt install golang-go
1020 bash 2023-03-14 20:17:59.000000 cd dwarf2json/
1020 bash 2023-03-14 20:18:05.000000 go version
1020 bash 2023-03-14 20:18:09.000000 go build
1020 bash 2023-03-14 20:18:12.000000 cd ..
1020 bash 2023-03-14 20:18:25.000000 ./dwarf2json linux --elf /usr/lib/debug/boot/vml
inux-5.10.0-21-amd64 --system-map /usr/lib/debug/boot/System.map-5.10.0-21-amd64 | xz -c > debia
n-5.10.0-21-amd64.json.xz
1020 bash 2023-03-14 20:18:48.000000 ls -l
1020 bash 2023-03-14 20:19:03.000000 cd /home/forensic/volatility/tools/linux
1020 bash 2023-03-14 20:19:03.000000 make -C /lib/modules/5.10.0-21-amd64/build CONFI
G_DEBUG_INFO=y M= modules
1020 bash 2023-03-14 20:19:04.000000 dwarfdump -di ./module.o > module.dwarf
1020 bash 2023-03-14 20:19:04.000000 zip linux-profile-hsr-$(uname -r).zip module.dwa
rf /usr/lib/debug/boot/System.map-$(uname -r)
1020 bash 2023-03-14 20:19:04.000000 mv linux-profile-hsr-$(uname -r).zip /media/sf_D
UMP/
1020 bash 2023-03-14 20:19:14.000000 echo -n "HSR{F4k3_Fl4gs_b3caus3_strings|grep_are
_not_your_friend_f0r_this_chall}"
1020 bash 2023-03-14 20:19:14.000000 echo -n "HSR{Fil3_In_M3m0ry_F0r3ns1cs}"
1020 bash 2023-03-14 20:19:14.000000 echo -n "HSR{Fil3_In_M3m0ry_F0r3ns1cs}"
1020 bash 2023-03-14 20:19:14.000000 echo -n "HSR{FIl3_In_M3m0ry_F0r3ns1cs}"
1020 bash 2023-03-14 20:19:14.000000 id
1020 bash 2023-03-14 20:19:14.000000 echo -n "HSR{Fil3_in_M3m0ry_F0r3ns1cs}"
1020 bash 2023-03-14 20:19:14.000000 echo -n "HSR{Fil3_in_m3m0ry_F0r3ns1cs}"
1020 bash 2023-03-14 20:19:14.000000 echo -n "HSR{Fil3_in_m3m0ry_f0r3ns1cs}"
1020 bash 2023-03-14 20:19:14.000000 echo -n "HSR{Fil3_in_M3m0ry_f0r3ns1cs}"
1020 bash 2023-03-14 20:19:14.000000 echo -n "HSR{Fil3_In_M3m0ry_f0r3ns1cs}"
1020 bash 2023-03-14 20:19:14.000000 echo -n "HSR{FIl3_in_M3m0ry_F0r3ns1cs}"
1020 bash 2023-03-14 20:19:14.000000 echo -n "HSR{FIl3_in_m3m0ry_F0r3ns1cs}"
1020 bash 2023-03-14 20:19:14.000000 echo -n "HSR{FIl3_in_m3m0ry_f0r3ns1cs}"
1020 bash 2023-03-14 20:19:14.000000 echo -n "HSR{FIl3_in_M3m0ry_f0r3ns1cs}"
1020 bash 2023-03-14 20:19:14.000000 ls -l
1020 bash 2023-03-14 20:19:14.000000 uname -a
1020 bash 2023-03-14 20:19:14.000000 w
1020 bash 2023-03-14 20:19:50.000000 cp /media/sf_DUMP/HSR/ .
1020 bash 2023-03-14 20:19:56.000000 cp -r /media/sf_DUMP/HSR/ .
1020 bash 2023-03-14 20:19:59.000000 cd HSR/
1020 bash 2023-03-14 20:20:26.000000 gpg --symmetric --cipher-algo AES-256 -o flag.en
c flag.pdf
1020 bash 2023-03-14 20:20:39.000000 chown -R forensic: HSR/
1020 bash 2023-03-14 20:20:41.000000 cd ..
1020 bash 2023-03-14 20:20:44.000000 chown -R forensic: HSR/
1020 bash 2023-03-14 20:20:47.000000 ls -ail
1020 bash 2023-03-14 20:20:52.000000 cd HSR
1020 bash 2023-03-14 20:21:12.000000 cd ..
1020 bash 2023-03-14 20:21:14.000000 base64 HSR/flag.enc > HSR/flag.enc.b64
1020 bash 2023-03-14 20:21:18.000000 cd HSR/
1020 bash 2023-03-14 20:21:20.000000 ls -ail
1020 bash 2023-03-14 20:22:39.000000 ls -ail
1020 bash 2023-03-14 20:23:03.000000 gcc a.c -o ransomware.o
1020 bash 2023-03-14 20:23:06.000000 ls -ail
1020 bash 2023-03-14 20:23:43.000000 ./ransomware.o
1540 bash 2023-03-14 20:22:03.000000 ip a
1540 bash 2023-03-14 20:22:03.000000 ping 1.1.1.1
1540 bash 2023-03-14 20:22:03.000000 UH��HH��t讖��H��]饖��D
1540 bash 2023-03-14 20:22:03.000000 mkdir .ssh
1540 bash 2023-03-14 20:22:03.000000 su
1540 bash 2023-03-14 20:22:03.000000 history
1540 bash 2023-03-14 20:22:03.000000 ��xLU�-�
1540 bash 2023-03-14 20:22:03.000000 su
On a donc une idée de ce qui s'est passé sur la machine :
- l'utilisateur a vérifié sa connexion réseau,
- semble avoir manipulé son répertoire
.ssh
, - a ouvert un shell root, dont Volatility n'est pas parvenu à récupérer l'historique,
- a installé quelques paquets puis a construit des profils, exactement comme nous venons de la faire,
- nous a fait passer les messages via echo
- a chiffré un fichier
flag.pdf
avecgpg
qui se trouvait sur une clé USB (ou autre support externe), - a compilé, puis lancé un binaire
ransomware.o
.
On note au milieu des commandes une qui nous semble suspecte :
1020 bash 2023-03-14 20:17:48.000000 echo -n "RmxhZyBpcyA6IEhTUntNM20wcnlfRjByM25zMWNz
XzN2M3J5X1QxbWV9"
Et sans surprise :
Memdump ➜ echo -n "RmxhZyBpcyA6IEhTUntNM20wcnlfRjByM25zMWNzXzN2M3J5X1QxbWV9" | base64 -d
Flag is : HSR{M3m0ry_F0r3ns1cs_3v3ry_T1me}
C'est le flag du premier challenge.
Second flag
L'intitulé du challenge nous parlait d'accès permanent, et on a vu que l'utilisateur avait manipulé son répertoire .ssh
.
Le créateur nous a en plus invité à récupérer des fichiers depuis la mémoire.
Tout ça nous pointe dans la direction du fichier .ssh/authorized_keys
,
qui permet à un utilisateur de renseigner les clés SSH qu'il souhaite pouvoir utiliser pour se connecter
sans avoir à renseigner son mot de passe.
Volatility 2 a la capacité bien pratique de pouvoir reconstruire l'arborescence d'un système Linux à partir des fichiers en cache,
nous allons donc nous en servir pour récupérer le plus de fichiers possible une bonne fois pour toutes.
Volatility 2 est malheureusement assez discret vis-à-vis de ses plugins Linux,
mais nous pouvons obtenir le nom de celui qui nous intéresse via vol2 --info
.
Le plugin linux_recover_filesystem
est particulièrement efficace, tellement même qu'il reconstruit également les permissions des fichiers.
Comme le vidage mémoire contient évidement des fichiers spéciaux ou appartenant à root, il faut élever nos permissions pour l'exécuter.
Nous n'aurons à priori pas besoin d'avoir les permissions exactes des fichiers, nous allons les changer par souci
de praticité.
Memdump ➜ mkdir fsystem
Memdump ➜ sudo vol2 -f HSR2023.dmp --profile=LinuxDebian_5_10_0-21-amd64_profilex64 linux_recover
_filesystem --dump-dir fsystem
[sudo] Mot de passe de smyler:
Volatility Foundation Volatility Framework 2.6.1
WARNING : volatility.debug : Overlay structure cpuinfo_x86 not present in vtypes
WARNING : volatility.debug : Overlay structure cpuinfo_x86 not present in vtypes
WARNING : volatility.debug : Unable to process file: fsystem/ : [Errno 21] Is a directory: 'fs
ystem/'
Recovered 22941 files
Memdump ➜ sudo chown -R smyler:smyler fsystem
Nous pouvons maintenant récupérer le fichier qui nous intéresse :
Memdump ➜ cd fsystem
fsystem ➜ ls
dev media proc run sys var
fsystem ➜ ls var/tmp/home/forensic/.ssh
authorized_keys
fsystem ➜ cat var/tmp/home/forensic/.ssh/authorized_keys
echo "ssh-rsa TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVlciBhZGlwaXNjaW5nIGVsaXQuIEFlbmV
hbiBjb21tb2RvIGxpZ3VsYSBlZ2V0IGRvbG9yLiBBZW5lYW4gbWFzc2EuIEN1bSBzb2NpaXMgbmF0b3F1ZSBwZW5hdGlidXMg
ZXQgbWFnbmlzIGRpcyBwYXJ0dXJpZW50IG1vbnRlcywgbmFzY2V0dXIgcmlkaWN1bHVzIG11cy4gRG9uZWMgcXVhbSBmZWxpc
ywgdWx0cmljaWVzIG5lYywgcGVsbGVudGVzcXVlIGV1LCBwcmV0aXVtIHF1aXMsIHNlbS4gTnVsbGEgY29uc2VxdWF0IG1hc3
NhIHF1aXMgZW5pbS4gRG9uZWMgcGVkZSBqdXN0bywgZnJpbmdpbGxhIHZlbCwgYWxpcXVldCBuZWMsIHZ1bHB1dGF0ZSBlZ2V
0LCBhcmN1LiBJbiBlbmltIGp1c3RvLCByaG9uY3VzIHV0LCBpbXBlcmRpZXQgYSwgdmVuZW5hdGlzIHZpdGFlLCBqdXN0by4g
TnVsbGFtIGRpY3R1bSBmZWxpcyBldSBwZWRlIG1vbGxpcyBwcmV0aXVtLiBJbnRlZ2VyIHRpbmNpZHVudC4gQ3JhcyBkYXBpY
nVzLiBWaXZhbXVzIGVsZW1lbnR1bSBzZW1wZXIgbmlzaS4gSFNSe0FfRnIzM19GbEBnX2IzY2F1czNfYV9GMWwzX2luX00zbW
9yeX0uIEFlbmVhbiB2dWxwdXRhdGUgZWxlaWZlbmQgdGVsbHVzLiBBZW5lYW4gbGVvIGxpZ3VsYSwgcG9ydHRpdG9yIGV1LCB
jb25zZXF1YXQgdml0YWUsIGVsZWlmZW5kIGFjLCBlbmltLiBBbGlxdWFtIGxvcmVtIGFudGUsIGRhcGlidXMgaW4sIHZpdmVy
cmEgcXVpcywgZmV1Z2lhdCBhLCB0ZWxsdXMuIFBoYXNlbGx1cyB2aXZlcnJhIG51bGxhIHV0IG1ldHVzIHZhcml1cyBsYW9yZ
WV0LiBRdWlzcXVlIHJ1dHJ1bS4gQWVuZWFuIGltcGVyZGlldC4gRXRpYW0gdWx0cmljaWVzIG5pc2kgdmVsIGF1Z3VlLiBDdX
JhYml0dXIgdWxsYW1jb3JwZXIgdWx0cmljaWVzIG5pc2kuIE5hbSBlZ2V0IGR1aS4gRXRpYW0gcmhvbmN1cy4g makhno@for
ensic" >> /home/forensic/.ssh/authorized_keys && chmod 600 /home/forensic/.ssh/authorized_keys
Étrange, le fichier est mal formaté et contient une commande pour injecter la clé plutôt que la clé elle-même. Le flag se trouve cependant dans la base64 de cette dernière.
Memdump ➜ echo TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVlciBhZGlwaXNjaW5nIGVsaXQuIEFlbm
VhbiBjb21tb2RvIGxpZ3VsYSBlZ2V0IGRvbG9yLiBBZW5lYW4gbWFzc2EuIEN1bSBzb2NpaXMgbmF0b3F1ZSBwZW5hdGlidXM
gZXQgbWFnbmlzIGRpcyBwYXJ0dXJpZW50IG1vbnRlcywgbmFzY2V0dXIgcmlkaWN1bHVzIG11cy4gRG9uZWMgcXVhbSBmZWxp
cywgdWx0cmljaWVzIG5lYywgcGVsbGVudGVzcXVlIGV1LCBwcmV0aXVtIHF1aXMsIHNlbS4gTnVsbGEgY29uc2VxdWF0IG1hc
3NhIHF1aXMgZW5pbS4gRG9uZWMgcGVkZSBqdXN0bywgZnJpbmdpbGxhIHZlbCwgYWxpcXVldCBuZWMsIHZ1bHB1dGF0ZSBlZ2
V0LCBhcmN1LiBJbiBlbmltIGp1c3RvLCByaG9uY3VzIHV0LCBpbXBlcmRpZXQgYSwgdmVuZW5hdGlzIHZpdGFlLCBqdXN0by4
gTnVsbGFtIGRpY3R1bSBmZWxpcyBldSBwZWRlIG1vbGxpcyBwcmV0aXVtLiBJbnRlZ2VyIHRpbmNpZHVudC4gQ3JhcyBkYXBp
YnVzLiBWaXZhbXVzIGVsZW1lbnR1bSBzZW1wZXIgbmlzaS4gSFNSe0FfRnIzM19GbEBnX2IzY2F1czNfYV9GMWwzX2luX00zb
W9yeX0uIEFlbmVhbiB2dWxwdXRhdGUgZWxlaWZlbmQgdGVsbHVzLiBBZW5lYW4gbGVvIGxpZ3VsYSwgcG9ydHRpdG9yIGV1LC
Bjb25zZXF1YXQgdml0YWUsIGVsZWlmZW5kIGFjLCBlbmltLiBBbGlxdWFtIGxvcmVtIGFudGUsIGRhcGlidXMgaW4sIHZpdmV
ycmEgcXVpcywgZmV1Z2lhdCBhLCB0ZWxsdXMuIFBoYXNlbGx1cyB2aXZlcnJhIG51bGxhIHV0IG1ldHVzIHZhcml1cyBsYW9y
ZWV0LiBRdWlzcXVlIHJ1dHJ1bS4gQWVuZWFuIGltcGVyZGlldC4gRXRpYW0gdWx0cmljaWVzIG5pc2kgdmVsIGF1Z3VlLiBDd
XJhYml0dXIgdWxsYW1jb3JwZXIgdWx0cmljaWVzIG5pc2kuIE5hbSBlZ2V0IGR1aS4gRXRpYW0gcmhvbmN1cy4g | base64
-d
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenea
n massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Do
nec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis eni
m. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut,
imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidu
nt. Cras dapibus. Vivamus elementum semper nisi. HSR{A_Fr33_Fl@g_b3caus3_a_F1l3_in_M3mory}. Aene
an vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, eni
m. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut m
etus varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur
ullamcorper ultricies nisi. Nam eget dui. Etiam rhoncus.
Troisième flag
L'intitulé du challenge nous parle de fichiers exfiltrés et chiffrés. Nous allons donc nous intéresser au fichier PDF chiffré avec GPG. Il semble avoir été extrait par Volatility 2, mais malheureusement, nous avons une mauvaise surprise en l'ouvrant.
Le fichier chiffré est lui bien présent. On en récupère la version en base64 pour éviter les erreurs de taille (volatility extrait parfois plus que simplement le fichier dont nous avons besoin).
Memdump ➜ find -name flag.enc.b64
./var/tmp/home/forensic/volatility/tools/linux/HSR/flag.enc.b64
Memdump ➜ cat ./var/tmp/home/forensic/volatility/tools/linux/HSR/flag.enc.b64 | base64 -d > ../fl
ag.enc
Il va maintenant nous falloir la clé. Il y a une chance qu'elle se trouve dans l'agent GPG si ce dernier est toujours actif.
Memdump ➜ vol3 -f HSR2023.dmp linux.pslist.PsList | grep gpg
0x93f3424a2f80.0833 833 699ckinggpg-agent
0x93f34a29af80 1512 1512 1 gpg-agent
Après une courte recherche, on trouve ce plugin pour Volatility 3 qui devrait faire l'affaire.
Memdump ➜ git clone 'https://github.com/kudelskisecurity/volatility-gpg'
Clonage dans 'volatility-gpg'...
remote: Enumerating objects: 88, done.
remote: Counting objects: 100% (88/88), done.
remote: Compressing objects: 100% (59/59), done.
remote: Total 88 (delta 40), reused 67 (delta 21), pack-reused 0
Réception d'objets: 100% (88/88), 36.13 Kio | 973.00 Kio/s, fait.
Résolution des deltas: 100% (40/40), fait.
Memdump ➜ vol3 -f HSR2023.dmp -p volatility-gpg linux.gpg_full
Volatility 3 Framework 2.4.0
Progress: 100.00 Stacking attempts finished
Offset Private key Secret size Plaintext
Searching from 26 Mar 2023 15:54:30 UTC to 12 Sep 2023 06:06:55 UTC
Searching from 26 Mar 2023 15:54:41 UTC to 12 Sep 2023 06:06:55 UTC
0x7f68d4002608 8d3a913a7950cfa2572d8fb5831cb4e6 64 !!*V3ryverylongP@ssphrase*_HSR202
3!!
0x7f68d4002608 8d3a913a7950cfa2572d8fb5831cb4e6 64 !!*V3ryverylongP@ssphrase*_HSR202
3!!
Memdump ➜ vol3 -f HSR2023.dmp -p volatility-gpg linux.gpg_full
Memdump ➜ gpg -d flag.enc > flag.pdf
gpg: données chiffrées avec AES256.CFB
gpg: chiffré avec 1 phrase secrète
On rentre le mot de passe extrait, et on obtient un PDF avec l'affiche du HSR et le flag.
Quatrième flag
Il ne nous reste plus qu'un seul fil à tirer : le ransomware. Nous tentons de récupérer son code source, mais ce dernier ne semble pas être présent dans le vidage. En revanche, le binaire s'y trouve.
fsystem ➜ sudo find -name a.c
fsystem ➜ sudo find -name ransomware.o
./var/tmp/home/forensic/volatility/tools/linux/HSR/ransomware.o
./media/sf_DUMP/HSR/ransomware.o
fsystem ➜ cp media/sf_DUMP/HSR/ransomware.o ..
Nous ouvrons ensuite l'exécutable dans Ghidra et remarquons une function decrypt_master
qui fait un xor entre une section mémoire et un short.
En cherchant les références à la fonction, on voit qu'elle est appelée avec une entrée utilisateur.
En supposant que la section mémoire déchiffrée soit le flag, nous disposons d'un clair connu (HSR{
).
En sortant le chiffré et en écrivant un court script python, on obtient le flag :
enc = bytes.fromhex("989982b1a8faa295e1b98fade0fab49593b8a9baa4fa8fa5a2959efaa4b7")
dec = bytearray()
key1 = enc[0] ^ ord('H')
key2 = enc[1] ^ ord('S')
for i, x in enumerate(enc):
if i % 2 == 0:
dec.append(key1 ^ x)
else:
dec.append(key2 ^ x)
print(dec)
Memdump ➜ vim main.py
Memdump ➜ python main.py
bytearray(b'HSR{x0r_1s_g00d_Crypt0_or_N0t}')