Loki 1.8: dossier sur le voleur de données jeune et en devenir





A la mi-juin, la lutte contre le coronavirus au Kazakhstan battait son plein. Alarmées par l'augmentation du nombre de cas (alors même l'ancien président Nursultan Nazarbayev a été infecté), les autorités locales ont décidé de fermer à nouveau tous les centres commerciaux et de divertissement, les chaînes de magasins, les marchés et les bazars. Et à ce moment-là, les cybercriminels ont profité de la situation en envoyant des courriers malveillants à des entreprises russes et internationales.



Des lettres dangereuses, déguisées en appel du Ministre de la santé de la République du Kazakhstan, ont été interceptées par le Groupe IB du Système de détection des menaces (TDS). La pièce jointe contenait des documents qui, une fois lancés, installaient un programme malveillant de la famille Loki PWS (Password Stealer), conçu pour voler les identifiants et les mots de passe d'un ordinateur infecté. À l'avenir, les attaquants peuvent les utiliser pour accéder à des comptes de messagerie pour fraude financière, espionnage ou vendre sur des forums de pirates.



Dans cet article, Nikita Karpov, analyste au CERT-GIB , examine une instance de l'un des voleurs de données les plus populaires actuellement - Loki.



Aujourd'hui, nous allons considérer l'une des versions de bot populaires - 1.8. Il est activement vendu, et le panneau d'administration peut même être trouvé dans le domaine public: ici .



Exemple de panneau d'administration:







Loki est écrit en C ++ et est l'un des logiciels malveillants les plus populaires utilisés pour voler les informations utilisateur d'un ordinateur infecté. Comme le fléau de notre temps - les virus ransomwares - Data Stealer, après avoir été touché sur l'ordinateur de la victime, effectue la tâche à très grande vitesse - il n'a pas besoin de prendre pied et d'augmenter ses privilèges dans le système, il ne laisse presque pas le temps de se défendre contre une attaque. Par conséquent, dans les événements avec des logiciels malveillants qui volent les données des utilisateurs, le rôle principal est joué par l'enquête sur l'incident.



Déballage et obtention d'un vidage de malware fonctionnel



La distribution se fait dans la plupart des cas par le biais de pièces jointes dans les listes de diffusion. L'utilisateur, déguisé en fichier légitime, télécharge et ouvre la pièce jointe, lançant le malware.



Le marqueur d'injection suggère la présence d'un Loader.





Avec l'aide de DIE, nous obtenons des informations indiquant que le fichier source est écrit en VB6.





Le graphique d'entropie indique une grande quantité de données cryptées.





Une fois lancé, le premier processus crée un processus enfant, l'injecte et se termine. Le deuxième processus est responsable du travail du malware. Après une courte période de temps, nous arrêtons le processus et enregistrons le vidage de la mémoire. Pour confirmer que Loki est à l'intérieur du vidage, regardez à l'intérieur de l'url du centre de commande, qui dans la plupart des cas se termine par fre.php .





Nous vidons le fragment de mémoire contenant le Loki et corrigeons l'en-tête PE.



Nous vérifierons les performances du dump à l'aide du système TDS Huntbox.





Fonctionnalité du bot



Lors de l'examen du code du malware décompilé, nous trouvons une partie contenant quatre fonctions qui vont immédiatement après l'initialisation des bibliothèques nécessaires à l'opération. Après avoir démonté chacun d'eux à l'intérieur, nous déterminons leur objectif et la fonctionnalité de nos logiciels malveillants.





Les noms des fonctions ont été renommés pour être plus descriptifs pour plus de commodité.

La fonctionnalité du bot est déterminée par deux fonctions principales:



  1. Data Stealer est la première fonction chargée de voler les données de 101 applications et de les envoyer au serveur.
  2. Downloader - une demande des commandes CnC (Command & Control) pour l'exécution.


Pour plus de commodité, le tableau ci-dessous répertorie toutes les applications à partir desquelles l'instance Loki examinée tente de voler des données.

ID de fonction application ID de fonction application ID de fonction application
1 Mozilla Firefox 35 FTPInfo 69 ClassiqueFTP
2 Comodo IceDragon 36 LinasFTP 70 PuTTY / KiTTY
3 Safari aux pommes 37 FileZilla 71 Thunderbird
4 K-Meleon 38 Personnel-FTP 72 Foxmail
cinq SeaMonkey 39 BlazeFtp 73 Pocomail
6 Troupeau 40 NETFile 74 IncrediMail
7 NETGATE BlackHawk 41 GoFTP 75 Gmail notifier pro
8 Lunascape 42 ALFTP 76 Vérifier le courrier
neuf Google Chrome 43 DeluxeFTP 77 WinFtp
Dix Opéra 44 Commandant total 78 Martin Prikryl
Onze Navigateur QTWeb 45 FTPGetter 79 32BitFtp
12 QupZilla 46 WS_FTP 80 Navigateur FTP
treize Internet Explorer 47 Fichiers de configuration du client de messagerie 81 Mailing

(softwarenetz)
Quatorze Opéra 2 48 Poker Full Tilt 82 Courrier Opera
quinze Cyberfox 49 Pokerstars 83 Boîte aux lettres
seize Lune pale 50 ExpanDrive 84 FossaMail
17 Waterfox 51 Coursier 85 Becky!
dix-huit Sabir 52 FlashFXP 86 POP3
19 SuperPutty 53 NovaFTP 87 Perspective
20 FTPShell 54 NetDrive 88 Ymail2
21 NppFTP 55 Commandant total 2 89 Trojitá
22 MyFTP 56 SmartFTP 90 TrulyMail
23 FTPBox 57 Gestionnaire FAR 91 Fichiers .spn
24 sherrod FTP 58 Bitvise 92 Liste des tâches
25 FTP maintenant 59 RealVNC

TightVNC
93 Stickies
26 NexusFile 60 Portefeuille mSecure 94 NoteFly
27 Xftp 61 Syncovery 95 RemarqueZilla
28 EasyFTP 62 FreshFTP 96 Notes autocollantes
29 SftpNetDrive 63 BitKinex 97 KeePass
trente AbleFTP 64 UltraFXP 98 Enpass
31 JaSFtp 65 FTP maintenant 2 99 Mon RoboForm
32 Automatiser 66 Vandyk SecureFX 100 1Mot de passe
33 Cyberduck 67 Expert FTP sécurisé d'Odin 101 Mikrotik WinBox
34 Fullsync 68 Jeter
À ce stade, l'analyse statique des logiciels malveillants est terminée, et dans la section suivante, nous examinerons comment Loki communique avec le serveur.



La mise en réseau



Deux problèmes doivent être résolus pour enregistrer les interactions réseau:



  1. Le centre de commande n'est disponible qu'au moment de l'attaque.
  2. Wireshark n'enregistre pas les communications du bot dans le bouclage, vous devez donc utiliser d'autres moyens.


La solution la plus simple consiste à transmettre l'adresse CnC avec laquelle Loki communiquera à localhost. Pour le bot, le serveur est désormais disponible à tout moment, même s'il ne répond pas, mais il n'est pas nécessaire d'enregistrer les communications du bot. Pour résoudre le deuxième problème, nous utiliserons l'utilitaire RawCap, qui nous permet d'écrire les communications dont nous avons besoin pour pcap. Ensuite, nous analyserons le pcap enregistré dans Wireshark.





Avant chaque communication, le bot vérifie la disponibilité de CnC et, si disponible, ouvre une socket. Toutes les communications réseau ont lieu au niveau du transport en utilisant le protocole TCP et au niveau de l'application, HTTP est utilisé.



Le tableau ci-dessous montre les en-têtes de paquets que Loki utilise en standard.

Champ Valeur La description
Agent utilisateur Mozilla / 4.08 (Charon; Inferno) Un agent utilisateur typique pour Loki
J'accepte * / *
Type de contenu application / flux d'octets
Encodage de contenu binaire
Clé de contenu 7DE968CC Résultat de hachage des en-têtes précédents (le hachage est effectué par un algorithme CRC personnalisé avec le polynôme 0xE8677835)
Lien Fermer
Faisons attention au corps du colis:



  1. La structure des données enregistrées dépend de la version du bot, et dans les versions antérieures, aucun champ n'est responsable des options de chiffrement et de compression.
  2. Le serveur détermine par le type de demande comment traiter les données reçues. Il existe 7 types de données que le serveur peut lire:

    • 0x26 Données de portefeuille volées
    • 0x27 Données d'application volées
    • 0x28 Demande de commande du serveur
    • 0x29 Déchargement d'un fichier volé
    • 0x2A POS
    • Données du keylogger 0x2B
    • Capture d'écran 0x2C
  3. Dans l'instance examinée, seuls 0x27, 0x28 et 0x2B étaient présents.
  4. Chaque demande contient des informations générales sur le bot et le système infecté, selon lesquelles le serveur identifie tous les rapports pour une machine, puis il y a des informations qui dépendent du type de demande.
  5. Dans la dernière version du bot, seule la compression des données est implémentée et les champs chiffrés sont préparés pour l'avenir et ne sont pas traités par le serveur.
  6. La bibliothèque APLib open source est utilisée pour compresser les données.


Lors de la formation d'une requête avec des données volées, le bot alloue un tampon de taille 0x1388 (5000 octets). La structure des requêtes 0x27 est indiquée dans le tableau ci-dessous:

Biais La taille Valeur La description
0x0 0x2 0x0012 Version du bot
0x2 0x2 0x0027 Type de demande (envoyer des données volées)
0x4 0xD ckav.ru ID binaire (XXXXX11111 se produit également)
0x11 0x10 - Nom d'utilisateur
0x21 0x12 - Nom de l'ordinateur
0x33 0x12 - Nom de domaine informatique
0x45 0x4 - Résolution d'écran (largeur et hauteur)

0x49 0x4 -
0x4D 0x2 0x0001 Drapeau des droits de l'utilisateur (1 si administrateur)
0x4F 0x2 0x0001 Indicateur SID (1 si défini)
0x51 0x2 0x0001 Indicateur de bitness du système (1 si x64)
0x53 0x2 0x0006 Version Windows (numéro de version majeur)
0x55 0x2 0x0001 Version Windows (numéro de version mineur)
0x57 0x2 0x0001 Informations système supplémentaires (1 = VER_NT_WORKSTATION)
0x59 0x2 -
0x5B 0x2 0x0000 Les données volées ont-elles été envoyées
0x5D 0x2 0x0001 La compression de données a-t-elle été utilisée
0x5F 0x2 0x0000 Type de compression
0x61 0x2 0x0000 Le cryptage des données a-t-il été utilisé
0x63 0x2 0x0000 Type de chiffrement
0x65 0x36 - MD5 à partir de la valeur de registre MachineGuid
0x9B - - Données volées compressées
La deuxième étape d'interaction avec le serveur commence après avoir été fixée dans le système. Le bot envoie une requête de type 0x28, dont la structure est illustrée ci-dessous:



Taille du tampon: 0x2BC (700 octets)

Biais La taille Valeur La description
0x0 0x2 0x0012 Version du bot
0x2 0x2 0x0028 Type de demande (demande de commande du centre de commande)
0x4 0xD ckav.ru ID binaire (XXXXX11111 se produit également)
0x11 0x10 - Nom d'utilisateur
0x21 0x12 - Nom de l'ordinateur
0x33 0x12 - Nom de domaine informatique
0x45 0x4 - Résolution d'écran (largeur et hauteur)
0x49 0x4 -
0x4D 0x2 0x0001 Drapeau des droits de l'utilisateur (1 si administrateur)
0x4F 0x2 0x0001 Indicateur SID (1 si défini)
0x51 0x2 0x0001 Indicateur de bitness du système (1 si x64)
0x53 0x2 0x0006 Version Windows (numéro de version majeur)
0x55 0x2 0x0001 Version Windows (numéro de version mineur)
0x57 0x2 0x0001 Informations système supplémentaires (1 = VER_NT_WORKSTATION)
0x59 0x2 0xFED0
0x5B 0x36 - MD5 à partir de la valeur de registre MachineGuid
Après la demande, le bot s'attend à recevoir une réponse du serveur contenant le numéro et les commandes elles-mêmes. Les variantes de commande possibles sont obtenues à l'aide d'une analyse statique du code du malware décompilé et sont présentées ci-dessous.



Taille du tampon: 0x10 (16 octets) + 0x10 (16 octets) pour chaque commande du paquet.

En-tête HTTP (début des données) \ r \ n \ r \ n [0D 0A 0D 0A] 4 octets
- - 4
2 [00 00 00 02] 4


4


4


4


4



()

#0

EXE-
[00 00 00 00] [00 00 00 00] [00 00 00 00] [00 00 00 23] www.notsogood.site/malicious.exe
#1

DLL
[00 00 00 00] [00 00 00 01] [00 00 00 00] [00 00 00 23] www.notsogood.site/malicious.dll
#2

EXE-
[00 00 00 00] [00 00 00 02] [00 00 00 00] [00 00 00 23] www.notsogood.site/malicious.exe
#8

(HDB file)
[00 00 00 00] [00 00 00 08] [00 00 00 00] [00 00 00 00] -
#9

[00 00 00 00] [00 00 00 09] [00 00 00 00] [00 00 00 00] -
#10

[00 00 00 00] [00 00 00 0A] [00 00 00 00] [00 00 00 00] -
#14

Loki
[00 00 00 00] [00 00 00 0E] [00 00 00 00] [00 00 00 00] -
#15

Loki
[00 00 00 00] [00 00 00 0F] [00 00 00 00] [00 00 00 23] www.notsogood.site/malicious.exe
# 16

Changer la fréquence de vérification de la réponse du serveur
[00 00 00 00] [00 00 00 10] [00 00 00 00] [00 00 00 01] cinq
# 17

Supprimer Loki et quitter
[00 00 00 00] [00 00 00 11] [00 00 00 00] [00 00 00 00] -


Analyseur de trafic réseau



Grâce à cette analyse, nous avons toutes les informations dont nous avons besoin pour analyser les interactions réseau de Loki.



L'analyseur est implémenté en Python, reçoit un fichier pcap en entrée et y trouve toutes les communications appartenant à Loki.



Tout d'abord, utilisons la bibliothèque dkpt pour trouver tous les paquets TCP. Pour ne recevoir que des paquets http, mettons un filtre sur le port utilisé. Parmi les paquets http reçus, nous sélectionnons ceux qui contiennent les en-têtes Loki bien connus, et obtenons les communications qui doivent être analysées afin d'en extraire des informations sous une forme lisible.



for ts, buf in pcap:
    eth = dpkt.ethernet.Ethernet(buf)
    if not isinstance(eth.data, dpkt.ip.IP):
        ip = dpkt.ip.IP(buf)
    else:
        ip = eth.data
 
    if isinstance(ip.data, dpkt.tcp.TCP):
        tcp = ip.data
        try:
            if tcp.dport == 80 and len(tcp.data) > 0:  # HTTP REQUEST
                if str(tcp.data).find('POST') != -1:
                    http += 1
                    httpheader = tcp.data
                    continue
                else:
                    if httpheader != "":
                        print('Request information:')
 
                        pkt = httpheader + tcp.data
                        httpheader = ""
                        if debug:
                            print(pkt)
                        req += 1
                        request = dpkt.http.Request(pkt)
                        uri = request.headers['host'] + request.uri
                        parsed_payload['Network']['Source IP'] = socket.inet_ntoa(ip.src)
                        parsed_payload['Network']['Destination IP'] = socket.inet_ntoa(ip.dst)
                        parsed_payload_same['Network']['CnC'] = uri
                        parsed_payload['Network']['HTTP Method'] = request.method
 
                        if uri.find("fre.php"):
                            print("Loki detected!")
                        pt = parseLokicontent(tcp.data, debug)
                        parsed_payload_same['Malware Artifacts/IOCs']['User-Agent String'] = request.headers['user-agent']
 
                        print(json.dumps(parsed_payload, ensure_ascii=False, sort_keys=False, indent=4))
                        parsed_payload['Network'].clear()
                        parsed_payload['Compromised Host/User Data'].clear()
                        parsed_payload['Malware Artifacts/IOCs'].clear()
                        print("----------------------")
            if tcp.sport == 80 and len(tcp.data) > 0:  # HTTP RESPONCE
                resp += 1
                if pt == 40:
                    print('Responce information:')
                    parseC2commands(tcp.data, debug)
                    print("----------------------")
                    pt = 0
        except(dpkt.dpkt.NeedData, dpkt.dpkt.UnpackError):
            continue


Dans toutes les requêtes Loki, les 4 premiers octets sont responsables de la version du bot et du type de requête. En utilisant ces deux paramètres, nous déterminons comment nous traiterons les données.



def parseLokicontent(data, debug):
    index = 0
 
    botV = int.from_bytes(data[0:2], byteorder=sys.byteorder)
    parsed_payload_same['Malware Artifacts/IOCs']['Loki-Bot Version'] =  botV
 
    payloadtype = int.from_bytes(data[2:4], byteorder=sys.byteorder)
    index = 4
    print("Payload type: : %s" % payloadtype)
    if payloadtype == 39:
        parsed_payload['Network']['Traffic Purpose'] =  "Exfiltrate Application/Credential Data"
        parse_type27(data, debug)
    elif payloadtype == 40:
        parsed_payload['Network']['Traffic Purpose'] = "Get C2 Commands"
        parse_type28(data, debug)
    elif payloadtype == 43:
        parsed_payload['Network']['Traffic Purpose'] = "Exfiltrate Keylogger Data"
        parse_type2b(lb_payload)
    elif payloadtype == 38:
        parsed_payload['Network']['Traffic Purpose'] = "Exfiltrate Cryptocurrency Wallet"
    elif payloadtype == 41:
        parsed_payload['Network']['Traffic Purpose'] = "Exfiltrate Files"
    elif payloadtype == 42:
        parsed_payload['Network'].['Traffic Purpose'] = "Exfiltrate POS Data"
    elif payloadtype == 44:
        parsed_payload['Network']['Traffic Purpose'] = "Exfiltrate Screenshots"
 
    return payloadtype


La prochaine ligne sera d'analyser la réponse du serveur. Pour lire uniquement les informations utiles, recherchez la séquence \ r \ n \ r \ n , qui définit la fin des en-têtes de paquet et le début des commandes du serveur.



def parseC2commands(data, debug):
    word = 2
    dword = 4
    end = data.find(b'\r\n\r\n')
    if end != -1:
        index = end + 4
        if (str(data).find('<html>')) == -1:
            if debug:
                print(data)
            fullsize = getDWord(data, index)
            print("Body size: : %s" % fullsize)
            index += dword
            count = getDWord(data, index)
            print("Commands: : %s" % count)
            if count == 0:
                print('No commands received')
            else:
                index += dword
                for i in range(count):
                    print("Command: %s" % (i + 1))
 
                    id = getDWord(data, index)
                    print("Command ID: %s" % id)
                    index += dword
 
                    type = getDWord(data, index)
                    print("Command type: %s" % type)
                    index += dword
 
                    timelimit = getDWord(data, index)
                    print("Command timelimit: %s" % timelimit)
                    index += dword
 
                    datalen = getDWord(data, index)
                    index += dword
 
                    command_data = getString(data, index, datalen)
                    print("Command data: %s" % command_data)
                    index += datalen
        else:
            print('No commands received')
    return None


Ceci conclut l'analyse de la partie principale de l'algorithme de l'analyseur et passe au résultat que nous obtenons en sortie. Toutes les informations sont affichées au format json.



Vous trouverez ci-dessous des images du résultat du travail de l'analyseur, obtenues à partir des communications de divers robots, avec différents CnC et enregistrées dans différents environnements.



Request information:
Loki detected!
Payload type: 39
Decompressed data: 
{'Module': {'Mozilla Firefox'}, 'Version': {0}, 'Data': {'domain': {'https://accounts.google.com'}, 'username': {'none@gmail.com'}, 'password': {'test'}}}
{'Module': {'NppFTP'}, 'Version': {0}, 'Data': {b'<?xml version="1.0" encoding="UTF-8" ?>\r\n<NppFTP defaultCache="%CONFIGDIR%\\Cache\\%USERNAME%@%HOSTNAME%" outputShown="0" windowRatio="0.5" clearCache="0" clearCachePermanent="0">\r\n    <Profiles />\r\n</NppFTP>\r\n'}}
{
    "Network": {
        "Source IP": "-",
        "Destination IP": "185.141.27.187",
        "HTTP Method": "POST",
        "Traffic Purpose": "Exfiltrate Application/Credential Data",
        "First Transmission": true
    },
    "Compromised Host/User Data": {},
    "Malware Artifacts/IOCs": {}
}


Ci-dessus, un exemple de requête au serveur 0x27 (téléchargement des données d'application). Pour les tests, des comptes ont été créés dans trois applications: Mozilla Firefox, NppFTP et FileZilla. Loki propose trois options pour enregistrer les données d'application:



  1. Sous la forme d'une base de données SQL (l'analyseur sauvegarde la base de données et y affiche toutes les lignes disponibles).
  2. Sous forme ouverte, comme dans Firefox dans l'exemple.
  3. En tant que fichier xml comme NppFTP et FileZilla.


Request information:
Loki detected!
Payload type: 39
No data stolen
{
    "Network": {
        "Source IP": "-",
        "Destination IP": "185.141.27.187",
        "HTTP Method": "POST",
        "Traffic Purpose": "Exfiltrate Application/Credential Data",
        "First Transmission": false
    },
    "Compromised Host/User Data": {},
    "Malware Artifacts/IOCs": {}
}


La deuxième requête est de type 0x28 et demande des commandes au serveur.



Responce information:
Body size: 26
Commands: 1
Command: 1
Command ID: 0
Command type: 9
Command timelimit: 0
Command data: 35


Un exemple de réponse de CnC, qui a envoyé une commande en réponse pour démarrer le keylogger. Et le déchargement ultérieur des données de keylogger.



Request information:
Loki detected!
Payload type: : 43
{
    "Network": {
        "Source IP": "-",
        "Destination IP": "185.141.27.187",
        "HTTP Method": "POST",
        "Traffic Purpose": "Exfiltrate Keylogger Data"
    },
    "Compromised Host/User Data": {},
    "Malware Artifacts/IOCs": {}
}


A la fin du travail, l'analyseur sort les informations contenues dans chaque requête du bot (informations sur le bot et le système), et le nombre de requêtes et réponses associées à Loki dans le fichier pcap.



General information:
{
    "Network": {
        "CnC": "nganyin-my.com/chief6/five/fre.php"
    },
    "Compromised Host/User Description": {
        "User Name": "-",
        "Hostname": "-",
        "Domain Hostname": "-",
        "Screen Resolution": "1024x768",
        "Local Admin": true,
        "Built-In Admin": true,
        "64bit OS": false,
        "Operating System": "Windows 7 Workstation"
    },
    "Malware Artifacts/IOCs": {
        "Loki-Bot Version": 18,
        "Binary ID": "ckav.ru",
        "MD5 from GUID": "-",
        "User-Agent String": "Mozilla/4.08 (Charon; Inferno)"
    }
}
Requests: 3
Responces: 3 




Le code d'analyseur complet est disponible sur: github.com/Group-IB/LokiParser



Conclusion



Dans cet article, nous avons examiné de plus près le malware Loki, démonté ses fonctionnalités et implémenté un analyseur de trafic réseau qui simplifiera considérablement le processus d'analyse des incidents et nous aidera à comprendre exactement ce qui a été volé sur l'ordinateur infecté. Alors que le développement de Loki est toujours en cours, seule la version 1.8 (et antérieure) a été divulguée, ce qui est la version que les professionnels de la sécurité rencontrent chaque jour.



Dans le prochain article, nous analyserons un autre voleur de données populaire, Pony, et comparerons ces logiciels malveillants.



Indicateur de compromis (IOC):



URL:



  • nganyin-my.com/chief6/five/fre.php
  • wardia.com.pe/wp-includes/texts/five/fre.php
  • broken2.cf/Work2/fre.php
  • 185.141.27.187/danielsden/ver.php
  • Hachage MD5: B0C33B1EF30110C424BABD66126017E5
  • User-Agent String: «Mozilla/4.08 (Charon; Inferno)»
  • Binary ID: «ckav.ru»



All Articles