
Détection basée sur des signatures de caractéristiques de logiciels malveillants basées sur des séquences d'appels d'API Windows. C'est comme YARA pour les traces d'API de sandbox !
dynmx (prononcé dynamics) est une approche de détection basée sur des signatures pour les caractéristiques comportementales des logiciels malveillants, fondée sur les séquences d'appels API Windows. De manière simplifiée, vous pouvez considérer dynmx comme une sorte de YARA pour les traces d'appels API (appelées journaux de fonctions) provenant de sandboxes de logiciels malveillants. Ainsi, la base de données pour l'approche de détection n'est pas constituée par les échantillons de logiciels malveillants eux-mêmes, analysés de manière statique, mais par des données générées lors d'une analyse dynamique de l'échantillon dans une sandbox. Actuellement, dynmx prend en charge les journaux de fonctions des sandboxes suivantes :
report.json)report.json)L'approche de détection est décrite en détail dans le mémoire de master Signature-Based Detection of Behavioural Malware Features with Windows API Calls. Ce projet est l'implémentation prototype de cette approche, développée dans le cadre du mémoire de master. Les signatures sont définies manuellement par des analystes de logiciels malveillants dans le DSL de signature dynmx et peuvent être détectées dans les journaux de fonctions à l'aide de cet outil. Les fonctionnalités et la syntaxe du DSL de signature dynmx se trouvent également dans le mémoire de master. De plus, vous trouverez des exemples de signatures dynmx dans le dépôt dynmx-signatures. En plus de détecter les caractéristiques des logiciels malveillants basées sur les appels API, dynmx peut extraire les ressources OS utilisées par le logiciel malveillant (un modèle d'activité d'accès). Ces ressources sont extraites en examinant les appels API et en reconstituant les opérations sur les ressources OS. Actuellement, les ressources OS des catégories système de fichiers, registre et réseau sont prises en compte dans le modèle.
Dans la section suivante, des exemples sont présentés pour la détection de caractéristiques de logiciels malveillants et pour l'extraction de ressources.
Pour cet exemple, nous choisissons l'échantillon de logiciel malveillant avec la somme de hachage SHA-256 c0832b1008aa0fc828654f9762e37bda019080cbdd92bd2453a05cfb3b79abb3. Selon MalwareBazaar, l'échantillon appartient à la famille de logiciels malveillants Amadey. Un rapport d'analyse VMRay public de cet échantillon est disponible, qui fournit également le journal de fonctions tracé par VMRay. Ce journal de fonctions sera notre base de données pour la détection.
Si nous souhaitons savoir si l'échantillon de logiciel malveillant utilise une technique d'injection appelée Process Hollowing, nous pouvons essayer de détecter la signature dynmx suivante dans le journal de fonctions.```yaml dynmx_signature: meta: name: process_hollow title: Process Hollowing description: Detection of Process hollowing malware feature detection: proc_hollow: # Create legit process in suspended mode - api_call: ["CreateProcess[AW]", "CreateProcessInternal[AW]"] with: - argument: "dwCreationFlags" operation: "flag is set" value: 0x4 - return_value: "return" operation: "is not" value: 0 store: - name: "hProcess" as: "proc_handle" - name: "hThread" as: "thread_handle" # Injection of malicious code into memory of previously created process - variant: - path: # Allocate memory with read, write, execute permission - api_call: ["VirtualAllocEx", "VirtualAlloc", "(Nt|Zw)AllocateVirtualMemory"] with: - argument: ["hProcess", "ProcessHandle"] operation: "is" value: "$(proc_handle)" - argument: ["flProtect", "Protect"] operation: "is" value: 0x40 - api_call: ["WriteProcessMemory"] with: - argument: "hProcess" operation: "is" value: "$(proc_handle)" - api_call: ["SetThreadContext", "(Nt|Zw)SetContextThread"] with: - argument: "hThread" operation: "is" value: "$(thread_handle)" - path: # Map memory section with read, write, execute permission - api_call: "(Nt|Zw)MapViewOfSection" with: - argument: "ProcessHandle" operation: "is" value: "$(proc_handle)" - argument: "AccessProtection" operation: "is" value: 0x40 # Resume thread to run injected malicious code - api_call: ["ResumeThread", "(Nt|Zw)ResumeThread"] with: - argument: ["hThread", "ThreadHandle"] operation: "is" value: "$(thread_handle)" condition: proc_hollow as sequence
Sur la base de la signature, nous pouvons trouver certaines fonctionnalités DSL qui rendent *dynmx* puissant :
* Définition de séquences d'appels API avec chemins alternatifs
* Correspondance des noms de fonctions d'appels API avec des expressions régulières
* Correspondance des valeurs d'argument et de retour avec plusieurs opérateurs
* Stockage de variables, par exemple pour suivre les handles dans la séquence d'appels API
* Définition d'une condition de détection avec des opérateurs booléens (`AND`, `OR`, `NOT`)
Si nous exécutons *dynmx* avec la signature montrée ci-dessus contre la fonction de l'échantillon `c0832b1008aa0fc828654f9762e37bda019080cbdd92bd2453a05cfb3b79abb3`, nous obtenons la sortie suivante indiquant que la signature a été détectée.```
$ python3 dynmx.py detect -i 601941f00b194587c9e57c5fabaf1ef11596179bea007df9bdcdaa10f162cac9.json -s process_hollow.yml
|
__| _ _ _ _ _
/ | | | / |/ | / |/ |/ | /\/
\_/|_/ \_/|/ | |_/ | | |_/ /\_/
/|
\|
Ver. 0.5 (PoC), by 0x534a
[+] Parsing 1 function log(s)
[+] Loaded 1 dynmx signature(s)
[+] Starting detection process with 1 worker(s). This probably takes some time...
[+] Result
process_hollow c0832b1008aa0fc828654f9762e37bda019080cbdd92bd2453a05cfb3b79abb3.txt
Nous pouvons entrer plus en détail en définissant le format de sortie sur detail. Maintenant, nous pouvons voir la séquence exacte d'appels API qui a été détectée dans le journal de la fonction. De plus, nous pouvons voir que la signature a été détectée dans le processus 51f0.exe.```
$ python3 dynmx.py -f detail detect -i 601941f00b194587c9e57c5fabaf1ef11596179bea007df9bdcdaa10f162cac9.json -s process_hollow.yml
|
__| _ _ _ _ _ / | | | / |/ | / |/ |/ | // _/|/ _/|/ | |/ | | |_/ /_/ /| |
Ver. 0.5 (PoC), by 0x534a
[+] Parsing 1 function log(s) [+] Loaded 1 dynmx signature(s) [+] Starting detection process with 1 worker(s). This probably takes some time...
[+] Result Function log: c0832b1008aa0fc828654f9762e37bda019080cbdd92bd2453a05cfb3b79abb3.txt Signature: process_hollow Process: 51f0.exe (PID: 3768) Number of Findings: 1 Finding 0 proc_hollow : API Call CreateProcessA (Function log line 20560, index 938) proc_hollow : API Call VirtualAllocEx (Function log line 20566, index 944) proc_hollow : API Call WriteProcessMemory (Function log line 20573, index 951) proc_hollow : API Call SetThreadContext (Function log line 20574, index 952) proc_hollow : API Call ResumeThread (Function log line 20575, index 953)
### Ressources
Afin d'extraire les ressources OS consultées à partir d'un journal de fonctions, nous pouvons simplement exécuter la commande *dynmx* `resources` sur le journal de fonctions. Un exemple de la sortie détaillée est présenté ci-dessous pour l'échantillon dont l'empreinte SHA-256 est `601941f00b194587c9e57c5fabaf1ef11596179bea007df9bdcdaa10f162cac9`. Il s'agit d'un rapport de sandbox CAPE qui fait partie du [Avast-CTU Public CAPEv2 Dataset](https://github.com/avast/avast-ctu-cape-dataset).```
$ python3 dynmx.py -f detail resources --input 601941f00b194587c9e57c5fabaf1ef11596179bea007df9bdcdaa10f162cac9.json
|
__| _ _ _ _ _
/ | | | / |/ | / |/ |/ | /\/
\_/|_/ \_/|/ | |_/ | | |_/ /\_/
/|
\|
Ver. 0.5 (PoC), by 0x534a
[+] Parsing 1 function log(s)
[+] Processing function log(s) with the command 'resources'...
[+] Result
Function log: 601941f00b194587c9e57c5fabaf1ef11596179bea007df9bdcdaa10f162cac9.json (/Users/sijansen/Documents/dev/dynmx_flogs/cape/Public_Avast_CTU_CAPEv2_Dataset_Full/extracted/601941f00b194587c9e57c5fabaf1ef11596179bea007df9bdcdaa10f162cac9.json)
Process: 601941F00B194587C9E5.exe (PID: 2008)
Filesystem:
C:\Windows\SysWOW64\en-US\SETUPAPI.dll.mui (CREATE)
API-MS-Win-Core-LocalRegistry-L1-1-0.dll (EXECUTE)
C:\Windows\SysWOW64\ntdll.dll (READ)
USER32.dll (EXECUTE)
KERNEL32.dll (EXECUTE)
C:\Windows\Globalization\Sorting\sortdefault.nls (CREATE)
Registry:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\OLEAUT (READ)
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Setup (READ)
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Setup\SourcePath (READ)
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion (READ)
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\DevicePath (READ)
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Internet Settings (READ)
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Internet Settings\DisableImprovedZoneCheck (READ)
HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\CurrentVersion\Internet Settings (READ)
HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\Security_HKLM_only (READ)
Process: 601941F00B194587C9E5.exe (PID: 1800)
Filesystem:
C:\Windows\SysWOW64\en-US\SETUPAPI.dll.mui (CREATE)
API-MS-Win-Core-LocalRegistry-L1-1-0.dll (EXECUTE)
C:\Windows\SysWOW64\ntdll.dll (READ)
USER32.dll (EXECUTE)
KERNEL32.dll (EXECUTE)
[...]
C:\Users\comp\AppData\Local\vscmouse (READ)
C:\Users\comp\AppData\Local\vscmouse\vscmouse.exe:Zone.Identifier (DELETE)
Registry:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\OLEAUT (READ)
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Setup (READ)
[...]
Process: vscmouse.exe (PID: 900)
Filesystem:
C:\Windows\SysWOW64\en-US\SETUPAPI.dll.mui (CREATE)
API-MS-Win-Core-LocalRegistry-L1-1-0.dll (EXECUTE)
C:\Windows\SysWOW64\ntdll.dll (READ)
USER32.dll (EXECUTE)
KERNEL32.dll (EXECUTE)
C:\Windows\Globalization\Sorting\sortdefault.nls (CREATE)
Registry:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\OLEAUT (READ)
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Setup (READ)
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Setup\SourcePath (READ)
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion (READ)
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\DevicePath (READ)
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Internet Settings (READ)
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Internet Settings\DisableImprovedZoneCheck (READ)
HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\CurrentVersion\Internet Settings (READ)
HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\Security_HKLM_only (READ)
Process: vscmouse.exe (PID: 3036)
Filesystem:
C:\Windows\SysWOW64\en-US\SETUPAPI.dll.mui (CREATE)
API-MS-Win-Core-LocalRegistry-L1-1-0.dll (EXECUTE)
C:\Windows\SysWOW64\ntdll.dll (READ)
USER32.dll (EXECUTE)
KERNEL32.dll (EXECUTE)
C:\Windows\Globalization\Sorting\sortdefault.nls (CREATE)
C:\ (READ)
C:\Windows\System32\uxtheme.dll (EXECUTE)
dwmapi.dll (EXECUTE)
advapi32.dll (EXECUTE)
shell32.dll (EXECUTE)
C:\Users\comp\AppData\Local\vscmouse\vscmouse.exe (CREATE,READ)
C:\Users\comp\AppData\Local\iproppass\iproppass.exe (DELETE)
crypt32.dll (EXECUTE)
urlmon.dll (EXECUTE)
userenv.dll (EXECUTE)
wininet.dll (EXECUTE)
wtsapi32.dll (EXECUTE)
CRYPTSP.dll (EXECUTE)
CRYPTBASE.dll (EXECUTE)
ole32.dll (EXECUTE)
OLEAUT32.dll (EXECUTE)
C:\Windows\SysWOW64\oleaut32.dll (EXECUTE)
IPHLPAPI.DLL (EXECUTE)
DHCPCSVC.DLL (EXECUTE)
C:\Users\comp\AppData\Roaming\Microsoft\Network\Connections\Pbk\_hiddenPbk\ (CREATE)
C:\Users\comp\AppData\Roaming\Microsoft\Network\Connections\Pbk\_hiddenPbk\rasphone.pbk (CREATE,READ)
Registry:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\OLEAUT (READ)
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Setup (READ)
[...]
Network:
24.151.31.150:465 (READ)
http://24.151.31.150:465 (READ,WRITE)
107.10.49.252:80 (READ)
http://107.10.49.252:80 (READ,WRITE)
Sur la base de la sortie affichée et des ressources consultées, nous pouvons déduire certaines caractéristiques du malware :
601941F00B194587C9E5.exe (PID 1800), l'identifiant de zone (Zone Identifier) du fichier C:\Users\comp\AppData\Local\vscmouse\vscmouse.exe est supprimévscmouse.exe (PID: 3036) se connecte aux points de terminaison réseau http://24.151.31.150:465 et http://107.10.49.252:80Les ressources consultées sont intéressantes pour identifier les indicateurs de détection basés sur l'hôte et le réseau. De plus, les ressources peuvent être utilisées dans des signatures dynmx. Un exemple courant est la détection de mécanismes de persistance dans le Registre.``` dynmx_signature: meta: name: run_keys_persistence title: Run Keys Persistence description: Detection of persistence based on Registry Run Keys detection: run_keys: - resource: category: "registry" access_operations: ["write"] with: - attribute: "location" operation: "regex" value: "^(HKEY_CURRENT_USER|HKEY_LOCAL_MACHINE)\\Software\\Microsoft\\Windows\\CurrentVersion\\(Run|RunOnce|RunOnceEx)\\" startup_folders_keys: - resource: category: "registry" access_operations: ["write"] with: - attribute: "location" operation: "regex" value: "^(HKEY_CURRENT_USER|HKEY_LOCAL_MACHINE)\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\(Shell Folders|User Shell Folders)\\" condition: run_keys as simple or startup_folders_keys as simple
## Installation
Pour utiliser le logiciel, Python 3.9 doit être disponible sur le système cible. De plus, les paquets Python suivants doivent être installés :
* `anytree`,
* `lxml`,
* `pyparsing`,
* `PyYAML`,
* `six` et
* `stringcase`
Pour installer les paquets, exécutez la commande `pip3` ci-dessous. Il est recommandé d'utiliser un environnement virtuel Python plutôt que d'installer les paquets à l'échelle du système.
pip3 install anytree lxml pyparsing PyYAML six stringcase
pip3 install -r requirements.txt
```
## Utilisation
Pour utiliser le prototype, exécutez simplement le point d'entrée principal `dynmx.py`. Les informations d'utilisation peuvent être consultées avec le paramètre de ligne de commande `-h` comme indiqué ci-dessous.```
$ python3 dynmx.py -h
usage: dynmx.py [-h] [--format {overview,detail}] [--show-log] [--log LOG] [--log-level {debug,info,error}] [--worker N] {detect,check,convert,stats,resources} ...
Detect dynmx signatures in dynamic program execution information (function logs)
optional arguments:
-h, --help show this help message and exit
--format {overview,detail}, -f {overview,detail}
Output format
--show-log Show all log output on stdout
--log LOG, -l LOG log file
--log-level {debug,info,error}
Log level (default: info)
--worker N, -w N Number of workers to spawn (default: number of processors - 2)
sub-commands:
task to perform
{detect,check,convert,stats,resources}
detect Detects a dynmx signature
check Checks the syntax of dynmx signature(s)
convert Converts function logs to the dynmx generic function log format
stats Statistics of function logs
resources Resource activity derived from function log
```
En général, comme indiqué dans la sortie, plusieurs paramètres de ligne de commande concernant la gestion des logs, le format de sortie des résultats ou le multiprocessing peuvent être définis. De plus, une commande doit être choisie pour exécuter une tâche spécifique. Veuillez noter que le nombre de workers n'affecte que les commandes qui utilisent le multiprocessing. Actuellement, il s'agit des commandes `detect` et `convert`.
Les commandes ont des paramètres de ligne de commande spécifiques qui peuvent être explorés en donnant le paramètre `-h` à la commande, par exemple pour la commande `detect` comme illustré ci-dessous.```
$ python3 dynmx.py detect -h
usage: dynmx.py detect [-h] --sig SIG [SIG ...] --input INPUT [INPUT ...] [--recursive] [--json-result JSON_RESULT] [--runtime-result RUNTIME_RESULT] [--detect-all]
optional arguments:
-h, --help show this help message and exit
--recursive, -r Search for input files recursively
--json-result JSON_RESULT
JSON formatted result file
--runtime-result RUNTIME_RESULT
Runtime statistics file formatted in CSV
--detect-all Detect signature in all processes and do not stop after the first detection
required arguments:
--sig SIG [SIG ...], -s SIG [SIG ...]
dynmx signature(s) to detect
--input INPUT [INPUT ...], -i INPUT [INPUT ...]
Input files
```
En tant qu'utilisateur de *dynmx*, vous pouvez décider comment la sortie est structurée. Si vous choisissez d'afficher le journal sur la console en définissant le paramètre `--show-log`, la sortie se compose de deux sections (voir liste ci-dessous). Le journal est affiché en premier, puis les résultats de la commande utilisée. Par défaut, le journal n'est ni affiché sur la console ni écrit dans un fichier journal (qui peut être défini à l'aide du paramètre `--log`). En raison du multitraitement, les entrées du fichier journal ne sont pas nécessairement dans l'ordre chronologique.```
|
__| _ _ _ _ _
/ | | | / |/ | / |/ |/ | /\/
\_/|_/ \_/|/ | |_/ | | |_/ /\_/
/|
\|
Ver. 0.5 (PoC), by 0x534a
[+] Log output
2023-06-27 19:07:38,068+0000 [INFO] (__main__) [PID: 13315] []: Start of dynmx run
[...]
[+] End of log output
[+] Result
[...]
```
Le niveau de détail du résultat affiché peut être défini à l'aide du paramètre de ligne de commande `--output-format` qui peut être défini sur `overview` pour un résultat de haut niveau ou sur `detail` pour un résultat détaillé. Par exemple, si vous définissez le format de sortie sur `detail`, les résultats de détection affichés dans la console contiendront les appels API et les ressources exacts qui ont déclenché la détection. Le format de sortie `overview` indiquera simplement quelle signature a été détectée dans quel journal de fonction.
## Exemples de lignes de commande
Détection d'une signature *dynmx* dans un journal de fonction avec un seul processus worker```
python3 dynmx.py -w 1 detect -i "flog.txt" -s dynmx_signature.yml
```
Conversion d'un journal de fonction au format de journal de fonction générique *dynmx*```
python3 dynmx.py convert -i "flog.txt" -o /tmp/
```
Vérifier une signature (seulement des vérifications de base de cohérence)```
python3 dynmx.py check -s dynmx_signature.yml
```
Obtenez une liste détaillée des ressources utilisées par un échantillon de logiciel malveillant basé sur le journal des fonctions (modèle d'activité d'accès)```
python3 dynmx.py -f detail resources -i "flog.txt"
```
## Dépannage
Veuillez considérer que cet outil est une preuve de concept développée en parallèle de la rédaction du mémoire de master. Par conséquent, la qualité du code n'est pas toujours optimale et il peut y avoir des bogues et des erreurs. J'ai essayé de rendre l'outil aussi robuste que possible dans le temps imparti.
La meilleure façon de résoudre les erreurs est d'activer la journalisation (sur la console et/ou dans un fichier journal) et de définir le niveau de journalisation sur `debug`. Les gestionnaires d'exceptions doivent écrire des erreurs détaillées dans le journal, ce qui peut faciliter le dépannage.