Paalkia CTF

Hexagone CTF / Forensics / Panthère Silencieuse 4/4

Hard T1573 Opération Panthère Silencieuse

Panthère Silencieuse 4/4

C2 en mémoire

01Énoncé

Une image mémoire de FIN-WKS-07 a été acquise alors que l'intrusion était encore active, accompagnée d'un fichier récupéré sur le poste. Extrais le secret de l'opérateur. Format du flag : RWX{...}

02Contexte

Dernière pièce de l'enquête sur FIN-WKS-07. Une image mémoire du poste a été acquise pendant que l'intrusion était encore active, et un fichier a été récupéré sur le disque. Il faut extraire le secret de l'opérateur.

TTP de référence : canal C2 chiffré (T1573) via le framework Sliver, utilisé notamment par APT29 et des groupes ransomware.

03Artefacts

PANTHERE-EVD-04.7z contenant :

  • FIN-WKS-07.elf : image mémoire (4 Go de RAM, format core dump VirtualBox)
  • creds.enc : fichier de 112 octets récupéré sur le poste
  • un fichier de symboles Volatility (.json.xz) pour une analyse hors ligne

04Difficulté

Le fichier récupéré est illisible et ne porte aucun indice sur son format. La clé n'est nulle part sur le disque : elle n'existe qu'en mémoire, au milieu de dizaines de processus. Le secret n'apparaît jamais en clair dans l'image mémoire : une recherche de chaînes ne donne rien.

05Résolution

Étape 1 : examiner le fichier récupéré

creds.enc ouvert dans HxD
Detect File Type dans CyberChef

Équivalent sous Linux :

bash
file creds.enc
xxd creds.enc

Le fichier fait 112 octets. Dans HxD, aucun en-tête reconnaissable : ni signature de format, ni le préfixe Salted__ d'un chiffrement OpenSSL, et aucun texte lisible. L'opération Detect File Type de CyberChef ne reconnaît aucun format. Les octets semblent aléatoires. La taille, 112 octets, est un multiple de 16 : c'est la taille de bloc d'AES. Hypothèse : un fichier chiffré par bloc. Il faut une clé, et l'image mémoire est le seul endroit où elle peut se trouver.

Étape 2 : lister les processus

bash
vol3 -f FIN-WKS-07.elf windows.pstree

L'arbre compte plus de 180 processus. Pour le trier sans connaître le nom de l'implant, on applique trois critères classiques :

  • un exécutable lancé depuis un répertoire utilisateur (Downloads, AppData, Temp) plutôt que depuis Windows ou Program Files ;
  • un processus orphelin, dont le parent n'existe plus ;
  • un interpréteur de commandes (cmd.exe, powershell.exe) dans la session de l'utilisateur.
Sortie de windows.pstree

FacturePro_Update.exe (PID 7612) coche les deux premiers critères : il s'exécute depuis C:\Users\j.martin\Downloads\ depuis 11:33:13, et son parent (PID 4472) n'existe plus. Un binaire au nom de logiciel métier, téléchargé, dont le processus lanceur a disparu : c'est le candidat le plus probable pour l'implant.

explorer.exe PID 5336

explorer.exe (PID 5336).

cmd.exe PID 11236

cmd.exe (PID 11236), PPID 5336 : son père est donc explorer.exe.

powershell.exe PID 5916 et 3020
powershell.exe PID 9836

Les captures montrent la filiation : explorer.exe (PID 5336) est le parent de cmd.exe (PID 11236) et de powershell.exe (PID 5916), lui-même parent de deux PowerShell lancés en arrière-plan (PID 3020 et 9836, options -s -NoLogo -NoProfile).

Sous explorer.exe, deux interpréteurs :

  • powershell.exe (PID 5916) et ses deux PowerShell d'arrière-plan, dont l'un (3020) ouvre et ferme en boucle Notepad, la Calculatrice et Paint : activité répétitive et automatisée, du bruit ;
  • cmd.exe (PID 11236), ouvert à 11:42:40, quelques instants avant l'acquisition, toujours actif.

Deux suspects à creuser : l'implant (7612) et la console (11236).

Étape 3 : examiner les suspects

La colonne Cmd du pstree montre qu'aucun des deux n'a été lancé avec des arguments : pas de clé passée en ligne de commande. Autre endroit où un opérateur place la configuration de ses outils sans rien écrire sur le disque : les variables d'environnement. Une variable définie dans une console (set VARIABLE=valeur) reste dans la mémoire de ce processus, dans son PEB. Le plugin windows.envars les extrait.

bash
vol3 -f FIN-WKS-07.elf windows.envars --pid 7612
windows.envars sur le PID 7612 : aucune variable

Aucune variable n'est récupérée pour l'implant : son bloc d'environnement n'est probablement pas lisible dans l'image (pages mémoire absentes de la RAM au moment de l'acquisition). Une limite courante de l'analyse mémoire.

bash
vol3 -f FIN-WKS-07.elf windows.envars --pid 11236
windows.envars sur le PID 11236

La console, elle, livre ses variables. On y retrouve les variables standard d'une session Windows (USERNAME, Path, TEMP...), les variables EFC_5336_* héritées de son parent explorer.exe (PID 5336), et PROMPT, propre à cmd.exe. Une seule est inconnue de Windows : SLIVER_C2KEY. Sliver est un framework C2 open source.

Sa valeur, 4cf9ac1a589118c84f37895698d958da8c65aff28221cae3e2aa8f0c775084ef, fait 64 caractères hexadécimaux, soit 32 octets : la taille exacte d'une clé AES-256.

PowerShell
vol3 -q -r csv -f FIN-WKS-07.elf windows.envars | ConvertFrom-Csv | Group-Object Variable | Sort-Object Count | Select-Object -First 20 Count,Name
Noms de variables les plus rares sur tous les processus

Pour s'assurer qu'aucun autre processus ne cache une variable du même genre, on compte les occurrences de chaque nom sur tous les processus et on affiche les plus rares. Certains noms sont tronqués (SERPROFILE, OMAIN...) : des pages mémoire partiellement indisponibles, à ignorer. Parmi les noms complets présents une seule fois, __COMPAT_LAYER, PROMPT ou EFC_* sont des variables Windows courantes. SLIVER_C2KEY est la seule anomalie.

Étape 4 : déchiffrer

Clé de 32 octets en mémoire, fichier de 112 octets (multiple de 16) : tout concorde avec de l'AES-256. Reste le mode. Le plus courant est CBC, qui exige un vecteur d'initialisation (IV) de 16 octets, souvent placé en tête du fichier chiffré. Hypothèse : 16 octets d'IV + 96 octets de données chiffrées.

On ouvre creds.enc dans HxD.

Les 16 premiers octets de creds.enc : l’IV

On lit l'IV directement dans les 16 premiers octets du fichier : 2637E35F9CA73C6216EDF76477A42CD9. Le fichier compte 7 lignes de 16 octets : 1 bloc d'IV suivi de 6 blocs chiffrés, une structure cohérente avec de l'AES en mode CBC.

Drop bytes puis AES Decrypt dans CyberChef

Drop bytes retire l'IV des données à déchiffrer, AES Decrypt applique la clé et l'IV. Le résultat est un fichier de configuration lisible, ce qui valide l'hypothèse AES-256-CBC. C'est la configuration C2 de l'opérateur : profil de communication mTLS, nom d'opérateur, et le secret dans le champ recovery.

Alternative en Python :

python
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
d = open("creds.enc","rb").read()
k = bytes.fromhex("4cf9ac1a589118c84f37895698d958da8c65aff28221cae3e2aa8f0c775084ef")
print(unpad(AES.new(k, AES.MODE_CBC, d[:16]).decrypt(d[16:]), 16).decode())

Pourquoi strings ne suffit pas

strings extrait les chaînes de caractères lisibles d'un fichier binaire. Sous Windows, l'outil de Sysinternals cherche à la fois l'ASCII et l'Unicode. Sous Linux, il faut deux passes : la première pour l'ASCII, la seconde avec -el pour l'UTF-16 little-endian, l'encodage natif de Windows (utilisé notamment pour les variables d'environnement et les chemins). L'option -a force l'analyse du fichier entier.

Dans les deux cas, la recherche de RWX{ ne renvoie rien : le secret n'existe en clair nulle part dans l'image mémoire. Seule la clé y figure. Il faut relier la mémoire et le fichier pour reconstituer la chaîne.

06Flag

RWX{m3m0ry_k3y_unl0cks_c2_v4ult}

07Pistes de détection

  • Un exécutable lancé depuis le profil utilisateur dont le processus parent a disparu.
  • Une variable d'environnement inconnue de Windows qui ressemble à une clé ou à un secret.
  • Une console cmd.exe ouverte de façon interactive pendant l'intrusion.
  • MITRE ATT&CK : T1573.

08Note du concepteur

Objectif pédagogique

Relier une image mémoire et un fichier chiffré pour retrouver un secret. Il faut reconnaître un fichier chiffré par bloc à partir de sa seule taille, trier plus de 180 processus avec des critères simples (emplacement, processus orphelin, console interactive), puis chercher la clé là où un opérateur la laisse sans rien écrire sur le disque : les variables d'environnement. Le déchiffrement AES-256-CBC valide toute la chaîne.

Anti-triche

Un strings sur le dump (ASCII et UTF-16LE) ne renvoie aucun RWX. Le flag n'est atteignable que par la chaîne complète : variables d'environnement, clé, déchiffrement.