Nuestras pipelines de detección de malware se activaron recientemente con un pequeño grupo de paquetes en npm que parecían... familiares.
Paquetes como json-bigint-extend, jsonfx, y jsonfb estaban imitando el popular json-bigint librería: misma funcionalidad, un archivo README idéntico e incluso un nombre de autor incómodamente cercano al mantenedor original.
La mayoría de las veces, este patrón indica ataques comunes a la cadena de suministro, como typosquatting y confusión de dependencias, diseñados para comprometer sistemas y exfiltrar secretos. Pero este se sintió diferente casi de inmediato.
No estaba intentando atacar a todo el mundo. Estaba intentando atacar algo.
El secuestro
A primera vista, json-bigint-extend se comporta exactamente como la legítima json-bigint librería: exporta las conocidas funciones parse/stringify utilizadas para soportar enteros grandes en JSON. De hecho, la mayoría de los desarrolladores y organizaciones no notarían nada inusual. Este payload está específicamente diseñado para permanecer en silencio y solo activarse cuando detecta que se está ejecutando dentro de un entorno objetivo específico, comprobando el valor de una variable de entorno específica llamada SERVICE_NAME.
Una vez que detecta que está en el entorno correcto, instala dos backdoors:
Primero, instala un middleware de Express dirigido, cableado específicamente a una ruta de pago (/v1/pay/purchase-goods). Este middleware está diseñado para ejecutar dinámicamente código adicional obtenido de un endpoint. Tras una inspección más detallada del código obtenido, parece ser un complejo sistema de reescritura de flujos de caja utilizado para manipular un juego de apuestas.
const routeInjectionRules = {
'/v1/pay/purchase-goods': {
identify: function (handlers, fn, index) {
...
},
position: 'after',
extraMiddlewares: [function (req, res, next) {
// Translation: [Plugin] Mount risk middleware as post-payment success logic.
log('[插件] 支付成功后的后置逻辑挂载risk');
riskCode(req, res, next); // Executes dynamically fetched code
}]
}
};
En segundo lugar, un middleware a nivel de prototipo que discretamente aplica un 'monkey-patch' a Express.js, añadiendo un middleware global a cada ruta POST. Este middleware escucha un x-operation encabezado secreto y desbloquea cuatro tipos de comandos para el operador:
- RunSQL: ejecutar SQL arbitrario contra la base de datos de producción.
- RunFileList: listar archivos y directorios del lado del servidor.
- RunFileContent: descargar el contenido de un archivo elegido.
- CompressDownload: descargar un directorio como un archivo zip.
El panel del operador
Dentro del paquete, también hay una página HTML incrustada para un “servicio de descarga de compresión de directorios” (título en chino: 目录压缩下载服务).

Aunque esta página nunca fue conectada en ningún lugar del código de puerta trasera que observamos, parece ser una interfaz de usuario (UI) orientada al operador para navegar y exfiltrar directorios como archivos zip.
Manipulación de resultados de apuestas
Lo más preocupante: esa riskCode(...) función invocada en el middleware está controlada remotamente y se actualiza cada 30 segundos.
Aunque la carga útil (payload) no se invoca activamente (todavía), observamos una lógica capaz de ajustar retroactivamente el historial de juego reciente de un usuario. El componente más sofisticado de esta puerta trasera (backdoor) es la fixFlow función, un motor de manipulación de saldos que reescribe retroactivamente el historial de apuestas de un usuario para lograr un cambio de saldo deseado, manteniendo la apariencia de una jugabilidad legítima.
La orquestación principal ocurre en este fixFlow, que ejecuta una pipeline de cuatro fases:
// Takes a desired amount as argument
async fixFlow(backupAmount) {
// Phase 1: Load recent cashflow records
const original = await this.getCashFlow();
// Phase 2: Compute required adjustments to betting history
const adjuster = new GameResultAdjuster({ debug: false });
const adjustResult = adjuster.adjustDBData(original, backupAmount);
const { backupRecords, adjustedResult } = adjustResult;
const rewritten = this.writeBackFlowData(backupRecords);
// Phase 3: Validate consistency
const validation = this.validateCashFlowChain(...);
if (!validation.isValid) {
...
}
// Phase 4: Persist to database
await this.updateUserCashFlow(rewritten);
await sendToUser(userId, { pop: false });
await this.updateUserGameRoundFlow(gameTasks);
}
La función carga los registros recientes de flujo de caja (cash-flow) y los convierte en registros de juego estructurados. Posteriormente, el adjustDBData método genera resultados de apuestas de reemplazo diseñados para producir un cambio de saldo fabricado. Lo interesante es que, en lugar de depender de un solo algoritmo, ejecuta dos estrategias competitivas (greedy vs. backtracking), y selecciona el enfoque con la puntuación de "realismo" más alta. Después de verificar la cadena de saldo reescrita para asegurar la consistencia, updateUserCashFlow y updateUserGameRoundFlow escribe los registros alterados a través de Prisma de nuevo en la base de datos de producción en vivo, mientras sendToUser envía el evento de saldo actualizado al dispositivo del usuario.
Estrategia de Fraude Greedy
El enfoque greedy divide la cantidad objetivo deseada de manera uniforme entre las rondas disponibles. Es rápido, pero produce patrones sospechosos. Imagine que necesita distribuir 300 monedas fabricadas en 3 rondas de juego. El enfoque greedy simplemente divide de manera uniforme: 100 por ronda. Para cada ronda, establece el pago para lograr el resultado deseado de esa ronda. Sin embargo, esto tiende a parecer falso. Los juegos reales no obtienen resultados consistentes en cada ronda.
Búsqueda Backtracking
El enfoque de backtracking explora todo el espacio de soluciones, probando diferentes combinaciones de apuesta/pago hasta encontrar una que alcance el objetivo deseado con un margen de error del 0,01%. En lugar de comprometerse con decisiones de inmediato, explora el árbol completo de posibilidades. Prueba una cantidad de apuesta, ve a dónde lleva, y si no funciona, deshazla y prueba otra apuesta. Esto es como resolver un laberinto probando cada camino hasta encontrar la salida. Este enfoque encuentra una cadena de resultados realista que tiene en cuenta las restricciones, como el efectivo disponible del usuario en el momento de la apuesta.
Funciona de la siguiente manera:
- Generar una lista de posibles cantidades de apuesta
- Filtrar las apuestas que el usuario no puede permitirse
- Puntuar cada una por su "alcanzabilidad" al objetivo deseado
- Probar primero la opción con mejor puntuación
- Si lleva al éxito, hemos terminado
- Si lleva al fracaso, deshacer y probar la siguiente apuesta
El algoritmo emplea varias optimizaciones, como la memoización para evitar la reexploración de intentos fallidos, y la poda por alcanzabilidad para omitir ramas que no pueden alcanzar matemáticamente el objetivo deseado.
Puntuación de Calidad: Hacer que el Fraude Parezca Natural
Después de ejecutar ambas estrategias, el sistema aplica un sofisticado mecanismo de puntuación de calidad que evalúa cuán "realista" parece un historial de apuestas falsificado. Esta puntuación determina qué salida de la estrategia de fraude se utiliza y sirve como métrica para el éxito del ataque.
// Generar una puntuación de calidad
const overallQuality = this.evaluateLogsQuality(adjustedGameLogs, completeness.actualNetGain);El evaluateLogsQuality La función comienza con 100 puntos y deduce penalizaciones por patrones sospechosos. Algunas de estas penalizaciones incluyen:
- Apuestas Imposibles (Penalización: -100): Una apuesta que excede el saldo disponible es imposible en el juego real. Sería rechazada por el servidor del juego.
- Pagos Huérfanos (Penalización: -2): Un pago sin una apuesta correspondiente en la misma ronda es estructuralmente inválido. En el juego legítimo, cada pago es el resultado de una apuesta. Un pago que aparece de la nada sugiere manipulación de registros.
- Rondas Intercaladas (Penalización: -1 a -40 según la gravedad): Los jugadores reales suelen completar una ronda antes de comenzar otra. El intercalado excesivo, es decir, iniciar varias rondas simultáneamente, parece un comportamiento de bot o manipulación.
- Multiplicadores Irrealistas (Penalización: -15): Ganar a 100x o más es raro. Si más del 10% de las rondas muestran multiplicadores extremos, el patrón parece fabricado y se aplica una penalización. El algoritmo greedy simple tiende a producir este patrón.
- Juego Monótono (Penalización: -10): Un jugador que pierde cada ronda en muchos juegos es sospechoso; incluso los jugadores con mala suerte ganan ocasionalmente.
En conclusión, significa que el objetivo no es solo el fraude. Es un fraude que supera las comprobaciones de consistencia interna, fabricando ganancias y pérdidas mientras mantiene la contabilidad consistente utilizando un ingenioso mecanismo anti-detección.
Bappa Rummy
No podemos decir con certeza qué juego está siendo atacado, pero las referencias circundantes sugieren que podría ser una aplicación de apuestas llamada Bappa Rummy. Uno de los endpoints referenciados en el archivo es gameland.myapptest.top/v1, y una búsqueda rápida de transparencia de certificados SSL para ese dominio muestra hosts relacionados como gali.web.test.myapptest.top. Al inspeccionarlo se revela lo que parece una página de aterrizaje rota vinculada a Bappa Rummy, lo que la convierte en un objetivo plausible de la puerta trasera. La aplicación parece ser ampliamente promocionada en línea a través de programas de referidos y tiendas de aplicaciones alternativas, pero ya no figura en la Google Play Store oficial.

Detección y prevención
Aunque no sabemos quién está detrás de la puerta trasera, lo más preocupante es lo que hace una vez que llega al entorno adecuado. Esto no es “solo” un implante de dependencia típico que exfiltra código fuente, secretos o datos de clientes.
En cambio, se conecta directamente a la lógica de negocio, ejecuta código controlado remotamente sobre tráfico real y puede reescribir el historial financiero respaldado por la base de datos. Si su monitorización asume que los registros de la base de datos son fiables, este tipo de manipulación puede permanecer invisible durante mucho tiempo.
Si ya utiliza Aikido, este paquete sería marcado en su feed como un hallazgo crítico de 100/100.
¿Todavía no está en Aikido? Cree una cuenta gratuita y vincule sus repositorios. El plan gratuito incluye nuestra cobertura de detección de malware (no se requiere tarjeta de crédito).
Finalmente, tener una herramienta que pueda detener el malware en tiempo real a medida que aparece puede prevenir una infección grave. Esta es la idea detrás de Aikido Safe Chain, una herramienta gratuita y de código abierto que envuelve npm, npx, yarn, pnpm y pnpx y utiliza tanto IA como investigadores de malware humanos para detectar y bloquear los últimos riesgos de la cadena de suministro antes de que entren en su entorno.
Indicadores de compromiso
Paquetes y autores:
- jsonfb (por sidoraress)
- jsonfx (por sidoraress)
- json-bigint-extend (por sidoraress & infinitynodestudio)
La puerta trasera se comunica con un host remoto tanto para las actualizaciones de payload como para el registro.
Endpoints observados:
https://payment[.]y1pay[.]vip/v1/risk/get-risk-codehttps://payment[.]y1pay[.]vip/v1/risk/loghttps://payment[.]snip-site[.]cchttps://gameland[.]21game[.]livehttps://gameland[.]myapptest[.]top/v1https://gameland[.]nbzysp1[.]com/v1https://gameland[.]21game[.]live/v1
Otros IOCs y comportamientos rastreables:
- Solicitudes que contienen
x-operation headercon uno de los cuatro tokens de operación:- RunSQL (token: cfh2DNITa84qpYQ0tdCz)
- RunFileList (token: m3QiEkg8Y1r9LFTI5e4f)
- RunFileContent (token: Y3SrZjVqWOvKsBdpTCh7)
- CompressDownload (token: SJQf31UJkZ1f88q9m361)
- Modificaciones en tiempo de ejecución a
express.Route.prototype.post

