Crime cibernético

Slow Pisces mira desenvolvedores com desafios de programação e introduz um novo malware em linguagem Python personalizado

Clock Icon 12 minutos de leitura

Resumo executivo

Slow Pisces (também conhecido como Jade Sleet, TraderTraitor, PUKCHONG) é um grupo de ameaças patrocinado pelo estado norte-coreano, cujo foco principal é gerar receita para o regime da RPDC, geralmente visando grandes organizações no setor de criptomoedas. Este artigo analisa a campanha do grupo, a qual acreditamos estar relacionada a roubos recentes de criptomoedas.

Nessa campanha, o Slow Pisces se envolveu com desenvolvedores de criptomoedas no LinkedIn, fazendo-se passar por possíveis empregadores e enviando malware disfarçado de desafios de programação. Esses desafios exigem que os desenvolvedores executem um projeto comprometido, infectando seus sistemas usando um malware que denominamos RN Loader e RN Stealer.

O grupo teria roubado mais de US$ 1 bilhão do setor de criptomoedas em 2023. Eles conseguiram isso usando vários métodos, incluindo plataformas falsas de negociação e trading, malware distribuído por meio do Node Package Manager (NPM) e comprometimentos da cadeia de suprimentos.

Em dezembro de 2024, o FBI atribuiu o roubo de US$ 308 milhões de uma empresa de criptomoedas com sede no Japão ao Slow Pisces. Mais recentemente, o grupo ganhou as manchetes por seu suposto envolvimento no roubo de US$ 1,5 bilhão de uma bolsa de criptomoedas de Dubai.

Compartilhamos nossa inteligência de ameaças com analistas do GitHub e do LinkedIn para derrubar as contas e os repositórios relevantes.

Eles forneceram a seguinte declaração em resposta:

O GitHub e o LinkedIn removeram essas contas maliciosas por violarem nossos respectivos termos de serviço. Em todos os nossos produtos, usamos tecnologia automatizada, combinada com equipes de especialistas em investigação e reportes de membros, para combater atores mal-intencionados e fazer cumprir os termos de serviço. Continuamos a evoluir e a melhorar nossos processos e incentivamos nossos clientes e membros a reportarem qualquer atividade suspeita.

Informações adicionais

Este relatório detalha como o Slow Pisces oculta o malware em seus desafios de programação e descreve as ferramentas subsequentes do grupo, com o objetivo de fornecer para a indústria em geral uma melhor compreensão dessa ameaça.

Os clientes da Palo Alto Networks estão mais bem protegidos contra as ameaças discutidas neste artigo por meio de nosso Firewall de próxima geração (“Next-Generation Firewall”) com assinaturas Advanced URL Filtering e Advanced DNS Security .

Se você acha que pode ter sido comprometido ou tem um assunto urgente, entre em contato com a equipe de resposta a incidentes da Unit 42.

Tópicos relacionados da Unit 42 Criptomoedas, RPDC

Análise técnica

Nossa visibilidade dessa campanha segue, em linhas gerais, três etapas, ilustradas abaixo na Figura 1.

Diagrama que ilustra ameaças de segurança cibernética envolvendo iscas de PDF, repositórios do GitHub e um servidor C2. Ele mostra: 1) arquivos PDF, como descrições de cargos e folhas de perguntas, atuando como iscas, 2) repositórios GitHub JavaScript e Python com várias APIs externas, potencialmente obtendo dados maliciosos, e 3) um servidor C2 configurado para enviar dados benignos ou uma carga maliciosa sob certas condições. Os logotipos da Palo Alto Networks e da UNIT 42 estão incluídos.
Figura 1. Visão geral da campanha "desafios de programação" do Slow Pisces.

Etapa 1 - Iscas em PDF

O Slow Pisces começou se passando por recrutadores no LinkedIn e se envolvendo com alvos em potencial, enviando-lhes um PDF benigno com uma descrição de emprego, conforme mostrado abaixo na Figura 2. Se os possíveis alvos se candidatassem, os atacantes apresentavam a eles um desafio de programação que consistia em várias tarefas descritas em uma folha de perguntas.

Imagem exibindo dois documentos lado a lado. À esquerda, uma “Descrição de cargo” para um coordenador de equipe de design de UX. À direita, uma “Folha de perguntas” contendo perguntas técnicas e gerais relacionadas ao design de experiência do usuário (UX).
Figura 2. Iscas em PDFs benignos.

Observamos o Slow Pisces se passando por várias organizações com essas iscas, principalmente no setor de criptomoedas. As folhas de perguntas incluíam tarefas genéricas de desenvolvimento de software e um desafio de programação de um "projeto real", relacionado a um repositório do GitHub mostrado na Figura 3 abaixo.

Captura de tela de um documento intitulado “Coding and Problem-Solving Skills With Real Project” (Habilidades de codificação e solução de problemas com projeto real). Ele inclui um link para um repositório do GitHub e descreve uma tarefa de codificação envolvendo taxas de câmbio de Bitcoin e Ethereum de fontes de API. O texto solicita aprimoramentos no projeto, adicionando mais APIs de mercado e melhorando a comunicação de rede no código.
Figura 3. Desafio de programação de um "projeto real" contido na isca PDF.

Etapa 2 - Repositórios do GitHub

O Slow Pisces apresentou aos alvos os chamados desafios de programação como projetos de repositórios do GitHub. Os repositórios continham códigos adaptados de projetos de código aberto, incluindo aplicativos para visualização e análise:

  • Dados do mercado de ações
  • Estatísticas das ligas de futebol europeias
  • Dados meteorológicos
  • Preços de criptomoedas

O grupo usou principalmente projetos em Python ou JavaScript, provavelmente dependendo do fato de o alvo ter se candidatado a uma função de desenvolvimento de front-end ou back-end. Também vimos repositórios baseados em Java nessa campanha, embora fossem muito menos comuns, com apenas duas instâncias representando um aplicativo de criptomoedas chamado jCoin.

Essa escassez sugere que os invasores podem ter criado repositórios sob demanda, com base na linguagem de programação preferida do alvo. Consequentemente, o grupo usou com mais frequência as linguagens mais populares no setor de criptomoedas, como JavaScript e Python. Da mesma forma, repositórios não descobertos também podem existir para outras linguagens de programação.

Etapa 3a - Repositório Python

No final de 2024, o grupo usou um projeto mostrado abaixo na Figura 4, intitulado "Stocks Pattern Analyzer", adaptado de um repositório legítimo.

Captura de tela de um repositório do GitHub chamado “Stocks Pattern Analyzer” mostrando a estrutura do arquivo à esquerda e o conteúdo do arquivo README à direita, explicando como executar o aplicativo diretamente e com o Docker.
Figura 4. Repositório Python "Stocks Pattern Analyzer".

A maior parte do código no repositório é benigna. Quando os alvos tentam executar o projeto de acordo com a folha de perguntas, dados são obtidos de três locais remotos:

  • hxxps://en.wikipedia[.]org/wiki/List_of_S%26P_500_companies
  • hxxps://en.wikipedia[.]org/wiki/Currency_pair
  • hxxps://en.stockslab[.]org/symbols/sp500

Duas das URLs extraem dados da Wikipedia. A terceira URL usa um domínio controlado pelo Slow Pisces. Esse padrão — usar várias fontes de dados, a maioria legítima, mas uma maliciosa — é comum nos repositórios Python do grupo.

O servidor mal-intencionado de comando e controle (C2) é configurado para imitar o formato das fontes legítimas. Nesse caso, ele usa o subdomínio .en e o domínio de nível superior (TLD) .org , como vemos no domínio legítimo da Wikipédia acima.

Desserialização de YAML

O Slow Pisces poderia simplesmente colocar o malware diretamente no repositório ou executar o código do servidor C2 usando as funções internas eval ou exec do Python. No entanto, essas técnicas são facilmente detectadas, tanto por inspeção manual quanto por soluções antivírus.

Em vez disso, o Slow Pisces primeiro garante que o servidor C2 responda com dados válidos do aplicativo. Por exemplo, o repositório mencionado acima espera uma lista de símbolos de empresas S&P 500. A URL C2 responde inicialmente com esses dados em uma lista formatada em JSON.

Os atores de ameaça enviam apenas uma carga maliciosa para alvos validados, provavelmente com base no endereço IP, na geolocalização, no horário e nos cabeçalhos de solicitação HTTP. O foco em indivíduos contatados via LinkedIn, em oposição a campanhas amplas de phishing, permite que o grupo controle rigidamente os estágios posteriores da campanha e entregue payloads apenas às vítimas esperadas.

Para evitar as funções suspeitas eval e exec , o Slow Pisces usa desserialização YAML para executar sua carga útil, conforme mostrado na Figura 5.

Captura de tela do código Python que define uma função ‘fetch_symbols’ que recupera símbolos de ações do S&P 500 usando uma chamada de API, lida com diferentes tipos de conteúdo e processa respostas com base em seu tipo de conteúdo. A última linha tem uma seção destacada em uma caixa vermelha.
Figura 5. Código Python mostrando o ponto de entrada do malware Slow Pisces usando desserialização YAML.

Esse código obtém dados do servidor C2 via HTTPS e verifica o cabeçalho de resposta Content-Type. Se o cabeçalho indicar dados JSON (application/json), o código analisará e retornará o JSON para o aplicativo.

Se a resposta indicar dados YAML (application/yaml), o código usará a função yaml.load() da biblioteca PyYAML para analisar os dados. Essa função é inerentemente insegura e a documentação do PyYAML recomenda explicitamente yaml.safe_load() para entrada não confiável.

O YAML é normalmente usado para arquivos de configuração, como o exemplo mostrado abaixo:

No entanto, yaml.load() pode serializar e desserializar objetos Python arbitrários, não apenas dados YAML válidos. Por exemplo, o código Python a seguir imprime os números de 0 a 4:

Se esse código fosse serializado usando yaml.dump(), ele se tornaria o seguinte:

Por fim, quando esses dados forem passados para yaml.load() , ele executará o código original: range(0, 5).

Isso destaca um ponto de detecção em potencial, pois os payloads para o repositório Python e o malware que usa desserialização YAML em geral contêm !!python/object/apply:builtins se a carga útil usar uma função Python embutida.

Os seguintes estágios da Tabela 1 existem primariamente na memória e geralmente não deixam traços no disco. Para ajudar a comunidade na detecção e conscientização, fizemos o upload desses payloads para o VirusTotal. O payload de desserialização YAML executa o malware que chamamos de RN Loader e RN Stealer com base no formato de token C2 que observamos no RN Stealer, que discutiremos nas seções a seguir.

Estágio Hash SHA256
Payload de desserialização YAML 47e997b85ed3f51d2b1d37a6a61ae72185d9ceaf519e2fdb53bf7e761b7bc08f
RN Loader 937c533bddb8bbcd908b62f2bf48e5bc11160505df20fea91d9600d999eafa79
RN Stealer e89bf606fbed8f68127934758726bbb5e68e751427f3bcad3ddf883cb2b50fc7

Tabela 1. Payloads do repositório Python.
O payload de desserialização YAML do Slow Pisces começa criando a pasta Public no diretório pessoal da vítima e criando um novo arquivo nesse diretório chamado __init__.py. Os dados Base64 incorporados são decodificados e escritos nesse arquivo, contendo o próximo estágio de infecção (RN Loader), que é então executado.

RN Loader

Esse arquivo recém-criado para o RN Loader em ~/Public/__init__.py se exclui após a execução, garantindo que ele exista somente na memória. Ele envia informações básicas sobre o computador e o sistema operacional da vítima por HTTPS para o mesmo C2 em en.stockslab[.]org, seguido por um loop de comando com as seguintes opções na Tabela 2.

Código Descrição
0 Dormir (Sleep) por 20 segundos
1 Decodifica em base64 o conteúdo enviado e o salva no arquivo init.dll para Windows ou init para todos os outros sistemas operacionais.

Define uma variável de ambiente X_DATABASE_NAME como uma cadeia de caracteres (string) vazia.

Carrega e executa a DLL baixada usando ctypes.cdll.LoadLibrary.

2 Decodifica em base64 o conteúdo enviado e o executa usando o exec incorporado ao Python.
3 Decodifica em base64 o conteúdo enviado e um parâmetro. O conteúdo é salvo no arquivo dockerd, enquanto o parâmetro é salvo como docker-init.

O dockerd é então executado em um novo processo, com o docker-init fornecido como argumento de linha de comando.

9 Termina a execução.

Tabela 2. Tabela de comandos do RN Loader.

Os payloads do loop de comando da Tabela 2 usando as opções 1 e 3 são atualmente desconhecidos e provavelmente são acionados por condições específicas. No entanto, recuperamos um infostealer baseado em Python fornecido pela opção 2, e rastreamos esse malware como RN Stealer.

RN Stealer

O RN Stealer primeiro gera um ID de vítima aleatório, usado posteriormente como um cookie em todas as comunicações com o servidor C2. Em seguida, ele solicita uma chave XOR do servidor para encriptar os dados exfiltrados.

A comunicação com o servidor C2 ocorre por HTTPS, usando tokens codificados em Base64 para identificar os tipos de solicitação e resposta. O payload analisado inclui quatro tipos de token:

  • R0 - solicitando a chave XOR
  • R64 - exfiltrando dados
  • R128 - exfiltrando dados compactados
  • R256 - infostealer completo

O formato desses tipos de token (a letra R seguida de um número inteiro N) levou a nossos nomes para esse payload. Chamamos o payload de RN Stealer e o estágio anterior de RN Loader.

Recuperamos o script para essa amostra do RN Stealer de um sistema macOS. Dessa forma, os autores da ameaça adaptaram essa amostra para roubar informações específicas de dispositivos macOS, incluindo:

  • Informações básicas sobre a vítima: nome de usuário, nome da máquina e arquitetura
  • Aplicativos instalados
  • Uma lista de diretórios e o conteúdo de nível superior do diretório inicial da vítima
  • O arquivo login.keychain-db, que armazena as credenciais salvas em sistemas macOS
  • Chaves SSH armazenadas
  • Arquivos de configuração para AWS, Kubernetes e Google Cloud

Os dados coletados pelo RN Stealer provavelmente determinam se acesso persistente é necessário. Em caso afirmativo, podemos inferir as seguintes etapas para essa cadeia de infecção do Python:

  1. O servidor C2 verifica vítimas que estejam enviando sinais (beaconing) com relação a um conjunto desconhecido de critérios. As vítimas válidas recebem um payload de desserialização YAML. Vítimas inválidas recebem dados JSON benignos.
  2. O payload de desserialização estabelece um loop de comando com o servidor C2, exfiltrando informações básicas da vítima e fornecendo um infostealer Python personalizado por meio do código de opção 2 na Tabela 2.
  3. O infostealer reúne informações mais detalhadas sobre a vítima, que os atacantes provavelmente usaram para determinar se precisavam de acesso contínuo.
    1. Se o acesso contínuo for necessário, o servidor C2 entrega um payload por meio dos códigos de opção 1 ou 3.
    2. Se o acesso não for mais necessário, o código de opção 9 encerra a execução do malware, removendo todo o acesso, já que o payloadreside apenas na memória.

Estágio 3b - Repositório JavaScript

Se as vítimas se candidatassem a uma função JavaScript, elas poderiam por sua vez encontrar um projeto "Cryptocurrency Dashboard", semelhante ao exemplo da Figura 6 abaixo.

Captura de tela de um repositório do GitHub chamado “Cryptocurrency Dashboard”, com um arquivo README.md exibido. Esse README inclui as seções: Recursos, Instalação, Uso, Estrutura do projeto, Configuração, Dependências e Licença. Ele descreve o projeto como um aplicativo criado com Node.js, Express e EJS que exibe dados históricos e em tempo real de várias criptomoedas.
Figura 6. Repositório JavaScript.

Esse aplicativo contém um arquivo .env com o C2 e um datasource legítimo:

  • PORT=3000
  • COINGECKO_API_URL=hxxps://api.coingecko[.]com/api/v3
  • JQUERY_API_URL=hxxps://update.jquerycloud[.]io/api/v1

O valor COINGECKO_API_URL é usado para buscar dados para o Cryptocurrency Dashboard, enquanto o valor JQUERY_API_URL representa um servidor C2 controlado pelo Slow Pisces. Semelhante ao repositório Python, o servidor JavaScript C2 fornece payloads apenas para alvos validados; caso contrário, ele responde com um número de versão.

O repositório usa a ferramenta de modelagem Embedded JavaScript (EJS), passando as respostas do servidor C2 para a função ejs.render(), mostrada abaixo na Figura 7.

Captura de tela mostrando um trecho de código em JavaScript. Ele inclui um comentário e uma chamada de função para renderizar uma página inicial com configurações e itens por página. res.render está destacado em uma caixa vermelha.
Figura 7. Código JavaScript mostrando o ponto de entrada do malware Slow Pisces usando a função de renderização EJS.

Assim como o uso de yaml.load(), essa é outra técnica que o Slow Pisces utiliza para ocultar a execução de código arbitrário de seus servidores C2, e esse método talvez só seja aparente ao visualizar um payload válido.

A função de renderização EJS aceita vários parâmetros, um dos quais é chamado de view options. Dentro disso, um código JavaScript arbitrário pode ser fornecido e executado por meio da chave escapeFunction.

Um pesquisador de Taiwan, conhecido como Huli, discutiu os detalhes técnicos de como isso resulta em execução arbitrária de código em um post de um CTF. No entanto, podemos entender suficientemente que um payload estruturado conforme mostrado na Figura 8 resultará na execução do código contido em escapeFunction quando passado para ejs.render().

Captura de tela de um trecho de código JavaScript envolvendo funções com “escapeFunction” destacado em uma caixa vermelha.
Figura 8. Carga parcial de renderização EJS.

Infelizmente, não conseguimos recuperar a parte total desse payload. Dessa forma, podemos apenas supor que um novo diretório .jql é criado no diretório inicial do usuário, onde um arquivo chamado helper.js é baixado (dropped), contendo dados codificados em Base64.

Infraestrutura

A linha do tempo abaixo, na Figura 9, detalha a infraestrutura de C2 usada nessa campanha de fevereiro de 2024 a fevereiro de 2025, agrupada pelo tipo de repositório servido (JavaScript ou Python).

Linha do tempo da infraestrutura que rastreia o comando e os controles JavaScript (parte superior, rótulo amarelo) e o comando e os controles Python (parte inferior, rótulo laranja). A linha do tempo começa no final do primeiro trimestre de 2024 e continua até o segundo trimestre de 2025.
Figura 9. Linha do tempo da infraestrutura C2.

Como mencionado anteriormente, os domínios na infraestrutura desta campanha podem imitar o formato das fontes legítimas usadas junto com eles, frequentemente usando subdomínios como .api ou .cdn. Até o momento da publicação deste artigo, descobrimos a infraestrutura associada a essa campanha.

Conclusão

Este relatório abordou a campanha mais recente do Slow Pisces, que se fez passar por recrutadores no LinkedIn para atingir desenvolvedores do setor de criptomoedas com desafios de programação maliciosos. Embora não tenhamos conseguido recuperar a cadeia de ataque completa para os repositórios JavaScript, a versão Python da campanha forneceu dois novos payloads que chamamos de RN Loader e RN Stealer.

O uso do LinkedIn e do GitHub dessa maneira não é exclusivo. Vários grupos afiliados à RPDC usaram táticas semelhantes, como Alluring Pisces e Contagious Interview.

Esses grupos não apresentam sobreposições operacionais. No entanto, é digno de nota o fato de essas campanhas usarem vetores de infecção inicial semelhantes.

O Slow Pisces se destaca das campanhas de seus pares em segurança operacional. A entrega de payloads em cada estágio é fortemente protegida, existindo apenas na memória. E o ferramental de estágio posterior do grupo só é implantado quando necessário.

Em particular, o grupo fez uso de duas técnicas para ocultar a funcionalidade:

  • Desserialização de YAML
  • EJS escapeFunction

Essas duas técnicas dificultam muito a análise, a detecção e a caça de ameaças. Da mesma forma, desenvolvedores relativamente novos ou inexperientes no setor de criptomoedas teriam dificuldade em identificar esses repositórios como maliciosos.

Com base em relatórios públicos de roubos de criptomoedas, essa campanha parece ser altamente bem-sucedida e provavelmente persistirá em 2025. Embora este artigo tenha destacado duas possíveis oportunidades de detecção para desserialização de YAML e payloads de EJS escapeFunction, a mitigação mais eficaz continua sendo a segregação rigorosa de dispositivos corporativos e pessoais. Isso ajuda a evitar o comprometimento de sistemas corporativos por campanhas de engenharia social direcionadas.

Proteção e mitigação da Palo Alto Networks

Os clientes da Palo Alto Networks estão mais bem protegidos contra as ameaças discutidas acima por meio dos seguintes produtos:

Se você acha que pode ter sido comprometido ou tem um assunto urgente, entre em contato com a equipe de resposta a incidentes da Unit 42 ou ligue para:.

  • América do Norte: ligação gratuita: +1 (866) 486-4842 (866.4.UNIT42)
  • Reino Unido: +44.20.3743.3660
  • Europa e Oriente Médio: +31.20.299.3130
  • Ásia: +65.6983.8730
  • Japão: +81.50.1790.0200
  • Austrália: +61.2.4062.7950
  • Índia: 00080005045107

A Palo Alto Networks compartilhou essas descobertas com nossos colegas membros da Cyber Threat Alliance (CTA). Os membros da CTA usam essa inteligência para implantar rapidamente proteções para seus clientes e para interromper sistematicamente os atores cibernéticos mal-intencionados. Saiba mais sobre a Cyber Threat Alliance.

Indicadores de comprometimento

Domínio Endereço IP Visto pela primeira vez Visto pela última vez Repositório
getstockprice[.]com 70.34.245[.]118 2025-02-03 2025-02-20 Python
cdn[.]clubinfo[.]io 5.206.227[.]51 2025-01-21 2025-02-19 Python
getstockprice[.]info 131.226.2[.]120 2025-01-21 2025-01-23 Python
api[.]stockinfo[.]io 136.244.93[.]248 2024-10-30 2024-11-11 Python
cdn[.]logoeye[.]net 54.39.83[.]151 2024-10-29 2024-11-03 Python
en[.]wfinance[.]org 195.133.26[.]32 2024-10-12 2024-11-01 Python
en[.]stocksindex[.]org 185.236.231[.]224 2024-09-11 2024-10-04 Python
cdn[.]jqueryversion[.]net 194.11.226[.]16 2024-08-23 2024-09-23 JavaScript
en[.]stockslab[.]org 91.103.140[.]191 2024-08-19 2024-09-12 Python
update[.]jquerycloud[.]io 192.236.199[.]57 2024-07-03 2024-08-22 JavaScript
cdn[.]soccerlab[.]io 146.70.124[.]70 2024-08-07 2024-08-21 Python
api[.]coinpricehub[.]io 45.141.58[.]40 2024-05-06 2024-08-06 Java
cdn[.]leaguehub[.]net 5.133.9[.]252 2024-07-15 2024-07-21 Python
cdn[.]clublogos[.]io 146.19.173[.]29 2024-06-24 2024-07-12 Python
api[.]jquery-release[.]com 146.70.125[.]120 2024-06-10 2024-06-28 JavaScript
cdn[.]logosports[.]net 185.62.58[.]74 2024-05-08 2024-06-23 Python
skypredict[.]org 80.82.77[.]80 2024-05-06 2024-06-16 JavaScript
api[.]bitzone[.]io 192.248.145[.]210 2024-04-25 2024-05-13 Python
weatherdatahub[.]org 194.15.112[.]200 2024-04-05 2024-05-03 JavaScript
api[.]ethzone[.]io 91.234.199[.]90 2024-04-16 2024-04-24 Python
api[.]fivebit[.]io 185.216.144[.]41 2024-04-08 2024-04-14 Python
blockprices[.]io 91.193.18[.]201 2024-03-15 2024-04-09 JavaScript
api[.]coinhar[.]io 185.62.58[.]122 2024-03-26 2024-04-09 Python
mavenradar[.]com 23.254.230[.]253 2024-02-21 2024-03-26 JavaScript
indobit[.]io 146.70.88[.]126 2024-03-19 2024-03-20 Python
api[.]thaibit[.]io 79.137.248[.]193 2024-03-07 2024-03-09 Python
chainanalyser[.]com 38.180.62[.]135 2024-02-23 2024-03-06 JavaScript

Recursos adicionais

 

Enlarged Image