Loki 1.8: expediente sobre un joven y prometedor ladrón de datos





A mediados de junio, la lucha contra el coronavirus en Kazajstán estaba en pleno apogeo. Alarmadas por el aumento en el número de casos (entonces incluso el ex presidente Nursultan Nazarbayev se infectó), las autoridades locales decidieron cerrar nuevamente todos los centros comerciales y de entretenimiento, cadenas de tiendas, mercados y bazares. En ese momento, los ciberdelincuentes se aprovecharon de la situación enviando correos maliciosos a empresas rusas e internacionales.



Las cartas peligrosas disfrazadas de apelación del Ministro de Salud de la República de Kazajstán fueron interceptadas por el Sistema de Detección de Amenazas (TDS) Group-IB. El archivo adjunto contenía documentos que, cuando se iniciaron, instalaron un programa malicioso de la familia Loki PWS (Password Stealer), diseñado para robar inicios de sesión y contraseñas de una computadora infectada. En el futuro, los atacantes pueden usarlos para obtener acceso a cuentas de correo electrónico para fraude financiero, espionaje o venderlos en foros de piratas informáticos.



En este artículo, Nikita Karpov, analista de CERT-GIB , examina una instancia de uno de los ladrones de datos más populares ahora: Loki.



Hoy consideraremos una de las versiones de bot populares: 1.8. Se vende activamente, y el panel de administración incluso se puede encontrar en el dominio público: aquí .



Ejemplo de panel de administración:







Loki está escrito en C ++ y es uno de los programas maliciosos más populares que se utiliza para robar información del usuario de una computadora infectada. Al igual que el flagelo de nuestro tiempo, los virus ransomware, Data Stealer, después de ser atacado en la computadora de la víctima, realiza la tarea a una velocidad muy alta, no necesita afianzarse y aumentar sus privilegios en el sistema, casi no deja tiempo para defenderse de un ataque. Por tanto, en los eventos con malware que roba datos de los usuarios, el papel principal lo juega la investigación del incidente.



Desembalaje y obtención de un volcado de malware viable



La distribución en la mayoría de los casos ocurre a través de archivos adjuntos en listas de correo. El usuario, disfrazado de archivo legítimo, descarga y abre el archivo adjunto, lanzando el malware.



El marcador de inyección sugiere la presencia de un cargador.





Con la ayuda de DIE obtenemos información de que el archivo fuente está escrito en VB6.





El gráfico de entropía indica una gran cantidad de datos cifrados.





Cuando se inicia, el primer proceso crea un proceso hijo, lo inyecta y sale. El segundo proceso es responsable del trabajo del malware. Después de un corto período de tiempo, detenemos el proceso y guardamos el volcado de memoria. Para confirmar que Loki está dentro del volcado, mire dentro de la URL del centro de comando, que en la mayoría de los casos termina en fre.php .





Volcamos el fragmento de memoria que contiene el Loki y ajustamos el encabezado PE.



Comprobaremos el rendimiento del volcado utilizando el sistema TDS Huntbox.





Funcionalidad del bot



En el proceso de examinar el código de malware descompilado, encontramos una parte que contiene cuatro funciones que van inmediatamente después de la inicialización de las bibliotecas necesarias para la operación. Habiendo desmontado cada uno de ellos en su interior, determinamos su propósito y funcionalidad de nuestro malware.





Los nombres de las funciones se han renombrado para que sean más descriptivos por conveniencia.

La funcionalidad del bot está determinada por dos funciones principales:



  1. Data Stealer es la primera función responsable de robar datos de 101 aplicaciones y enviarlos al servidor.
  2. Downloader: una solicitud de los comandos CnC (Command & Control) para su ejecución.


Por conveniencia, la siguiente tabla enumera todas las aplicaciones de las que la instancia de Loki que se examina intenta robar datos.

ID de función solicitud ID de función solicitud ID de función solicitud
1 Mozilla Firefox 35 FTPInfo 69 ClassicFTP
2 Comodo IceDragon 36 LinasFTP 70 PuTTY / KiTTY
3 Safari de manzana 37 FileZilla 71 Thunderbird
4 K-Meleon 38 Personal-FTP 72 Foxmail
cinco SeaMonkey 39 BlazeFtp 73 Pocomail
6 Rebaño 40 NETFile 74 IncrediMail
7 NETGATE BlackHawk 41 GoFTP 75 Notificador de Gmail pro
8 Lunascape 42 ALFTP 76 Revisar correo
nueve Google Chrome 43 DeluxeFTP 77 WinFtp
diez Ópera 44 Comandante total 78 Martin Prikryl
once Navegador QTWeb 45 FTPGetter 79 32BitFtp
12 QupZilla 46 WS_FTP 80 Navegador FTP
trece explorador de Internet 47 Archivos de configuración del cliente de correo 81 Envío

(softwarenetz)
catorce Opera 2 48 Poker de inclinación completa 82 Opera Mail
quince Cyberfox 49 Pokerstars 83 Buzón
dieciséis Luna pálida 50 ExpanDrive 84 FossaMail
17 Waterfox 51 Corcel 85 Becky!
Dieciocho Lengua macarrónica 52 FlashFXP 86 POP3
19 SuperPutty 53 NovaFTP 87 panorama
20 FTPShell 54 NetDrive 88 Ymail2
21 NppFTP 55 Total Commander 2 89 Trojitá
22 MyFTP 56 SmartFTP 90 TrulyMail
23 FTPBox 57 Gerente FAR 91 Archivos .spn
24 sherrod FTP 58 Bitvise 92 Lista de tareas pendientes
25 FTP ahora 59 RealVNC

TightVNC
93 Stickies
26 NexusFile 60 mSecure Wallet 94 NoteFly
27 Xftp 61 Syncovery 95 NoteZilla
28 EasyFTP 62 FreshFTP 96 Notas adhesivas
29 SftpNetDrive 63 BitKinex 97 KeePass
treinta AbleFTP 64 UltraFXP 98 Enpass
31 JaSFtp sesenta y cinco FTP ahora 2 99 Mi RoboForm
32 Automatizar 66 Vandyk SecureFX 100 1 contraseña
33 Cyberduck 67 Experto en FTP seguro de Odin 101 Mikrotik WinBox
34 Fullsync 68 Arrojar
En esta etapa, se completa el análisis estático de malware, y en la siguiente sección consideraremos cómo se comunica Loki con el servidor.



Redes



Hay dos problemas que deben abordarse para registrar las interacciones de la red:



  1. El Centro de mando solo está disponible en el momento del ataque.
  2. Wireshark no registra las comunicaciones de los bots en el loopback, por lo que debe utilizar otros medios.


La solución más simple es reenviar la dirección CnC con la que Loki se comunicará a localhost. Para el bot, el servidor ahora está disponible en cualquier momento, aunque no responde, pero no es necesario registrar las comunicaciones del bot. Para resolver el segundo problema, usaremos la utilidad RawCap, que nos permite escribir las comunicaciones que necesitamos para pcap. A continuación, analizaremos el pcap grabado en Wireshark.





Antes de cada comunicación, el bot verifica la disponibilidad de CnC y, si está disponible, abre un socket. Todas las comunicaciones de red tienen lugar a nivel de transporte utilizando el protocolo TCP, y a nivel de aplicación, se utiliza HTTP.



La siguiente tabla muestra los encabezados de los paquetes que Loki usa como estándar.

Campo Valor Descripción
Agente de usuario Mozilla / 4.08 (Charon; Inferno) Un agente de usuario típico de Loki
Aceptar * / *
Tipo de contenido aplicación / secuencia de octetos
Codificación de contenido binario
Clave de contenido 7DE968CC Resultado de hash de encabezados anteriores (el hash se realiza mediante un algoritmo CRC personalizado con polinomio 0xE8677835)
Conexión cerca
Prestemos atención al cuerpo del paquete:



  1. La estructura de los datos registrados depende de la versión del bot, y en versiones anteriores no hay campos que sean responsables de las opciones de cifrado y compresión.
  2. El servidor determina cómo procesar los datos recibidos según el tipo de solicitud. Hay 7 tipos de datos que el servidor puede leer:

    • 0x26 Datos de billetera robados
    • 0x27 Datos de aplicación robados
    • 0x28 Solicitud de comando del servidor
    • 0x29 Descarga de un archivo robado
    • POS 0x2A
    • 0x2B datos del registrador de teclas
    • 0x2C Captura de pantalla
  3. En el caso examinado, solo estaban presentes 0x27, 0x28 y 0x2B.
  4. Cada solicitud contiene información general sobre el bot y el sistema infectado, según la cual el servidor identifica todos los informes para una máquina, y luego hay información que depende del tipo de solicitud.
  5. En la última versión del bot, solo se implementa la compresión de datos y los campos encriptados están preparados para el futuro y no son procesados ​​por el servidor.
  6. La biblioteca APLib de código abierto se utiliza para comprimir datos.


Al realizar una solicitud con datos robados, el bot asigna un búfer de tamaño 0x1388 (5000 bytes). La estructura de las solicitudes 0x27 se muestra en la siguiente tabla:

Parcialidad El tamaño Valor Descripción
0x0 0x2 0x0012 Versión bot
0x2 0x2 0x0027 Tipo de solicitud (enviar datos robados)
0x4 0xD ckav.ru ID binario (también aparece XXXXX11111)
0x11 0x10 - Nombre de usuario
0x21 0x12 - Nombre del computador
0x33 0x12 - Nombre de dominio de la computadora
0x45 0x4 - Resolución de pantalla (ancho y alto)

0x49 0x4 -
0x4D 0x2 0x0001 Indicador de derechos de usuario (1 si es administrador)
0x4F 0x2 0x0001 Indicador SID (1 si está configurado)
0x51 0x2 0x0001 Indicador de bitness del sistema (1 si es x64)
0x53 0x2 0x0006 Versión de Windows (número de versión principal)
0x55 0x2 0x0001 Versión de Windows (número de versión menor)
0x57 0x2 0x0001 Información adicional del sistema (1 = VER_NT_WORKSTATION)
0x59 0x2 -
0x5B 0x2 0x0000 ¿Se enviaron los datos robados?
0x5D 0x2 0x0001 ¿Se utilizó compresión de datos?
0x5F 0x2 0x0000 Tipo de compresión
0x61 0x2 0x0000 ¿Se utilizó cifrado de datos?
0x63 0x2 0x0000 Tipo de cifrado
0x65 0x36 - MD5 del valor de registro MachineGuid
0x9B - - Datos robados comprimidos
La segunda etapa de interacción con el servidor comienza después de ser reparada en el sistema. El bot envía una solicitud con el tipo 0x28, cuya estructura se muestra a continuación:



Tamaño del búfer: 0x2BC (700 bytes)

Parcialidad El tamaño Valor Descripción
0x0 0x2 0x0012 Versión bot
0x2 0x2 0x0028 Tipo de solicitud (solicitud de comando del centro de comando)
0x4 0xD ckav.ru ID binario (también aparece XXXXX11111)
0x11 0x10 - Nombre de usuario
0x21 0x12 - Nombre del computador
0x33 0x12 - Nombre de dominio de la computadora
0x45 0x4 - Resolución de pantalla (ancho y alto)
0x49 0x4 -
0x4D 0x2 0x0001 Indicador de derechos de usuario (1 si es administrador)
0x4F 0x2 0x0001 Indicador SID (1 si está configurado)
0x51 0x2 0x0001 Indicador de bitness del sistema (1 si es x64)
0x53 0x2 0x0006 Versión de Windows (número de versión principal)
0x55 0x2 0x0001 Versión de Windows (número de versión menor)
0x57 0x2 0x0001 Información adicional del sistema (1 = VER_NT_WORKSTATION)
0x59 0x2 0xFED0
0x5B 0x36 - MD5 del valor de registro MachineGuid
Después de la solicitud, el bot espera recibir una respuesta del servidor que contenga el número y los comandos en sí. Las posibles variantes de comando se obtienen mediante un análisis estático del código de malware descompilado y se presentan a continuación.



Tamaño del búfer: 0x10 (16 bytes) + 0x10 (16 bytes) para cada comando del paquete.

Encabezado HTTP (inicio de datos) \ r \ n \ r \ n [0D 0A 0D 0A] 4 bytes
- - 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

Cambia la frecuencia de verificación de la respuesta del servidor
[00 00 00 00] [00 00 00 10] [00 00 00 00] [00 00 00 01] cinco
# 17

Elimina a Loki y sal
[00 00 00 00] [00 00 00 11] [00 00 00 00] [00 00 00 00] -


Analizador de tráfico de red



Gracias a este análisis, tenemos toda la información que necesitamos para analizar las interacciones de red de Loki.



El analizador está implementado en Python, recibe un archivo pcap como entrada y encuentra en él todas las comunicaciones que pertenecen a Loki.



Primero, usemos la biblioteca dkpt para encontrar todos los paquetes TCP. Para recibir solo paquetes http, pongamos un filtro en el puerto utilizado. Entre los paquetes http recibidos, seleccionamos aquellos que contienen los conocidos encabezados Loki, y obtenemos comunicaciones que necesitan ser analizadas para extraer información de ellos en una forma legible.



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


En todas las solicitudes de Loki, los primeros 4 bytes son responsables de la versión del bot y el tipo de solicitud. Usando estos dos parámetros, determinamos cómo procesaremos los datos.



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


El siguiente en la línea será analizar la respuesta del servidor. Para leer solo información útil, busque la secuencia \ r \ n \ r \ n , que define el final de los encabezados de los paquetes y el comienzo de los comandos del servidor.



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


Esto concluye el análisis de la parte principal del algoritmo del analizador sintáctico y pasa al resultado que obtenemos en la salida. Toda la información se muestra en formato json.



A continuación se muestran imágenes del resultado del trabajo del parser, obtenidas a partir de las comunicaciones de varios bots, con diferentes CnC y registradas en diferentes entornos.



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": {}
}


Arriba hay un ejemplo de una solicitud al servidor 0x27 (carga de datos de la aplicación). Para las pruebas, se crearon cuentas en tres aplicaciones: Mozilla Firefox, NppFTP y FileZilla. Loki tiene tres opciones para grabar datos de aplicaciones:



  1. En forma de una base de datos SQL (el analizador guarda la base de datos y muestra todas las filas disponibles en ella).
  2. En forma abierta, como en Firefox en el ejemplo.
  3. Como un archivo xml como NppFTP y 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 segunda solicitud es de tipo 0x28 y solicita comandos del servidor.



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


Un ejemplo de una respuesta de CnC, que envió un comando en respuesta para iniciar el keylogger. Y la posterior descarga de datos del 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": {}
}


Al final del trabajo, el analizador genera la información contenida en cada solicitud del bot (información sobre el bot y el sistema) y el número de solicitudes y respuestas asociadas con Loki en el archivo 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 




El código completo del analizador está disponible en: github.com/Group-IB/LokiParser



Conclusión



En este artículo, analizamos más de cerca el malware Loki, desarmamos su funcionalidad e implementamos un analizador de tráfico de red que simplificará enormemente el proceso de análisis de incidentes y nos ayudará a comprender qué fue exactamente lo que se robó de la computadora infectada. Si bien el desarrollo de Loki aún está en curso, solo se ha filtrado la versión 1.8 (y anteriores), que es la versión que los profesionales de seguridad encuentran todos los días.



En el próximo artículo, analizaremos otro popular ladrón de datos, Pony, y compararemos este malware.



Indicador de compromiso (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
  • Hash MD5: B0C33B1EF30110C424BABD66126017E5
  • User-Agent String: «Mozilla/4.08 (Charon; Inferno)»
  • Binary ID: «ckav.ru»



All Articles