logo

Analyse Lockbits

Tutoriels
Analyse Lockbits

Analyse statique du code

Yohan, notre expert en reverse engineering est tombé récemment sur une nouvelle souche du programme LOCKBIT. Une annonce de LOCKBIT 3.0 ayant été faite récemment, serions-nous face à cette mise à jour ou avons-nous simplement à faire à un groupe imitateur ? Nous sommes en cours d’analyse sur le sujet, voici nos premiers éléments.
Qu’en pensez-vous ?

Vérification de l’Anti-Debug

Au début du programme, celui-ci vérifie que le flag `NtGlobalFlag` (`0x70`) est set. Si c’est le cas, alors le binaire rentre dans une boucle infinie. Sinon, le binaire continue son exécution.
Vérification de l’Anti-Debug
Vérification de l’Anti-Debug

Chargement des DLL

Le binaire charge très peu de DLL et de fonctions au démarrage.
Liste des DLL chargés par le programme
Liste des DLL chargés par le programme

Si l’on continue dans le code, on peut voir des modifications de chaînes de caractères depuis la stack.
Ajout d’une string sur la stack
Ajout d’une string sur la stack

On s’aperçoit ensuite que la chaîne est XORée avec une clé statique mise en place juste avant la chaîne. Cette clé, pour la première chaîne, est `0x20`, chose que l’on peut vérifier avec Python.
XOR de la chaîne avec la clé 0x20
XOR de la chaîne avec la clé 0x20

Code du binaire permettant de XOR la chaîne
Code du binaire permettant de XOR la chaîne

Chaque nom de DLL est encodé avec du code différent. La liste des DLL encodées est la suivante :
- `gdiplus.dll` - `ws2_32.dll` - `shell32.dll` - `advapi32.dll` - `user32.dll` - `ole32.dll` - `netapi32.dll` - `gpredit.dll` - `oleaut32.dll` - `shlwapi.dll` - `msvcrt.dll` - `activeds.dll` - `gdiplus.dll` - `mpr.dll` - `bcrypt.dll` - `crypt32.dll` - `iphlpapi.dll` - `wtsapi32.dll` - `win32u.dll` - `Comdlg32.dll` - `cryptbase.dll` - `ombase.dll` - `winspool.drv`

Résolution des DLL Dynamique

Une fois le nom des DLL résolu, le binaire doit résoudre dynamiquement les adresses des DLL afin de pouvoir utiliser les fonctions. Pour cela, il résout dans un premier temps `Kernel32.dll` puis `LoadLibraryA` afin de résoudre chacune des fonctions.
Résolution des fonctions dynamiquement
Résolution des fonctions dynamiquement

Kernel32.dll

Pour la résolution de cette DLL, le binaire réalise un hash FNV du nom de la DLL en minuscule et la vérifie avec une chaîne harcodé. Si cette valeur est juste alors l’adresse de base de la DLL est retourné.
Vérification du nom de la DLL et renvoie de l’adresse de base
Vérification du nom de la DLL et renvoie de l’adresse de base

Résultat d’un hash FNV sur la chaîne Kernel32.dll
Résultat d’un hash FNV sur la chaîne Kernel32.dll

LoadLibraryA

Pour la résolution de cette fonction, le binaire réalise les mêmes opérations. Il boucle dans les fonctions présentes dans Kernel32.dll puis pour chaque fonction réalise son hash FNV et le compare à une valeur hardcodée. Si la valeur est la même alors il retourne l’adresse de base de la fonction.
Vérification du nom de la fonction et renvoie l’adresse de base
Vérification du nom de la fonction et renvoie l’adresse de base

Résultat d’un hash FNV sur la chaîne LoadLibraryA
Résultat d’un hash FNV sur la chaîne LoadLibraryA

Pas touche à ma langue

Le binaire va ensuite récupérer la fonction GetSystemDefaultUILanguage afin de vérifier la langue par défaut sur l’ordinateur pour ne pas chiffrer les systèmes ayant une certaine langue par défaut.
Récupération de l’adresse de base de la fonction GetSystemDefaultUILanguage
Récupération de l’adresse de base de la fonction GetSystemDefaultUILanguage

Résultat d’un hash FNV sur la chaîne GetSystemDefaultUILanguage
Résultat d’un hash FNV sur la chaîne GetSystemDefaultUILanguage

La valeur renvoyée par cette fonction est ensuite comparé avec des entiers qui correspondent à la langue du système.
Vérification de la langue du système
Vérification de la langue du système

En se basant sur la documentation officiel de microsoft, il est possible de récupérer la liste des langues comparés avec la variable.
- Azeri (Cyrillic) - Azeri (Latin) - Armenian (Armenia) - Belarusian - Georgian - Kazakh - Kyrgyz (Cyrillic) - Russian (Moldava) - Russian - Tajik - Turkmen - Uzbek (Cyrillic) - Uzbek (Latin) - Ukrainian
Si la langue est dans la liste alors, le binaire résout la fonction ExitProcess pour terminer l’exécution.
Résolution de la fonction ExitProcess
Résolution de la fonction ExitProcess

Résultat du hash FNV pour ExitProcess
Résultat du hash FNV pour ExitProcess

Réduction des droits sur le process

Le binaire va réduire ses droits d’accès au process en modifiant sa propre liste d’accès.
Pour cela, il résout la fonction NtOpenProcess pour avoir un handle sur son process en cours et récupère les droits via GetSecurityInfo.
Suite à cela, il appelle RtlAllocateAndInitializeSid pour créer une nouvelle structure SID afin d’appeler RtlAddAccessDeniedAce et mettre les droits du groupe EVERYONE à ACCESS_DENIED.
Récupération des droits sur le process
Récupération des droits sur le process

Enfin, le binaire va appeler RtlGetAce afin de passer sur chaque ACE et ajouter une ACL via RtlAddAce. Le binaire appelle ensuite SetSecurityInfo pour appliquer toutes les ACL et bloquer l’accès à tout le monde sur le process.
Blocage du process pour tout le monde
Blocage du process pour tout le monde

Error Stack Trace

Le binaire utilise la fonction NtSetInformationProcess afin de bloquer le moindre message d’erreur. Il utilise trois flags qui sont les suivants :
- SEM_FAILCRITICALERRORS - SEM_NOGPFAULTERRORBOX - SEM_NOALIGNMENTFAULTEXCEPT
Blocage des messages d’erreurs
Blocage des messages d’erreurs

Décodage de la configuration

La fonction suivante permet de décoder la configuration dans le binaire.
Un simple XOR avec la clé 0x5F est réalisé, il est donc facile de récupérer les chaînes en réalisant un XOR sur tout le binaire.
Après avoir effectué le XOR, il est possible de récupérer une image via binwalk. L’image affiche le logo de LockBit.
Récupération de l’image dans la configuration du binaire
Récupération de l’image dans la configuration du binaire

Une seule image ressort, pourtant il existe 9 fichiers.
- Fichier EMF: Contient le vecteur graphique du texte "ALL YOUR IMPORTANT FILES ARE STOLEN AND ENCRYPTED"
- Fichier EMF: Contient le vecteur graphique pour "LOCKBIT 2.0"
- Un fichier Blender Pro Medium TTF
- Un fichier Proxima Nova TTF
- Le texte du logo LockBit en PNG
- Le logo LockBit en PNG
- Un logo grand logo LockBit en PNG
- Une liste de processus
- Une liste de services

Le binaire va ensuite compter le nombre de processus dans la liste afin de les mettre dans une liste.
La configuration elle, est stocké dans une liste de bytes.
Si le byte contient 0xFF alors l’option est activé dans le cas contraire, la valeur du byte est 0xAA.
Configuration du binaire
Configuration du binaire

Les index de la liste correspondent à :

- Index 0: Désactivation du bypass de l'UAC.
- index 1: Activation de l'auto suppression.
- Index 2: Activation de la page de log.
- Index 3: Activation du chiffrement par le réseau.
- Index 4, 5, 6: Si un de ces 3 flags est à `0xFF` alors le binaire se réplique via les GPO.
- Index 7: Mise en place de clé de registre pour les fichiers .lockbit.
- Index 8: Impression de la page de ransom sur les imprimantes.

On remarque que contrairement aux malwares dans la nature, celui-ci a une configuration modifiée.
Il n’active pas le chiffrement par le réseau et ne met pas en place de clé de registre pour les fichiers .lockbit.

Escalade de privilège

Pour avoir tous les droits sur la machine courante, le binaire va utiliser une technique connu nommé `Juicy Potato` pour élever ses droits. Cette technique abuse du `Golden Privileges` afin d’élever ses droits en local.

Log

Le binaire va ensuite vérifier si le flag de Log est activé dans la configuration. Étant donné que ce n’est pas le cas dans notre configuration, je vais passer cette partie.

Bypass UAC

Pour bypass l'UAC, le binaire va dans un premier temps vérifier qu'il est admin puis, va bypass l'UAC via l'interface COM `ColorDataProxy/CCMLuaUtil`. Cette technique connu peut être trouvé sur [Github](https://github.com/hfiref0x/UACME/blob/92e84a734c4719a9067f4e9c8cb0e263ae4e06af/Source/Akagi/methods/hybrids.c#L877).

Réplication via GPO

Si le binaire est admin et qu’un des flags pour la réplication GPO est activé alors, celui-ci va ensuite essayer de se répliquer via les GPO.
Vérification des droits et des flags pour lancer la réplication via GPO
Vérification des droits et des flags pour lancer la réplication via GPO

Dans un premier temps, le binaire vérifie s’il est exécuté sur l’Active Directory en récupérant le nom de l’ordinateur courant et celui de l’Active Directory afin de comparer les deux.
Check si l’ordinateur actuel est un AD
Check si l’ordinateur actuel est un AD

Si l’ordinateur actuel n’est pas un AD, alors cette partie s’arrête et le binaire n’essaye de pas de créer de GPO.
Le binaire, va ensuite récupérer le nom DNS de l’AD ainsi que le nom du compte Administrateur afin de se connecter au domain.
Suite à cela, il va préparer la chaîne pour la création de la GPO. Pour cela, il s’aide de la format string `%02X%02X%02X%02X%02X%02X%02X` utilisé sur la clé publique hardcodée dans le programme.
Cette clé publique aussi est différente des autres samples rencontré dans la nature.
A l’aide de cette chaîne, le binaire va ensuite se connecter au domaine.
Création de la chaîne à l’aide de la format string et connexion au domaine
Création de la chaîne à l’aide de la format string et connexion au domaine

Dans cette continuité, en s’aidant de la chaîne LDAP formaté juste avant, le binaire va créer la GPO dans le domaine.
Création de la GPO
Création de la GPO

ne fois cette GPO créé, le binaire va créer et mettre à jour le fichier GPT.INI.
Ce fichier va contenir la chaîne suivante formaté:
```
[General]
Version=%s
displayName=%s
```

La version est contenu sur la stack est XORé ce qui permet de la récupérer. La valeur pour la version est `2621892`.
Contenu du fichier GPT.INI
Contenu du fichier GPT.INI

Maintenant, le binaire va mettre à jour le dossier de la GPO pour y ajouter les fichiers suivants :
– \MACHINE\Preferences\NetworkShares\NetworkShares.xml: **Permet de mettre en partage réseau tous les disques du serveur.**
– \MACHINE\Preferences\Services\Services.xml: **Arrête une liste de service trouvés précédemment.**
– \MACHINE\Preferences\Files\Files.xml: **Place le binaire sur le Bureau de tous les partages.**
– \MACHINE\Preferences\ScheduledTasks\ScheduledTasks.xml: **Kill tous les process de la liste trouvé précédemment.**
– \MACHINE\Registry.pol: **Contient des clés de registre.**
– \MACHINE\comment.cmtx

Les chaînes de caractères de chaque fichier sont situés sur la stack et encodé différemment à chaque fois. Pour le cas de `ScheduledTasks.xml` le contenu du fichier est encodé de la manière suivante :
Décodage de la chaîne pour le fichier ScheduledTasks.xml
Décodage de la chaîne pour le fichier ScheduledTasks.xml

Une fois le contenu des fichiers mise en place, le programme attend une minute avant de lancer une réplication.
Pour la réplication, le programme passe par PowerShell, cette chaîne est encodées dans la stack puis décodé avec une simple soustraction.
Commande de réplication PowerShell
Commande de réplication PowerShell

Le binaire vérifie évidemment si la commande s’est bien déroulé. En cas de problème celui-ci passe par le LDAP pour envoyer un gpudpate sur tous les postes.
Fin de la fonction de réplication
Fin de la fonction de réplication

Suppression des Shadows Copies

Une fois le malware implanté, celui-ci va supprimer les backups pour que le système ne soit plus récupérables. Pour cela, il va passer par des chaînes encodés sur la stack et va exécuter les commandes suivantes :
- cmd.exe /c vssadmin Delete Shadows /All /Quiet
- cmd.exe /c bcdedit /set {default} recoveryenabled No
- cmd.exe /c bcdedit /set {default} bootstatuspolicy ignoreallfailures
- cmd.exe /c wmic SHADOWCOPY /nointeractive
- cmd.exe /c wevtutil cl security
- cmd.exe /c wevtutil cl system
- cmd.exe /c wevtutil cl application

Exécute chacune des commandes pour supprimer les shadows copies
Exécute chacune des commandes pour supprimer les shadows copies

Impression des notes du ransomware


Lancement de la fonction pour imprimer la ransomnote
Lancement de la fonction pour imprimer la ransomnote

Pour ce qui est de l’impression, dans un premier temps le binaire récupère toutes les imprimantes sur le système à l’aide de la fonction `EnumPrintersW`.
Une fois la liste de toutes les imprimantes récupérées, il va s’assurer de ne pas imprimer dans des fichiers en comparant les imprimantes avec les chaînes `Microsoft Print to PDF` et `Microsoft XPS Document Writer`.
Une fois ce filtrage effectué, le binaire va ouvrir l’imprimante, écrire le contenu de la ransomnote et fermer l’imprimante pour chacune des imprimantes présentes.
Fermeture de l’imprimante
Fermeture de l’imprimante

Processus de chiffrement

Le binaire appelle la fonction `FindFirstVolumeW` afin de trouver le premier volume de disponible sur la machine pour commencer son chiffrement. Il itère les volumes suivants avec `FindNextVolumeW` pour trouver ceux disponibles.
Itération pour récupérer tous les volumes
Itération pour récupérer tous les volumes

Pour initialiser son contexte cryptographique, le binaire essaye d’importer la DLL `bcrypt`, s’il échoue il récupère alors la fonction `CryptAcquireContextW` présente dans la DLL `advapi32`.
Initialisation de la fonction Cryptographique
Initialisation de la fonction Cryptographique

Le binaire créé ensuite une paire de clé publique et privée, à l’aide de l’algorithme `Libsodium`. Il chiffre la clé publique et supprime la clé privée de la mémoire.
Génération, Chiffrement, Suppression
Génération, Chiffrement, Suppression

Pour sa dernière partie de process, le binaire va lancer la fonction `NtCreateIoCompletion` pour lui permettre d’accélérer son process de chiffrement et va lancer autant de Thread de chiffrement qu’en contient le CPU.
Durant son process, le binaire va éviter de chiffrer les dossiers, fichiers et extensions suivantes:
Dossiers:
- $Windows.~bt
- intel
- msocache
- $recycle.bin
- $windows.~ws
- tor browser
- boot
- windows nt
- msbuild
- microsoft
- all users
- system volume information
- perflog
- google
- application data
- windows
- windows.old
- appdata
- mozilla
- microsoft.net
- microsoft shared
- internet explorer
- common files
- opera
- windows journal
- windows defender
- windowsapp
- windowspowershell
- usoshared
- windows security
- windows photo viewer

Fichiers:
- ntldr
- ntuser.dat.log
- bootsect.bak
- autorun.inf
- thumbs.db
- iconcache.db
- restore-my-files.txt

Extensions:
- .386
- .cmd
- .ani
- .adv
- .msi
- .msp
- .com
- .nls
- .ocx
- .mpa
- .cpl
- .mod
- .hta
- .prf
- .rtp
- .rpd
- .bin
- .hlp
- .shs
- .drv
- .wpx
- .bat
- .rom
- .msc
- .spl
- .msu
- .ics
- .key
- .exe
- .dll
- .lnk
- .ico
- .hlp
- .sys
- .drv
- .cur
- .idx
- .ini
- .reg
- .mp3
- .mp4
- .apk
- .ttf
- .otf
- .fon
- .fnt
- .dmp
- .tmp
- .pif
- .wav
- .wma
- .dmg
- .iso
- .app
- .ipa
- .xex
- .wad
- .msu
- .icns
- .lock
- .lockbit
- .theme
- .diagcfg
- .diagcab
- .diagpkg
- .msstyles
- .gadget
- .woff
- .part
- .sfcache
- .winmd

Auto Suppression

Une fois le processus de chiffrement terminé, le programme va procéder à sa suppression.
Pour cela, il va lancer une commande shell toujours encodé sur la stack.
Décodage de la chaîne d’auto suppression
Décodage de la chaîne d’auto suppression
La commande `fsutil` est utilisé pour que le binaire ne soit plus sur le disque une fois l’exécution terminée. C’est bien plus efficace qu’une simple suppression avec la commande `rm` car le fichier est totalement remplacé sur le disque, il n’y a donc pas de moyen de le récupéré avec des outils une fois la suppression effectué.
De plus, il utilise la fonction `MoveFileExW` pour dire au système de supprimer le fichier après un reboot.

Fin d’exécution

Le binaire résout la fonction `ExitProcess` afin de se fermer.
Arrêt du binaire
Arrêt du binaire

Conclusion

La génération de clé de 32 bits suivis du chiffrement de la clé publique avec la clé publique de Lockbit et la suppression de la clé privée en mémoire rend le processus de décryptage impossible.
De plus, le binaire ne communique pas avec l’extérieur. Il n’envoie pas de message et ne se connecte à aucun C2. Ils n’ont pas besoin de récupérer d’information spécifique sur le chiffrement, car toutes les informations sont stockées à la fin des fichiers. Ces informations sont bien évidemment aussi chiffrées.
Pour ce qui est de la propagation, sachez que si la configuration GPO est activé dans le binaire et que vous détectez une GPO pour déployer le malware. Celui-ci à de grande chance d’avoir été lancé dans un premier temps sur l’Active Directory.