# Holmes CTF 2025 - The Tunnel Without Walls  [4/4]

Quatrième épreuves du CTF “Holmes CTF 2025”

## **The Tunnel Without Walls**

*A memory dump from a connected Linux machine reveals covert network connections, fake services, and unusual redirects. Holmes investigates further to uncover how the attacker is manipulating the entire network!*

Dans ce challenge, nous disposons d'un dump mémoire Linux\*\*.\*\*

*   `memdump.mem`
    

L’analyse est réalisée principalement avec **Volatility 3**, complétée par différentes commandes Linux (`strings`, `grep`, `john`, etc.) lorsque cela est nécessaire.

Difficulté : 🟩🟧🟥 - Hard

### Questions

**1 - What is the Linux kernel version of the provided image? (string)**

La commande [`windows.info`](http://windows.info) n’étant pas compatible avec une image Linux, nous pouvons utiliser le plugin suivant :

*   `banners.Banners`
    

![](https://cdn.hashnode.com/uploads/covers/6844a65884f0259d1edf0aa9/2b7879ae-a804-4d76-8cfd-d3fe2e4c69e6.png align="center")

✅ Réponse : `5.10.0-35`

**2 - The attacker connected over SSH and executed initial reconnaissance commands. What is the PID of the shell they used? (number)**

⚠️ La première étape consiste à télécharger les symboles permettant de débloquer les fonctionnalités de Volatility pour cette version précise du kernel Linux.

Les symboles sont disponibles ici :

*   [Volatility 3 Debian symbols](https://github.com/Abyss-W4tcher/volatility3-symbols/tree/master/Debian/amd64/5.10.0/35)
    

Une fois les symboles installés, nous pouvons commencer à analyser le dump mémoire.

Ce que nous cherchons ici est le shell utilisé par l’attaquant. De plus, ce shell doit être lié à un processus SSH.

Nous pouvons commencer par lister les processus avec :

`python3` [`vol.py`](http://vol.py) `-f memdump.mem linux.psaux.PsAux`

En filtrant les résultats, nous pouvons identifier les différents processus SSH :

![](https://cdn.hashnode.com/uploads/covers/6844a65884f0259d1edf0aa9/360a0514-4aeb-472a-b85b-fd1209df630f.png align="center")

Nous pouvons également retrouver les différents processus `bash` :

![](https://cdn.hashnode.com/uploads/covers/6844a65884f0259d1edf0aa9/d2628936-eb51-4778-b3b0-42442029036b.png align="center")

L’un des processus `bash` provient d’une session SSH, comme nous pouvons le voir grâce à son processus parent (`13607`). Nous pouvons donc en conclure qu’il s’agit du shell utilisé par l’attaquant.

✅ Réponse : `13608`

**3 - After the initial information gathering, the attacker authenticated as a different user to escalate privileges. Identify and submit that user's credentials. (user:password)**

Ici, deux informations sont nécessaires pour valider le flag :

*   le nom d’utilisateur ;
    
*   le mot de passe.
    

Cherchons ces informations étape par étape.

En regardant les commandes exécutées par le processus `bash` identifié dans la question précédente, nous pouvons facilement retrouver le nom de l’utilisateur :

![](https://cdn.hashnode.com/uploads/covers/6844a65884f0259d1edf0aa9/052ccc84-dfe7-4dd8-aebb-df96f4b938ab.png align="center")

Première réponse, nom d’utilisateur **:** `jm`

Pour retrouver le mot de passe, nous devons maintenant récupérer deux fichiers présents dans le dump mémoire :

*   `/etc/passwd`
    
*   `/etc/shadow`
    

Nous allons utiliser le plugin `linux.pagecache.InodePages`.

Sous Linux, le page cache conserve en mémoire les données des fichiers récemment lus ou écrits. Ce plugin permet notamment de :

*   parcourir les inodes présents en mémoire ;
    
*   retrouver les pages de cache associées à chaque inode ;
    
*   afficher les informations relatives à ces pages (adresses mémoire, index des pages, etc.) ;
    
*   reconstruire ou analyser le contenu des fichiers encore présents dans le page cache.
    

Cela va nous permettre de retrouver nos fichiers et, si possible, d’en extraire leur contenu.

Nous utilisons la commande suivante :

`python3` [`vol.py`](http://vol.py) `-f memdump.mem -o /htb/htb_sherlock/tunnels/ linux.pagecache.InodePages --dump --find /etc/passwd`

Nous faisons ensuite la même chose pour `/etc/shadow`.

Le résultat est plutôt positif :

![](https://cdn.hashnode.com/uploads/covers/6844a65884f0259d1edf0aa9/fffe0a0f-b95e-4701-b747-5ff6e433881b.png align="center")

Nous avons donc accès aux deux fichiers, en cherchant dedans :

![](https://cdn.hashnode.com/uploads/covers/6844a65884f0259d1edf0aa9/9e2a71a7-e710-4513-97ff-497ff57e0659.png align="center")

Nous obtenons la première information nécessaire pour retrouver le mot de passe : son hash.

Il faut maintenant tenter de retrouver le mot de passe correspondant à ce hash.

*   `jm` → nom de l’utilisateur ;
    
*   `$1$` → indique un hash **MD5 crypt** (ancien format `md5crypt`) ;
    
*   `jm$poAH2RyJp8ZllyUvIkxxd0` → correspond au hash du mot de passe.
    

J’utilise **John the Ripper** afin de retrouver le mot de passe correspondant à ce hash :

`john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt`

John the Ripper parvient à retrouver le mot de passe.

![](https://cdn.hashnode.com/uploads/covers/6844a65884f0259d1edf0aa9/07065aff-c2c3-4c21-a154-e1b249c838c7.png align="center")

✅ Réponse : `jm:WATSON0`

**4 - The attacker downloaded and executed code from Pastebin to install a rootkit. What is the full path of the malicious file? (/path/filename.ext)**

Un **rootkit** est un type de malware conçu pour dissimuler sa présence ou celle d’autres logiciels malveillants. Il peut modifier le fonctionnement du système en agissant à différents niveaux : espace utilisateur, kernel, firmware, etc.

Il peut notamment permettre de cacher des processus, des fichiers ou encore des connexions réseau.

D’après cette définition, un plugin Volatility est particulièrement intéressant pour détecter ce type de malware :

*   `linux.malware.hidden_modules.Hidden_modules` ([documentation](https://volatility3.readthedocs.io/en/latest/volatility3.plugins.linux.malware.hidden_modules.html))
    

Ce plugin permet de détecter des modules kernel Linux qui sont chargés en mémoire mais qui ont été retirés des listes officielles du kernel.

Un rootkit peut charger un module kernel puis le retirer de la liste des modules chargés. Cela permet notamment d’éviter sa détection avec des commandes telles que :

*   `lsmod`
    
*   `cat /proc/modules`
    

![](https://cdn.hashnode.com/uploads/covers/6844a65884f0259d1edf0aa9/13b470ce-5a54-4f68-af47-74bc5d5292ba.png align="center")

En cherchant via `strings` dans le dump via `strings memdump.mem | egrep -i 'Nullincrevenge.ko' | head -n 50` :

![](https://cdn.hashnode.com/uploads/covers/6844a65884f0259d1edf0aa9/05863970-81b1-479f-a705-60535d2d18bd.png align="center")

En recherchant ensuite le fichier dans le cache avec :

`python3` [`vol.py`](http://vol.py) `-f memdump.mem linux.pagecache.Files | grep "Nullincrevenge"`

Nous retrouvons le chemin complet du fichier malveillant.

✅ Réponse : `/usr/lib/modules/5.10.0-35-amd64/kernel/lib/Nullincrevenge.ko`

**5 - What is the email account of the alleged author of the malicious file? (**[**user@example.com**](mailto:user@example.com)**)**

Nous allons commencer par extraire le fichier :

`python3` [`vol.py`](http://vol.py) `-f memdump.mem linux.pagecache.InodePages -o /dumpfile/ --find /usr/lib/modules/5.10.0-35-amd64/kernel/lib/Nullincrevenge.ko --dump`

Puis, avec `strings` sur le fichier extrait :

`strings inode_0x9b3386454a80.dmp`

Nous pouvons retrouver l’adresse e-mail associée au fichier malveillant :

![](https://cdn.hashnode.com/uploads/covers/6844a65884f0259d1edf0aa9/7c2f0fc4-8710-4d72-971b-fc1174e14db0.png align="center")

✅ Réponse : `i-am-the@network.now`

**6 - The next step in the attack involved issuing commands to modify the network settings and installing a new package. What is the name and PID of the package? (package name,PID)**

Lorsqu’il s’agit d’identifier les commandes exécutées par l’attaquant, nous pouvons directement utiliser le plugin :

`python3` [`vol.py`](http://vol.py) `-f memdump.mem linux.bash.Bash`

![](https://cdn.hashnode.com/uploads/covers/6844a65884f0259d1edf0aa9/569160e0-e391-424c-b614-b0ae24a2c61e.png align="center")

Nous pouvons notamment observer l’installation et l’exécution de `dnsmasq`.

`dnsmasq` est un logiciel pouvant notamment servir de serveur DNS, de cache DNS et de serveur DHCP, notamment pour les petits réseaux.

Nous devons maintenant retrouver son PID.

Pour cela :

`python3` [`vol.py`](http://vol.py) `-f memdump.mem linux.psaux | grep "dnsmasq"`

Et le processus correspondant apparaît dans les résultats :

![](https://cdn.hashnode.com/uploads/covers/6844a65884f0259d1edf0aa9/111741a2-3446-4562-994a-320c71644cff.png align="center")

✅ Réponse : `dnsmasq,38687`

**7 - Clearly, the attacker's goal is to impersonate the entire network. One workstation was already tricked and got its new malicious network configuration. What is the workstation's hostname?**

Si nous reprenons les commandes observées avec :

`python3` [`vol.py`](http://vol.py) `-f memdump.mem linux.bash.Bash`

![](https://cdn.hashnode.com/uploads/covers/6844a65884f0259d1edf0aa9/270841f5-fbfe-44db-a2c9-3028d9067c5a.png align="center")

Nous pouvons comprendre que l’attaquant met en place une attaque **MITM (Man-In-The-Middle)** afin de pouvoir contrôler le trafic du réseau depuis une machine compromise.

Nous pouvons également voir qu’un fichier de configuration `dnsmasq` est utilisé.

Nous allons donc l’extraire :

`python3` [`vol.py`](http://vol.py) `-f memdump.mem -o dump_file/dnsmasq.conf linux.pagecache.InodePages --find /etc/dnsmasq.conf --dump`

Puis, en utilisant `strings` sur le fichier récupéré :

![](https://cdn.hashnode.com/uploads/covers/6844a65884f0259d1edf0aa9/008cec46-b95d-4ce7-bdc6-805e91a072c7.png align="center")

Nous disposons désormais de suffisamment d’informations concernant la configuration utilisée pour le MITM.

En recherchant dans le dump les adresses IP correspondant au réseau [`192.168.211.XXX`](http://192.168.211.XXX) :

`strings memdump.mem | grep -E '192.168.211.[0-9]{1,3}'`

Nous retrouvons notamment l’adresse IP ainsi que le nom de la workstation compromise.

✅ Réponse : `Parallax-5-WS-3`

**8 - After receiving the new malicious network configuration, the user accessed the City of CogWork-1 internal portal from this workstation. What is their username? (string)**

En recherchant la chaîne `username=` dans le dump :

`strings memdump.mem | grep -i 'username='`

Nous pouvons retrouver plusieurs éléments intéressants :

![](https://cdn.hashnode.com/uploads/covers/6844a65884f0259d1edf0aa9/c0bc00e7-d0f3-47d6-a9a5-ccece1ba757d.png align="center")

Avec ces nouveaux éléments, nous pouvons effectuer une recherche plus précise :

`strings memdump.mem | grep -i -C 10 "mike.sullivan"`

![](https://cdn.hashnode.com/uploads/covers/6844a65884f0259d1edf0aa9/235ae2ec-6c76-49d8-b0f6-8a05cc7ff528.png align="center")

Nous pouvons voir que l’identifiant retrouvé est utilisé pour se connecter à une adresse IP privée correspondant au portail interne.

✅ Réponse : `mike.sullivan`

**9 - Finally, the user updated a software to the latest version, as suggested on the internal portal, and fell victim to a supply chain attack. From which Web endpoint was the update downloaded?**

En cherchant `strings memdump.mem | grep -E '192.168.211.[0-9]{1,3}'` on tombe sur quelque chose d'intéressant qui correspond parfaitement à ce que l'on cherche dans la question :

![](https://cdn.hashnode.com/uploads/covers/6844a65884f0259d1edf0aa9/1a972a5b-fe95-42e2-aaaa-8745cbf414ae.png align="center")

✅ Réponse : `/win10/update/CogSoftware/AetherDesk-v74-77.exe`

**10 - To perform this attack, the attacker redirected the original update domain to a malicious one. Identify the original domain and the final redirect IP address and port. (domain,IP:port)**

En analysant à nouveau les résultats de :

`python3` [`vol.py`](http://vol.py) `-f memdump.mem linux.bash.Bash`

![](https://cdn.hashnode.com/uploads/covers/6844a65884f0259d1edf0aa9/173fb52f-e23d-42e8-8dca-78a51930b920.png align="center")

Nous pouvons comprendre que le conteneur Docker sert notamment de serveur Web.

Le but est donc de récupérer le fichier de configuration `default.conf`.

Nous pouvons le retrouver avec :

`python3` [`vol.py`](http://vol.py) `-f memdump.mem linux.pagecache.Files | grep "/tmp/default.conf"`

Nous retrouvons bien le fichier et pouvons l’extraire avec :

`python3` [`vol.py`](http://vol.py) `-f memdump.mem -o dump_file linux.pagecache.InodePages --find /tmp/default.conf --dump`

Nous pouvons désormais consulter son contenu :

![](https://cdn.hashnode.com/uploads/covers/6844a65884f0259d1edf0aa9/2c9242b8-8fd5-4f2d-9ffa-863c26d3883e.png align="center")

Nous observons notamment une adresse IP externe associée à un port peu commun. C’est un bon point de départ.

Il faut maintenant retrouver l’adresse de redirection.

En reprenant la configuration de `dnsmasq` :

![](https://cdn.hashnode.com/uploads/covers/6844a65884f0259d1edf0aa9/e20957eb-d68b-46a6-8183-85450f98eed6.png align="center")

Nous pouvons alors assembler les deux informations afin d’obtenir la réponse finale.

✅ Réponse : [`updates.cogwork-1.net:`](http://updates.cogwork-1.net:13)`13.62.49.86:7477`
