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:
- Data Stealer es la primera función responsable de robar datos de 101 aplicaciones y enviarlos al servidor.
- 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 |
Redes
Hay dos problemas que deben abordarse para registrar las interacciones de la red:
- El Centro de mando solo está disponible en el momento del ataque.
- 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 |
- 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.
- 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
- En el caso examinado, solo estaban presentes 0x27, 0x28 y 0x2B.
- 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.
- 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.
- 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 |
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 |
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:
- En forma de una base de datos SQL (el analizador guarda la base de datos y muestra todas las filas disponibles en ella).
- En forma abierta, como en Firefox en el ejemplo.
- 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»