Loki 1.8: dossiê sobre o jovem e promissor roubador de dados





Em meados de junho, a luta contra o coronavírus no Cazaquistão estava a todo vapor. Alarmadas com o aumento do número de casos (até o ex-presidente Nursultan Nazarbayev foi infectado), as autoridades locais decidiram fechar novamente todos os centros comerciais e de entretenimento, cadeias de lojas, mercados e bazares. Naquele momento, os cibercriminosos aproveitaram-se da situação enviando correspondências maliciosas para empresas russas e internacionais.



Cartas perigosas, disfarçadas como um apelo do Ministro da Saúde da República do Cazaquistão, foram interceptadas pelo Grupo IB do Sistema de Detecção de Ameaças (TDS). O anexo continha documentos que, quando iniciados, instalavam um programa malicioso da família Loki PWS (Password Stealer), projetado para roubar logins e senhas de um computador infectado. No futuro, os invasores podem usá-los para obter acesso a contas de email para fraude financeira, espionagem ou vendê-los em fóruns de hackers.



Neste artigo, Nikita Karpov, analista do CERT-GIB , examina uma instância de um dos ladrões de dados mais populares da atualidade - Loki.



Hoje vamos considerar uma das versões de bot populares - 1.8. É vendido ativamente e o painel de administração pode até ser encontrado no domínio público: aqui .



Exemplo de painel de administração:







Loki é escrito em C ++ e é um dos malwares mais populares usados ​​para roubar informações do usuário de um computador infectado. Como o flagelo do nosso tempo - vírus de ransomware - o Data Stealer, após ser atingido no computador da vítima, executa a tarefa em uma velocidade muito alta - não precisa se firmar e aumentar seus privilégios no sistema, quase não deixa tempo para se defender de um ataque. Portanto, nos eventos com malware que rouba dados do usuário, o papel principal é desempenhado pela investigação do incidente.



Descompactando e obtendo um despejo de malware viável



A distribuição na maioria dos casos ocorre por meio de anexos em listas de mala direta. O usuário, disfarçado como um arquivo legítimo, baixa e abre o anexo, iniciando o malware.



O marcador de injeção sugere a presença de um Loader.





Com a ajuda do DIE, obtemos informações de que o arquivo fonte está escrito em VB6.





O gráfico de entropia indica uma grande quantidade de dados criptografados.





Quando iniciado, o primeiro processo cria um processo filho, o injeta e sai. O segundo processo é responsável pelo trabalho do malware. Após um curto período de tempo, interrompemos o processo e salvamos o despejo de memória. Para confirmar se o Loki está dentro do dump, olhe dentro do url do centro de comando, que na maioria dos casos termina em fre.php .





Despejamos o fragmento de memória que contém o Loki e corrigimos o cabeçalho PE.



Verificaremos o desempenho do dump usando o sistema TDS Huntbox.





Funcionalidade do bot



No processo de exame do código do malware descompilado, encontramos uma parte contendo quatro funções que vão imediatamente após a inicialização das bibliotecas necessárias para a operação. Depois de desmontar cada um deles internamente, determinamos sua finalidade e funcionalidade de nosso malware.





Os nomes das funções foram renomeados para serem mais descritivos por conveniência.

A funcionalidade do bot é determinada por duas funções principais:



  1. O Data Stealer é a primeira função responsável por roubar dados de 101 aplicativos e enviá-los ao servidor.
  2. Downloader - uma solicitação de comandos CnC (Comando e Controle) para execução.


Por conveniência, a tabela abaixo lista todos os aplicativos dos quais a instância do Loki sendo examinada tenta roubar dados.

ID da função inscrição ID da função inscrição ID da função inscrição
1 Mozilla Firefox 35 FTPInfo 69 ClassicFTP
2 Comodo IceDragon 36 LinasFTP 70 PuTTY / KiTTY
3 Apple Safari 37 FileZilla 71 Thunderbird
4 K-Meleon 38 Equipe-FTP 72 Foxmail
cinco SeaMonkey 39 BlazeFtp 73 Pocomail
6 Rebanho 40 NETFile 74 IncrediMail
7 NETGATE BlackHawk 41 GoFTP 75 Notificador pro Gmail
8 Lunascape 42 ALFTP 76 Checkmail
nove Google Chrome 43 DeluxeFTP 77 WinFtp
dez Ópera 44 Comando total 78 Martin Prikryl
onze Navegador QTWeb 45 FTPGetter 79 32BitFtp
12 QupZilla 46 WS_FTP 80 Navegador FTP
treze Internet Explorer 47 Arquivos de configuração do cliente de email 81 Mailing

(softwarenetz)
quatorze Opera 2 48 Full tilt poker 82 Opera Mail
quinze Cyberfox 49 Pokerstars 83 Caixa postal
dezesseis Lua pálida 50 ExpanDrive 84 FossaMail
17 Waterfox 51 Corcel 85 Becky!
dezoito Pidgin 52 FlashFXP 86 POP3
19 SuperPutty 53 NovaFTP 87 Outlook
20 FTPShell 54 NetDrive 88 Ymail2
21 NppFTP 55 Total Commander 2 89 Trojitá
22 MyFTP 56 SmartFTP 90 TrulyMail
23 FTPBox 57 FAR Manager 91 Arquivos .spn
24 sherrod FTP 58 Bitvise 92 Lista de tarefas para fazer
25 FTP agora 59 RealVNC

TightVNC
93 Stickies
26 NexusFile 60 Carteira mSecure 94 NoteFly
27 Xftp 61 Syncovery 95 NoteZilla
28 EasyFTP 62 FreshFTP 96 Post-it
29 SftpNetDrive 63 BitKinex 97 KeePass
trinta AbleFTP 64 UltraFXP 98 Enpass
31 JaSFtp 65 FTP agora 2 99 Meu RoboForm
32 Automize 66 Vandyk SecureFX 100 1 senha
33 Cyberduck 67 Odin Secure FTP Expert 101 Mikrotik WinBox
34 Fullsync 68 Arremesso
Nesse estágio, a análise estática do malware é concluída e, na próxima seção, consideraremos como o Loki se comunica com o servidor.



Networking



Existem dois problemas que precisam ser resolvidos para registrar as interações de rede:



  1. A Central de Comando está disponível apenas no momento do ataque.
  2. O Wireshark não grava comunicações de bot no loopback, então você precisa usar outros meios.


A solução mais simples é encaminhar o endereço CnC com o qual o Loki se comunicará para o localhost. Para o bot, o servidor agora está disponível a qualquer momento, embora não responda, mas não é necessário registrar as comunicações do bot. Para resolver o segundo problema, usaremos o utilitário RawCap, que nos permite escrever as comunicações de que precisamos para pcap. A seguir, analisaremos o pcap gravado no Wireshark.





Antes de cada comunicação, o bot verifica a disponibilidade do CnC e, se disponível, abre um soquete. Todas as comunicações de rede ocorrem no nível de transporte usando o protocolo TCP e, no nível do aplicativo, o HTTP é usado.



A tabela abaixo mostra os cabeçalhos dos pacotes que o Loki usa como padrão.

Campo Valor Descrição
Agente de usuário Mozilla / 4.08 (Charon; Inferno) Um agente de usuário típico para Loki
Aceitar * / *
Tipo de conteúdo aplicação / fluxo de octeto
Codificação de conteúdo binário
Content-Key 7DE968CC Resultado de hash dos cabeçalhos anteriores (o hash é feito por um algoritmo CRC personalizado com polinômio 0xE8677835)
Conexão perto
Vamos prestar atenção ao corpo do pacote:



  1. A estrutura dos dados gravados depende da versão do bot, e nas versões anteriores não há campos responsáveis ​​pelas opções de criptografia e compactação.
  2. O servidor determina pelo tipo de solicitação como processar os dados recebidos. Existem 7 tipos de dados que o servidor pode ler:

    • 0x26 Dados de carteira roubados
    • 0x27 Dados de aplicativo roubados
    • 0x28 Pedido de comando do servidor
    • 0x29 Descarregando um arquivo roubado
    • 0x2A POS
    • Dados do keylogger 0x2B
    • 0x2C Screenshot
  3. Na instância examinada, apenas 0x27, 0x28 e 0x2B estavam presentes.
  4. Cada solicitação contém informações gerais sobre o bot e o sistema infectado, de acordo com as quais o servidor identifica todos os relatórios de uma máquina, e depois há informações que dependem do tipo de solicitação.
  5. Na versão mais recente do bot, apenas a compactação de dados é implementada e os campos criptografados são preparados para o futuro e não são processados ​​pelo servidor.
  6. A biblioteca APLib de software livre é usada para compactar dados.


Ao formar uma solicitação com dados roubados, o bot aloca um buffer de tamanho 0x1388 (5000 bytes). A estrutura das solicitações 0x27 é mostrada na tabela abaixo:

Viés O tamanho Valor Descrição
0 x 0 0x2 0x0012 Versão do bot
0x2 0x2 0x0027 Tipo de solicitação (enviar dados roubados)
0x4 0xD ckav.ru ID binário (XXXXX11111 também ocorre)
0x11 0x10 - Nome do usuário
0x21 0x12 - Nome do computador
0x33 0x12 - Nome de domínio do computador
0x45 0x4 - Resolução da tela (largura e altura)

0x49 0x4 -
0x4D 0x2 0x0001 Sinalizador de direitos do usuário (1 se administrador)
0x4F 0x2 0x0001 Sinalizador SID (1 se definido)
0x51 0x2 0x0001 Sinalizador de bitness do sistema (1 se x64)
0x53 0x2 0x0006 Versão do Windows (número da versão principal)
0x55 0x2 0x0001 Versão do Windows (número da versão secundária)
0x57 0x2 0x0001 Informações adicionais do sistema (1 = VER_NT_WORKSTATION)
0x59 0x2 -
0x5B 0x2 0x0000 Os dados roubados foram enviados
0x5D 0x2 0x0001 Foi usada compressão de dados
0x5F 0x2 0x0000 Tipo de compressão
0x61 0x2 0x0000 Foi usada criptografia de dados
0x63 0x2 0x0000 Tipo de encriptação
0x65 0x36 - MD5 do valor de registro MachineGuid
0x9B - - Dados roubados compactados
A segunda etapa de interação com o servidor começa após ser consertada no sistema. O bot envia uma solicitação do tipo 0x28, cuja estrutura é mostrada a seguir:



Tamanho do buffer: 0x2BC (700 bytes)

Viés O tamanho Valor Descrição
0 x 0 0x2 0x0012 Versão do bot
0x2 0x2 0x0028 Tipo de solicitação (solicitação de comando do centro de comando)
0x4 0xD ckav.ru ID binário (XXXXX11111 também ocorre)
0x11 0x10 - Nome do usuário
0x21 0x12 - Nome do computador
0x33 0x12 - Nome de domínio do computador
0x45 0x4 - Resolução da tela (largura e altura)
0x49 0x4 -
0x4D 0x2 0x0001 Sinalizador de direitos do usuário (1 se administrador)
0x4F 0x2 0x0001 Sinalizador SID (1 se definido)
0x51 0x2 0x0001 Sinalizador de bitness do sistema (1 se x64)
0x53 0x2 0x0006 Versão do Windows (número da versão principal)
0x55 0x2 0x0001 Versão do Windows (número da versão secundária)
0x57 0x2 0x0001 Informações adicionais do sistema (1 = VER_NT_WORKSTATION)
0x59 0x2 0xFED0
0x5B 0x36 - MD5 do valor de registro MachineGuid
Após a solicitação, o bot espera receber uma resposta do servidor contendo o número e os próprios comandos. As variantes de comando possíveis são obtidas usando a análise estática do código do malware descompilado e são apresentadas a seguir.



Tamanho do buffer: 0x10 (16 bytes) + 0x10 (16 bytes) para cada comando no pacote.

Cabeçalho HTTP (início dos dados) \ 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

Altere a frequência de verificação da resposta do servidor
[00 00 00 00] [00 00 00 10] [00 00 00 00] [00 00 00 01] cinco
# 17

Remova Loki e saia
[00 00 00 00] [00 00 00 11] [00 00 00 00] [00 00 00 00] -


Analisador de tráfego de rede



Graças a essa análise, temos todas as informações de que precisamos para analisar as interações de rede de Loki.



O analisador é implementado em Python, recebe um arquivo pcap como entrada e encontra todas as comunicações pertencentes a Loki nele.



Primeiro, vamos usar a biblioteca dkpt para encontrar todos os pacotes TCP. Para receber apenas pacotes http, vamos colocar um filtro na porta usada. Entre os pacotes http recebidos, selecionamos aqueles que contêm os cabeçalhos Loki bem conhecidos e obtemos as comunicações que precisam ser analisadas para extrair informações deles de forma legível.



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


Em todas as solicitações Loki, os primeiros 4 bytes são responsáveis ​​pela versão do bot e pelo tipo de solicitação. Usando esses dois parâmetros, determinamos como processaremos os dados.



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


O próximo passo será analisar a resposta do servidor. Para ler apenas informações úteis, procure a seqüência \ r \ n \ r \ n , que define o final dos cabeçalhos dos pacotes e o início dos comandos do 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


Isso conclui a análise da parte principal do algoritmo do analisador e segue para o resultado que obtemos na saída. Todas as informações são exibidas no formato json.



Abaixo estão imagens do resultado do trabalho do parser, obtidas a partir das comunicações de vários bots, com diferentes CnCs e gravadas em diferentes ambientes.



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


Acima está um exemplo de uma solicitação ao servidor 0x27 (carregando dados do aplicativo). Para teste, contas foram criadas em três aplicativos: Mozilla Firefox, NppFTP e FileZilla. O Loki tem três opções para registrar os dados do aplicativo:



  1. Na forma de um banco de dados SQL (o analisador salva o banco de dados e exibe todas as linhas disponíveis nele).
  2. Na forma aberta, como o Firefox no exemplo.
  3. Como um arquivo xml, como NppFTP e 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": {}
}


A segunda solicitação é do tipo 0x28 e solicita comandos do servidor.



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


Um exemplo de resposta do CnC, que enviou um comando em resposta para iniciar o keylogger. E o posterior descarregamento de dados do 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": {}
}


No final do trabalho, o analisador imprime as informações contidas em cada solicitação do bot (informações sobre o bot e o sistema) e o número de solicitações e respostas associadas ao Loki no arquivo 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 




O código do analisador completo está disponível em: github.com/Group-IB/LokiParser



Conclusão



Neste artigo, examinamos mais de perto o malware Loki, desmontamos sua funcionalidade e implementamos um analisador de tráfego de rede que simplificará muito o processo de análise de incidentes e nos ajudará a entender o que exatamente foi roubado do computador infectado. Embora o desenvolvimento do Loki ainda esteja em andamento, apenas a versão 1.8 (e anteriores) vazou, que é a versão que os profissionais de segurança encontram todos os dias.



No próximo artigo, analisaremos outro ladrão de dados popular, o Pony, e compararemos esses malware.



Indicador de compromisso (IOCs):



Urls:



  • 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