Nos pipelines de détection de logiciels malveillants ont récemment détecté un petit groupe de paquets sur npm qui semblaient... familiers.
Des forfaits tels que json-bigint-extend, jsonfx, et jsonfb imitaient le populaire json-grand nombre entier bibliothèque : mêmes fonctionnalités, fichier README identique, et même un nom d'auteur étrangement proche de celui du mainteneur d'origine.
La plupart du temps, ce schéma indique des attaques courantes visant la chaîne d'approvisionnement, telles que le typosquatting et la confusion des dépendances, conçues pour compromettre les systèmes et exfiltrer des secrets. Mais celle-ci semblait différente dès le départ.
Il n'essayait pas de frapper tout le monde. Il essayait de frapper quelque chose.
Le détournement
À première vue, json-bigint-extend se comporte exactement comme le légitime json-grand nombre entier bibliothèque : elle exporte les fonctions parse/stringify familières utilisées pour prendre en charge les grands nombres entiers dans JSON. En fait, la plupart des développeurs et des organisations ne remarqueraient rien d'inhabituel. Cette charge utile est spécialement conçue pour rester silencieuse et ne se déclencher que lorsqu'elle détecte qu'elle s'exécute dans un environnement cible spécifique, en vérifiant la valeur d'une variable d'environnement spécifique appelée SERVICE_NAME.
Une fois qu'il détecte qu'il se trouve dans le bon environnement, il installe deux portes dérobées :
Tout d'abord, il installe un middleware Express ciblé, connecté spécifiquement à une voie de paiement (/v1/paiement/achat-de-marchandises). Ce middleware est conçu pour exécuter dynamiquement du code supplémentaire récupéré à partir d'un point de terminaison. Après une inspection plus approfondie du code récupéré, il semble s'agir d'un système complexe de réécriture des flux de trésorerie utilisé pour manipuler un jeu de hasard.
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
}]
}
};
Deuxièmement, un middleware de niveau prototype qui modifie discrètement Express.js, en ajoutant un middleware global à chaque Route POST. Ce middleware écoute un secret opération croisée en-tête et débloque quatre types de commandes pour l'opérateur :
- RunSQL : exécutez n'importe quelle requête SQL sur la base de données de production.
- RunFileList : liste les fichiers et répertoires côté serveur.
- RunFileContent : télécharger le contenu d'un fichier sélectionné.
- CompresserTélécharger : télécharger un répertoire sous forme de fichier zip.
Le tableau de bord de l'opérateur
À l'intérieur du paquet, il y a également une page HTML intégrée pour un « service de téléchargement de compression de répertoire » (titre chinois : Service de téléchargement de fichiers compressés).

Bien que cette page n'ait jamais été connectée à aucun endroit dans le code de la porte dérobée que nous avons observé, elle semble être une interface utilisateur destinée aux opérateurs pour parcourir et exfiltrer des répertoires sous forme de fichiers zip.
Manipulation des résultats des jeux d'argent
Le plus effrayant : cela codeRisque(...) La fonction appelée dans le middleware est contrôlée à distance et mise à jour toutes les 30 secondes.
Bien que la charge utile ne soit pas (encore) activement invoquée, nous avons observé une logique capable d'ajuster rétroactivement l'historique de jeu récent d'un utilisateur. Le composant le plus sophistiqué de cette porte dérobée est le fixFlow fonction, un moteur de manipulation du solde qui réécrit rétroactivement l'historique de jeu d'un utilisateur afin d'obtenir le changement de solde souhaité tout en conservant l'apparence d'un jeu légitime.
L'orchestration principale se fait ici. fixFlow, qui exécute un pipeline en quatre phases :
// 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 fonction charge les enregistrements récents des flux de trésorerie et les convertit en journaux de jeu structurés. Ensuite, le ajuster les données DBD Cette méthode génère des résultats de paris de remplacement conçus pour produire un changement d'équilibre artificiel. Ce qui est intéressant, c'est qu'au lieu de s'appuyer sur un seul algorithme, elle utilise deux stratégies concurrentes (avide vs retour en arrière), et sélectionne l'approche ayant obtenu le score de « réalisme » le plus élevé. Après avoir vérifié la cohérence de la chaîne d'équilibrage réécrite, Mettre à jour le flux de trésorerie de l'utilisateur et Mettre à jour le flux de parties utilisateur Prisma les enregistrements modifiés via Prisma dans la base de données de production en direct, tout en envoyerÀL'utilisateur envoie l'événement de solde mis à jour à l'appareil de l'utilisateur.
Stratégie de fraude cupide
L'approche gloutonne répartit le montant cible souhaité de manière égale entre les tours disponibles. Elle est rapide, mais produit des schémas suspects. Imaginez que vous deviez distribuer 300 pièces fabriquées sur 3 tours de jeu. L'approche gloutonne les répartit simplement de manière égale : 100 par tour. Pour chaque tour, elle fixe le gain afin d'atteindre le résultat souhaité pour ce tour. Cependant, cela a tendance à paraître faux. Les jeux réels n'obtiennent pas des résultats constants à chaque tour.
Recherche par retour en arrière
L'approche par retour en arrière explore l'ensemble des solutions possibles, en essayant différentes combinaisons de paris/gains jusqu'à trouver celle qui atteint l'objectif souhaité avec une marge d'erreur de 0,01 %. Au lieu de prendre immédiatement une décision, elle explore l'ensemble des possibilités. Essayez un montant de pari, voyez où cela mène, et si cela ne fonctionne pas, annulez-le et essayez un autre pari. C'est comme résoudre un labyrinthe en essayant tous les chemins jusqu'à ce que vous trouviez la sortie. Cette approche permet de trouver une chaîne de résultats réaliste qui tient compte des contraintes, telles que l'argent disponible de l'utilisateur au moment du pari.
Cela fonctionne à peu près comme ceci :
- Générer une liste des montants de paris possibles
- Filtrer les paris que l'utilisateur ne peut pas se permettre
- Évaluez chacun en fonction de son « accessibilité » par rapport à l'objectif souhaité.
- Essayez d'abord l'option qui obtient le meilleur score.
- Si cela mène au succès, nous avons terminé.
- Si cela conduit à un échec, annulez et essayez le pari suivant.
L'algorithme utilise plusieurs optimisations, telles que la mémorisation pour éviter la réexploration des tentatives infructueuses, et l'élagage d'accessibilité pour ignorer les branches qui ne peuvent mathématiquement atteindre la cible souhaitée.
Évaluation de la qualité : rendre la fraude naturelle
Une fois les deux stratégies exécutées, le système applique un mécanisme sophistiqué de notation de la qualité qui évalue le degré de « réalisme » d'un historique de jeu falsifié. Ce score détermine quelle stratégie de fraude est utilisée et sert d'indicateur du succès de l'attaque.
// Générer un score de qualité
const overallQuality = this.evaluateLogsQuality(adjustedGameLogs, completeness.actualNetGain);Le évaluerLaQualitéDesJournaux La fonction commence à 100 points et déduit des pénalités pour les modèles suspects. Certaines de ces pénalités comprennent :
- Paris impossibles (pénalité : -100) : un pari qui dépasse le solde disponible est impossible dans le jeu réel. Il serait rejeté par le serveur du jeu.
- Paiements orphelins (pénalité : -2) : un paiement sans mise correspondante au cours du même tour est structurellement invalide. Dans un jeu légitime, chaque paiement est le résultat d'une mise. Un paiement apparaissant de nulle part suggère une falsification des enregistrements.
- Rounds entrelacés (pénalité : -1 à -40 selon la gravité) : les vrais joueurs terminent généralement un round avant d'en commencer un autre. Un entrelacement excessif, c'est-à-dire le fait de commencer plusieurs rounds simultanément, ressemble à un comportement de bot ou à une manipulation.
- Multiplicateurs irréalistes (pénalité : -15) : il est rare de gagner avec un multiplicateur supérieur ou égal à 100. Si plus de 10 % des tours affichent des multiplicateurs extrêmes, le modèle semble artificiel et une pénalité est appliquée. L'algorithme glouton simple a tendance à produire ce modèle.
- Gameplay monotone (pénalité : -10) : un joueur qui perd toutes les parties dans plusieurs jeux est suspect, même les joueurs malchanceux gagnent parfois.
En conclusion, cela signifie que l'objectif n'est pas seulement la fraude. Il s'agit d'une fraude qui résiste aux contrôles de cohérence internes, en fabriquant des gains et des pertes tout en conservant une comptabilité cohérente grâce à un mécanisme anti-détection astucieux.
Bappa Rami
Nous ne pouvons pas affirmer avec certitude quel jeu est visé, mais les références environnantes suggèrent qu'il pourrait s'agir d'une application de jeu appelée Bappa Rummy. L'un des points de terminaison référencés dans le fichier est gameland.myapptest.top/v1, et une recherche rapide de transparence des certificats SSL pour ce domaine montre des hôtes associés tels que gali.web.test.monapplikationtest.topSon inspection révèle ce qui semble être une page d'accueil cassée liée à Bappa Rummy, ce qui en fait une cible plausible pour la porte dérobée. L'application semble être largement promue en ligne par le biais de programmes de parrainage et d'autres boutiques d'applications, mais elle n'est plus répertoriée sur le Google Play Store officiel.

Détection et prévention
Même si nous ne savons pas qui se cache derrière cette porte dérobée, le plus effrayant est ce qu'elle fait une fois qu'elle se retrouve dans le bon environnement. Il ne s'agit pas « simplement » d'un implant de dépendance classique qui exfiltre le code source, les secrets ou les données des clients.
Au lieu de cela, il s'intègre directement à la logique métier, exécute du code contrôlé à distance sur le trafic réel et peut réécrire l'historique financier soutenu par la base de données. Si votre surveillance part du principe que les journaux de la base de données sont fiables, ce type de manipulation peut rester invisible pendant longtemps.
Si vous utilisez déjà Aikido, ce package serait signalé dans votre flux comme une découverte critique 100/100.
Vous n'êtes pas Aikido sur Aikido ? Créez un compte gratuit et connectez vos référentiels. L'offre gratuite inclut notre couverture de détection des logiciels malveillants (aucune carte de crédit requise).
Enfin, disposer d'un outil capable de bloquer les logiciels malveillants en temps réel dès leur apparition peut prévenir une infection grave. C'est le principe qui sous-tend Aikido Chain, un outil gratuit et open source qui s'intègre à npm, npx, yarn, pnpm et pnpx et utilise à la fois l'IA et des chercheurs en logiciels malveillants pour détecter et bloquer les derniers risques liés à la chaîne d'approvisionnement avant qu'ils ne pénètrent dans votre environnement.
Indicateurs de compromission
Paquets et auteurs :
- jsonfb (par sidoraress)
- jsonfx (par sidoraress)
- json-bigint-extend (par sidoraress & infinitynodestudio)
La porte dérobée communique avec un hôte distant à la fois pour les mises à jour de la charge utile et la journalisation.
Critères d'évaluation observés :
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
Autres IOC et comportements suspects :
- Demandes contenant
En-tête d'opération xavec l'un des quatre jetons d'opération :- RunSQL (jeton : cfh2DNITa84qpYQ0tdCz)
- RunFileList (jeton : m3QiEkg8Y1r9LFTI5e4f)
- RunFileContent (jeton : Y3SrZjVqWOvKsBdpTCh7)
- CompressDownload (jeton : SJQf31UJkZ1f88q9m361)
- Modifications apportées au runtime
express.Route.prototype.post

