Avatar

Smyler.net

Hacking, software development, networking and everything in between

Memdump

CTF writeup: HackSecuReims 2023

2023/03/27

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 installer linux-image-<version>-dbg en plus de linux-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 :

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 :

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.

Okteta screenshot - 0x00

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

GPG password prompt screenshot

On rentre le mot de passe extrait, et on obtient un PDF avec l'affiche du HSR et le flag.

Okular flag document screenshot

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.

Ghidra screenshot Ghidra screenshot Ghidra screenshot

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}')

Related resources:

More articles