当社のマルウェア検出パイプラインは最近、npm上の一部のパッケージ群で反応を示しました。それは...見覚えのあるものでした。
「json-bigint-extend」、「jsonfx」、「jsonfb」といったパッケージは、 json-bigint-extend, jsonfx、および jsonfb 人気の「json-bigint」ライブラリを模倣しており、 json-bigint 同じ機能、同一のREADMEファイル、さらにはオリジナルのメンテナーに不快なほど近い著者名まで持っていました。
ほとんどの場合、このパターンはタイポスクワッティングや依存関係の混乱といった一般的なサプライチェーン攻撃を示しており、システムを侵害し、シークレットを外部に漏洩させることを目的としています。しかし、このケースはすぐに何か違うと感じられました。
これはすべての人を標的にしていたわけではありません。特定の何かを標的にしようとしていました。
ハイジャック
一見すると、 json-bigint-extend 正当な「json-bigint」ライブラリとまったく同じように動作し、 json-bigint JSONで大きな整数をサポートするために使用される、おなじみのparse/stringify関数をエクスポートします。実際、ほとんどの開発者や組織は異常に気づかないでしょう。このペイロードは、特定の環境変数「SERVICE_NAME」の値をチェックすることで、特定のターゲット環境内で実行されていることを検出した場合にのみ静かにトリガーされるように特別に設計されています。 SERVICE_NAME.
適切な環境にあることを検出すると、2つのバックドアをインストールします。
まず、支払いルート(「/v1/pay/purchase-goods」)に特化して組み込まれた、ターゲットを絞ったExpressミドルウェアをインストールします。/v1/pay/purchase-goods)。このミドルウェアは、エンドポイントから取得した追加コードを動的に実行するように設計されています。取得したコードをさらに調査すると、ギャンブルゲームを操作するために使用される複雑なキャッシュフロー書き換えシステムであるようです。
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
}]
}
};
次に、Express.jsを静かにモンキーパッチするプロトタイプレベルのミドルウェアで、グローバルミドルウェアを すべての POSTルートに追加します。このミドルウェアは、シークレットの x-operation 「x-operation」ヘッダーをリッスンし、オペレーターに4種類のコマンドを解除します。
- RunSQL: 本番データベースに対して任意のSQLを実行します。
- RunFileList: サーバー側のファイルとディレクトリを一覧表示します。
- RunFileContent: 選択したファイルの内容をダウンロードします。
- CompressDownload: ディレクトリをzipファイルとしてダウンロードします。
オペレーターダッシュボード
パッケージ内には、「ディレクトリ圧縮ダウンロードサービス」という埋め込みHTMLページも存在します(中国語タイトル: 目录压缩下载服务)。

観測されたバックドアコードのどこにもこのページが接続されている形跡はありませんでしたが、これはディレクトリを閲覧し、zipファイルとして外部に持ち出すためのオペレーター向けUIであるように見えます。
ギャンブルの結果操作
恐ろしいのは、その riskCode(...) ミドルウェアで呼び出される関数がリモート制御され、30秒ごとに更新されることです。
ペイロードはまだ積極的に呼び出されていませんが、ユーザーの最近のゲーム履歴を遡って調整できるロジックが確認されました。このバックドアの最も洗練されたコンポーネントは、 fixFlow 関数です。これは、ユーザーのギャンブル履歴を遡って書き換え、正当なゲームプレイの外観を維持しながら、望ましい残高変更を達成するバランス操作エンジンです。
主要なオーケストレーションは、この fixFlowで行われ、4段階のパイプラインを実行します。
// 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);
}
この関数は、最近のキャッシュフロー記録をロードし、それらを構造化されたゲームログに変換します。その後、 adjustDBData メソッドは、偽造された残高変更を生み出すように設計された代替のベッティング結果を生成します。興味深いのは、1つのアルゴリズムに依存するのではなく、2つの競合する戦略(グリーディ vs バックトラッキング)を実行し、最も「現実的」なスコアを持つアプローチを選択します。書き換えられた残高チェーンの一貫性を検証した後、 updateUserCashFlow そして updateUserGameRoundFlow Prismaを介して変更された記録を稼働中の本番データベースに書き込み、 sendToUser 更新された残高イベントをユーザーのデバイスにプッシュします。
グリーディ詐欺戦略
グリーディなアプローチは、目標とする金額を利用可能なラウンドに均等に分配します。これは高速ですが、不審なパターンを生み出します。例えば、300枚の偽造コインを3つのゲームラウンドに分配する必要があるとします。グリーディなアプローチは単純に均等に分割し、各ラウンドに100枚を割り当てます。各ラウンドで、そのラウンドの望ましい結果を達成するようにペイアウトを設定します。しかし、これは不自然に見える傾向があります。実際のゲームでは、毎ラウンド一貫した結果が出ることはありません。
バックトラッキング探索
バックトラッキングのアプローチは、完全な解空間を探索し、0.01%の誤差範囲内で目標を達成する組み合わせが見つかるまで、様々なベット/ペイアウトの組み合わせを試行します。決定をすぐに確定するのではなく、可能性の完全なツリーを探索します。あるベット額を試してその結果を確認し、うまくいかない場合は元に戻して別のベットを試します。これは、出口を見つけるまであらゆる道を試す迷路の解き方に似ています。このアプローチは、ベット時のユーザーの利用可能な現金などの制約を考慮した、現実的な結果の連鎖を見つけ出します。
これは次のように機能します。
- 可能なベット額のリストを生成する
- ユーザーが支払えないベットを除外する
- 各ベットを目標達成への「到達可能性」でスコアリングする
- 最もスコアの高いオプションから試す
- 成功すれば完了
- 失敗した場合は元に戻し、次のベットを試す
このアルゴリズムは、失敗した試行の再探索を避けるためのメモ化や、数学的に目標に到達できないブランチをスキップするための到達可能性プルーニングなど、いくつかの最適化を採用しています。
品質スコアリング:詐欺を自然に見せる
両方の戦略が実行された後、システムは、偽造されたギャンブル履歴がどれほど「現実的」に見えるかを評価する高度な品質スコアリングメカニズムを適用します。このスコアは、どの詐欺戦略の出力が使用されるかを決定し、攻撃の成功の指標として機能します。
// 品質スコアを生成する
const overallQuality = this.evaluateLogsQuality(調整済みゲームログ, 完全性.実際の純増分);会社情報 ログ品質評価 関数は100ポイントから開始し、不審なパターンに対してペナルティを差し引きます。ペナルティの一例は以下の通りです:
- 不可能なベット(ペナルティ:-100):利用可能な残高を超えるベットは実際のゲームプレイでは不可能です。ゲームサーバーによって拒否されます。
- 孤立した配当(ペナルティ:-2):同一ラウンドにおいて対応するベットが存在しない配当は構造的に無効である。正当なゲームプレイにおいては、全ての配当はベットの結果として発生する。突然現れた配当は記録改ざんの可能性を示唆する。
- 交互ラウンド(ペナルティ:深刻度により-1~-40):実際のプレイヤーは通常、1ラウンドを完了してから次のラウンドを開始します。過度な交互処理、すなわち複数のラウンドを同時に開始する行為は、ボットの動作や操作行為と見なされます。
- 非現実的な倍率(ペナルティ:-15): 100倍以上の勝利は 稀である。ラウンドの10%以上が極端な倍率を示す場合、そのパターンは人為的に操作されたように見え、ペナルティが適用される。単純な貪欲アルゴリズムはこのパターンを生成する傾向がある。
- 単調なゲームプレイ(ペナルティ:-10):多くのゲームで全てのラウンドを負け続けるプレイヤーは不審である。運が悪いプレイヤーでも時々は勝つものだ。
結論として、その目的は単なる詐欺ではない。内部整合性チェックをすり抜け、巧妙な検知回避メカニズムを用いて会計処理の一貫性を保ちつつ、勝敗を捏造する詐欺である。
バッパ・ラミー
どのゲームが標的とされているかは断定できませんが、関連する記述から、ギャンブルアプリ「Bappa Rummy」である可能性が示唆されています。ファイル内で言及されているエンドポイントの一つはgです。ameland.myapptest.top/v1また、そのドメインのSSL証明書透過性に関する簡単な検索では、関連するホストとして以下のようなものが表示されます: ガリ.ウェブ.テスト.マイアプリテスト.トップ調査の結果、Bappa Rummyに関連した破損したランディングページのようなものが確認され、これがバックドアの標的として有力な候補となっている。このアプリは紹介プログラムや代替アプリストアを通じてオンライン上で広く宣伝されているようだが、公式のGoogle Playストアでは既に掲載されていない。

検出と防止
バックドアの背後に誰がいるかは不明ですが、恐ろしいのは、適切な環境に侵入した際にそれが何をするかです。これは、ソースコード、シークレット、または顧客データを外部に持ち出すような「単なる」典型的な依存関係インプラントではありません。
その代わりに、これはビジネスロジックに直接フックし、実際のリクエストに対してリモート制御されたコードを実行し、データベースに保存された財務履歴を書き換えることができます。監視システムがデータベースログを信頼できると仮定している場合、この種の操作は長期間にわたって検出されない可能性があります。
すでにAikidoをご利用の場合、このパッケージは、フィード内で100/100のクリティカルな検出結果としてフラグ付けされます。
まだAikidoをご利用ではありませんか? 無料アカウントを作成し、リポジトリを連携してください。無料プランには、マルウェア検出機能が含まれています(クレジットカードは不要です)。
最後に、マルウェアが出現した際にリアルタイムで阻止できるツールを持つことは、深刻な感染を防ぐことができます。これがAikido Safe Chainの背後にある考え方です。これは、npm、npx、yarn、pnpm、およびpnpxをラップする無料のオープンソースツールであり、AIと人間のマルウェア研究者の両方を利用して、最新のサプライチェーンリスクが環境に侵入する前に検出およびブロックします。
侵害の痕跡
パッケージと作成者:
- jsonfb (sidoraressによる)
- jsonfx (sidoraressによる)
- json-bigint-extend (sidoraressとinfinitynodestudioによる)
バックドアは、ペイロードの更新とロギングの両方のためにリモートホストと通信します。
観測されたエンドポイント:
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
その他のIOCと追跡可能な挙動:
- リクエストに含まれる
x-operationヘッダー次の4つの操作トークンのいずれかを使用して:- RunSQL (トークン: cfh2DNITa84qpYQ0tdCz)
- RunFileList (トークン: m3QiEkg8Y1r9LFTI5e4f)
- RunFileContent (トークン: Y3SrZjVqWOvKsBdpTCh7)
- CompressDownload (トークン: SJQf31UJkZ1f88q9m361)
- ランタイムの変更:
express.Route.prototype.post

