スキャナーが見逃した攻撃:Cloudflareクライアントセキュリティがストアを守る方法

Cloudflare、グラフニューラルネットワークとLLMの再確認により、実トラフィックで4件の悪意あるJavaScriptキャンペーン、計8個のペイロードを検知——うち7個はVirusTotalに全く存在しなかった。記事はそれぞれのゲート、クローキング、バックドアを個別に解剖し、侵害指標と防御者向けの4つの教訓を示す。

日本語
コピー
Cloudflare 博客题图:橙色线条画的店铺插画,左侧是放大镜与告警三角、柱状图,右侧是浏览器窗口里的电路板大脑,两旁是网络节点连线

スキャナが見逃す攻撃:Cloudflare クライアントサイドセキュリティが店舗を守る仕組み

現代の店舗は、表面上はまったく健全に見えても、その裏で悪意ある JavaScript が動いていることがある。アフィリエイト報酬を抜き取り、検索やクリックを乗っ取り、分析データを改ざんし、あるいは次に何を実行すべきかをリモートサーバーに問い合わせる。ページは読み込まれ、商品は表示され、チェックアウトも機能する。その一方でブラウザは、サイト所有者が一度も許可したことのない処理を静かに進めているかもしれない。

これこそ、私たちのクライアントサイドセキュリティ機械学習(ML)モデルが明るみに出す盲点だ。本記事では、4つのキャンペーンにまたがる8つのペイロードを追う。いずれも私たちの Page Shield ML が実環境で発見したものだ。これらの悪意あるペイロードの検出は自動で行われる。人間が関与するのは、システムがフラグを立てた後に各検出結果を確認するときだけだ。後からセキュリティスキャンツールでこれらのキャンペーンを検証したところ、8つのペイロードのうち7つは VirusTotal にまったく存在せず、URLScan もいずれに対しても悪意ある判定を下していなかった。Page Shield ML は、その8つすべてをリアルタイムのトラフィックの中で捉えていた。

たとえば、より広い Lnkr ファミリー自体はセキュリティ研究コミュニティによって何年も前に記録されている。しかし、そのうち特定のペイロード版は URLScan に2年半近く登録され、「分類なし」のままだった。2024年1月の直接スキャンも含めてだ。VirusTotal がより早くこのペイロードを収録していたのはこの1件だけであり、現在はこのスクリプトを悪意ありと判定しているが、公開されている履歴からその判定がいつ最初に下されたのかは分からない。一方 Page Shield ML は、あるオンライン小売業者の店舗上で、リアルタイムのトラフィックの中から、まったく同じバイト列を独自に発見した。より一般に言えば、ハッシュはその背後にあるコードが悪意ありと判定されるよりずっと前から知られている可能性がある。防御がそのラベルを待っているなら、すでに手遅れだ。必要なのは、JavaScript そのものを分解し、大規模に判断できる ML だ。

確かに、ファイルを見つけることと理解することは別だ。厄介なのは、この4つのキャンペーンに共通のシグネチャも、共通の隠蔽手法もないことだ。あるものは、デバイス、国、時刻、参照元、ブラウザの状態が、それが待つ条件と一致したときにだけ目を覚ます。別のものは、クリック不要のアフィリエイトリクエストを不可視の iframe に隠す。さらに別のものはクリックを横取りし、監視を抑え込み、あるいは条件付きでリモートサーバーから追加のコードを読み込む。これらを捕まえるには、部品がどう連携するかを見なければならない。スクリプトがいつ目を覚ますのか、何を隠しているのか、何を横取りするのか、次に何を取りに行くのか。ページを一度調べるだけでは足りない。これらの事例が示すのは、こうしたスクリプトが、適切な被害者が現れるまで静かにしているよう設計されているということだ。だからこそ、継続的なブラウザの可視性が、攻撃を1件捕まえられるか、完全に見逃すかを分ける。

私たちが JavaScript を大規模に検出しラベル付けする方法

本記事の4つのキャンペーンにフラグを立てたのと同じ GNN(グラフニューラルネットワーク)は、以前にも悪意ある npm パッケージ実環境で動いていた Magecart の決済情報窃取ツールを捉えている。この GNN は JavaScript を平坦なテキストとして扱わず、コードをグラフとして推論する。コードのシンボルをつなぐ構文木であり、これによって誰が誰を呼び出すのか、攻撃者が何を埋めようとしているのか、そして何が依然として外部に通信しているのかが見える。この構造のおかげで、既知の URL やバイト単位のシグネチャに頼ることなく、圧縮やリネーム、一部の難読化を越えて疑わしいパターンを識別できる。

GNN が悪意ありとフラグを立てた少数のスクリプト(分析対象トラフィック全体の0.3%未満)は、Workers AI 上の軽量な大規模言語モデル(LLM)に渡され、リアルタイムでセカンドオピニオンを受ける。これにより誤検知をさらに減らしつつ、再現率を高く保つ。LLM が GNN を裏付ければ、顧客にアラートが届く。

最も複雑なスクリプトを大規模に調査するため、私たちは教師(teacher)と呼ぶフロンティアモデルの一群を使っている。自動で査定するアンサンブルだ。この一群には、Workers AI 上で動くオープンウェイトモデルを含め、およそ6つの異なる系統の最先端モデルが集まっている。それぞれを agent として起動し、まったく新しい独立したセッションで同じ疑わしいスクリプトを分析させる。有用な場面では、agent のツール権限によって、制限付きの JavaScript 評価器で小さな断片を分解し、隠された挙動をあぶり出せる。このパイプラインはまもなく Cloudflare Sandbox で拡張し、分離環境でより深い分析を行う予定だ。

フロンティアモデルは、とりわけ入り組んだスクリプトでは意見が割れることがある。私たちはその不一致をノイズではなくシグナルとして扱う。各ラベルは1票となり、重みはそのモデルの Artificial Analysis Intelligence Index のスコアだ。最終的に4つのラベル上の確率分布が出力される。良性、決済情報窃取(magecart)、その他のマルウェア、暗号通貨マイニング。したがって人間のレビュアーが見る必要があるのは、悪意ありとラベル付けされたスクリプトか、明確な3分の2の多数を得られなかったスクリプトだけだ。その後、このラベル分布を GNN の訓練に戻し、ますます微妙な事例を区別できるようにする。このフィードバックループはまだ一部が手動だが、自動化に取りかかっている。

私たちが捉えた4つの悪意ある JavaScript キャンペーン

この4つのキャンペーンが行うことは大きく異なる。報酬の窃取から、店舗がすでに金を払って獲得した顧客の分析データの窃取までさまざまだ。報酬を1件盗むこととクレジットカードを不正利用することは同じではない。同様に、検索を乗っ取ることとパスワードを盗むことも同じではない。ML モデルがそのうち1つの手口しか知らなければ、他の手口には眠ったままだ。だからこそ私たちの Page Shield ML は、あらゆる敵対的行為に敏感でなければならない。以下では各キャンペーンとその仕組みを1つずつ詳しく見ていく。

動作顧客への影響スクリプトの挙動
1)退勤後のアフィリエイト報酬ハイジャックアフィリエイト報酬を奪うモバイル判定と時間帯ゲート、動的なページ監視、クリック横取り、複数日クールダウン
2)クリック不要のアフィリエイト窃取ユーザーがクリックしなくてもアフィリエイト報酬を盗む画面外 iframe、隠しリンクの自動クリックによるフォールバック、余分な IP 照会リクエストと時間帯ゲート、時間単位で切り替わるアフィリエイトリンク
3)かつての検索エンジン破壊者、今や店舗のバックドアユーザーを追跡し、任意のリモート JavaScript を実行するバックドアを開く遺残キーワードの無効化、localStorage によるオプトアウト、テレメトリ、リモートコード読み込み
4)広告流入にだけ効くモバイルクローキングキャンペーンタグ付きのモバイル訪問者に店舗を隠し、広告と分析の差し替えを試み、サポート窓口を隠すホスト・ビューポート・UTM タグによるゲート、325 件の IP 部分文字列リスト、9 つの監視/分析ツールの無効化、ゼロピクセルのトラッキングビーコン

行動 1:退勤後のアフィリエイト報酬ハイジャック

静かな日曜の午後を思い浮かべてほしい。ある顧客がスマートフォンで商品をタップする。スクリプトはそのクリックに素直に従う代わりに、攻撃者が事前に選んだ商品ページやキャンペーンのランディングページを新しいタブで開き、元のタブにはアフィリエイトのリダイレクトを通過させる。店舗はいつもどおりに見える。顧客が購入を完了すれば(その場でも後日でも)、この迂回がアトリビューションを乗っ取り、その売上(ひいては発生する報酬)を、この紹介関係をもたらしていないアカウントに計上させる。

店舗が失うもの

店舗は、この顧客を連れてきていないアカウントに、支払う必要のない報酬を払ってしまうかもしれない。さらに悪いのは、紹介が正規のパートナーによるものだった場合だ。この強制リクエストが誤ったアトリビューションを行い、実際に仕事をしたパートナーから功績と報酬を奪いかねない。損害は報酬一件にとどまらない。アトリビューションを信頼しなくなったパートナーは、その背後にある小売業者も信頼しなくなるかもしれない。

攻撃チェーン

符合条件的移动访客 → 被拦截的商品点击 → 脚本选定的页面在新标签页打开 + 原标签页走攻击者的联盟路径

BLOG-3372 2.png

どのように隠れていたか

関連するスクリプトビルドを5つ確認した。うち2つが稼働中、3つは発見時に停止状態だった。稼働中の各変種は、動き出す前にそれぞれ異なるゲート群を通過する。訪問者のデバイスとローカル時刻、この仕掛けが最近動いたかどうか、特定の商品ボタンが現れたか、そして実際に誰かがそれをクリックしたか——これらを確認するのだ。この規則の迷宮のせいで、その変種固有の条件が満たされない限り、短時間の自動アクセスでは悪意ある挙動は見えない。稼働中のスクリプトは MutationObserver(JavaScript API)を使い、ページの初回読み込み後に動的に現れる商品カードやボタンを監視する。これにより、後から現れる要素へのクリックを横取りできる。HTMLを一度読み込んで止まるクローラーでは、このリダイレクト経路を完全に見逃す可能性がある。

遅めの稼働変種では、スクリプトは条件に合うクリックを横取りし、localStorage に3日間のクールダウンを書き込む(このデバイスでは数日間休眠する)。その後、二重タブの手口を実行する。攻撃者が選んだ商品ページを新しいタブにポップアップして客をつなぎ止める一方、元のタブは攻撃者のアフィリエイト追跡リンクをこっそり辿り、店舗へ戻り、バックグラウンドで攻撃者のアトリビューション cookie を植え付ける。コンソールの隠蔽と自己防衛的なソースチェックが審査を難しくし、クールダウンと狭い時間帯が、通常の買い物の過程でこの悪意ある経路が現れる頻度を制限している。

以下のマスク済み抜粋は、ペイロードが動的な商品カードにフックし、二重タブの迂回を実行する様子を示す。可読性のため、識別子を簡略化し、コードの整形をやり直し、宛先 URL を無害化した。

// Watch for late-rendering product elements and hook clicks
new MutationObserver((_, observer) => {
  const tile = document.querySelector(TARGET_SELECTOR);
  if (!tile) return;
  observer.disconnect();
  tile.addEventListener("click", (e) => {
    // Bail out if cooldown is still active on this device
    const stored = JSON.parse(localStorage.getItem(STORAGE_KEY) || "null");
    if (stored && stored.expires > Date.now()) return;
    e.preventDefault();
    e.stopPropagation();
    localStorage.setItem(
      STORAGE_KEY,
      JSON.stringify({ value: "tracked", expires: Date.now() + COOLDOWN_MS }),
    );
    // Keep shopper engaged in new tab...
    window.open(target.link, "_blank");
    // ... while routing original tab through the attacker's affiliate link
    setTimeout(() => {
      window.location.href = target.redirectUrl;
    }, 200);
  }); // Note: some variants added { once: true } to detach after the first tap
}).observe(document.body, { childList: true, subtree: true });

停止状態のビルドは、スクリプトに手を触れずにこの作戦がどう静かになるかを示している。埋め込まれた設定に status: "paused" が入っているため、クリックハンドラを設置する前に終了する。これらの停止スクリプトは、訪問者ごとの異なるクールダウン設定(3日、4日、5日)を備えている。停止スクリプトの1つはバージョン履歴のコメントまで残しており、この作戦がブラックフライデー後に停止されたことを明記している。

訪問者に到達するため、この作戦はサイトのマーケティングサプライチェーンを借用した。EC サイトが広告キャンペーンや分析データを追跡するために埋め込むサードパーティスクリプトとタグマネージャーである。確認された配信経路の1つは、本来ならごく普通の2つのタグマネージャーを通っていた。Google Tag Manager → 別のタグマネージャー → 悪意あるスクリプト。これがペイロードがブラウザに届く仕組みであり、この2つのタグマネージャーのどちらかが侵害された証拠ではない。

攻撃者は、迅速なマーケットプレイス審査を通過するために、スクリプトをホストするドメインまで偽装した。配信ホストの1つは堂々と隠れていた。adtargett[.]comadtarget[.]com は「t」1文字しか違わず、後者は1998年に登録された広告ドメインである。この偽ドメインは2025年に登録され、我々が確認した時点で、そのトップページは「Adtarget.com - Performance Marketing Agency」と名乗っていた。これがタイポスクワッティングである。実在する広告代理店を模倣することで、このホストは日常的なマーケティングタグに紛れ込み、顧客のクリックを乗っ取り、アフィリエイト支払いリンク経由でリダイレクトする悪意あるペイロードを静かに配信していた。

作戦 2:クリック不要のアフィリエイト窃取

最初の詐欺はクリックを必要としたが、こちらはもっと少なくて済む。顧客は予約ページを開き、商品オプションに留まり、広告には一切触れない。しかし背後で、スクリプトはすでにアフィリエイトリクエストを送信しており、その後の売上が誰かがこの顧客を紹介したかのように見えるかもしれない。実際、スクリプトの条件が満たされると、ペイロードは隠し iframe か、自分自身をクリックするリンクを通じてそのリクエストを送信する。

店舗が失ったもの

影響を受けた旅行業者にとって、この攻撃は顧客獲得の経済性を損ないかねない。正当な予約や購入が、受け取る資格のないアフィリエイトアカウントに計上される可能性がある。コードは隠蔽された自動アフィリエイトリクエストの存在を証明しているが、個々のリクエストが実際にアトリビューションを形成し、アカウントに記録され、コミッションが支払われたかどうかは未観測のままである。

攻撃チェーン

带时间门控的浏览器 → 隐蔽的联盟请求(屏幕外 iframe)→ 一小时的节流 cookie → 被拦下时自动点击隐藏链接兜底

BLOG-3372 3.png

どのように隠れていたか

スクリプトはアフィリエイトへのリクエストを2つの層で隠している。選択的な実行(事前のネットワークゲートと時間単位のスケジューリング)と、隠れた配信(画面外の iframe)だ。1つ目の層で意外なのは、国ラベルが実際の地理的位置と食い違っている点である。選択を決めているのは顧客の位置でも店舗の位置でもない。

まず、スクリプトは公開の IP ベースのジオロケーションサービスを呼び出すが、返ってきたものは顧客の国を含めてすべて無視する。なぜ成功レスポンスを要求しながら返り値を無視するのかは分からない。調査者を惑わすためかもしれないし、単に古いバージョンの名残かもしれない。面白いのは、ジオロケーションリクエストが失敗するとスクリプトが黙って止まることだ。promise チェーンは .catch(() => {}) で終わっている。意図は確認できていないが、失敗したら閉じるというこの挙動は、ネットワークを制限したサンドボックスからスクリプトが逃れるのに役立っている可能性がある。

次に、ペイロードは取得したジオロケーションデータを使わず、TradeDoubler(アフィリエイトマーケティングネットワーク)の設定オブジェクトを3つ埋め込んでいる。ラベルは AUUSUK だ。これらの設定ブロックはコードに直書きされ、それぞれにアフィリエイト URL と開始・終了時刻が入っている。スクリプトは JavaScript で Asia/Kolkata の時刻を計算し、設定された時間枠を確認したうえで、固定の奇数/偶数時間ルールを当てはめて3つのうち1つを選ぶ。どれにも当てはまらなければ、その回のアフィリエイトリクエストはスキップされる。選択は決定論的だ。

スケジューリングとブラウザ状態のチェックが合わさって、時間でゲートされた選択的実行、つまりクローキングが成立している。条件が噛み合わなければアフィリエイトの動作は眠ったままで、一度きりの確認では見逃す。

設定を1つ選ぶと、スクリプトは affiliateClicked_ という名前のローカル cookie を1時間のクールダウンとして書き込み、同じ地域ですぐ再発火しないようにする(これはノイズを避けるためのクライアント側スロットリングであり、アフィリエイトネットワークのアトリビューション cookie ではない)。続いて、オリジンが抑制された画面外の iframe でそのアフィリエイト URL を読み込む。iframe が主な配信経路だが、強引なフォールバックも備えている。iframe がエラーになるか、1〜2秒たっても読み込みが完了しない場合、スクリプトは target 属性のない隠しリンクを作り、プログラムからクリックする。これでユーザーが現在開いているタブが遷移させられる可能性がある。条件に合致した顧客にはすべて普通に見える。広告は一度も目にせず、クリックも不要で、何事もなかったかのようにタブを閉じられる。

スクリプトの難読化は単純だが効果的で、属性名まで1文字ずつ組み立てている。以下のマスク済みの抜粋は、ペイロードが不可視の画面外 iframe をどう作るかを示している。読みやすさのため、主要な識別子は改名し、コードの書式は整え直した。宛先は削除済み。

function loadAttribution(target) {
  const frame = document['c'+'r'+'e'+'a'+'t'+'e'+'E'+'l'+'e'+'m'+'e'+'n'+'t'](
    'i'+'f'+'r'+'a'+'m'+'e'
  );
  frame['s'+'r'+'c'] = target;
  frame['r'+'e'+'f'+'e'+'r'+'r'+'e'+'r'+'P'+'o'+'l'+'i'+'c'+'y'] =
    'n'+'o'+'-'+'r'+'e'+'f'+'e'+'r'+'r'+'e'+'r';
  frame['s'+'t'+'y'+'l'+'e']['c'+'s'+'s'+'T'+'e'+'x'+'t'] =
    'w'+'i'+'d'+'t'+'h'+':'+'1'+'p'+'x'+';'+'h'+'e'+'i'+'g'+'h'+'t'+':'+'1'+'p'+'x'+';'+
    'p'+'o'+'s'+'i'+'t'+'i'+'o'+'n'+':'+'a'+'b'+'s'+'o'+'l'+'u'+'t'+'e'+';'+
    'l'+'e'+'f'+'t'+':'+'-'+'9'+'9'+'9'+'9'+'p'+'x'+';'+
    'v'+'i'+'s'+'i'+'b'+'i'+'l'+'i'+'t'+'y'+':'+'h'+'i'+'d'+'d'+'e'+'n';
  document['b'+'o'+'d'+'y']['a'+'p'+'p'+'e'+'n'+'d'+'C'+'h'+'i'+'l'+'d'](frame);
}

行動 3:かつての検索エンジン荒らしが、今は店舗のバックドアに

何年も前、Lnkr マルウェアファミリーは怪しいブラウザ拡張に潜んでいたことでニュースになった。Google や Bing の検索を横取りし、結果をリダイレクトして広告収入を自分の懐に入れていた。今、攻撃者はこのコードベースを転用し、あるオンライン小売業者のサイトにバックドアを仕込んでいる。

スクリプトが検索エンジンではなく店舗上で動いているため、かつてのリダイレクトの仕掛けは眠ったままだ。今回スクリプトは、テレメトリを攻撃者に送り返すために使われている。さらに危険なのは、攻撃者にリモートの入口を与え、サーバー上のファイルに一切触れることなく、いつでも顧客のブラウザで新しい JavaScript を勝手にダウンロードして実行できるようにしている点だ。拡張の時代から残った技まで備えている。誰かが Google に「virus」や「popup」といった語を入力すると、スクリプトは自分を止める。外から見れば、店舗は変わらず商品を売り続けており、問題が起きている気配はない。

店舗が失ったもの

店舗は「自分の顧客のブラウザでどのコードを動かすか」の制御を失った。攻撃者は訪問者のセッションを密かに追跡し、いつでも店舗のページに任意の JavaScript を送り込んで実行できる直接のバックドアを握っている。

攻撃チェーン

由 HTML 引用的脚本 → 躲避分析人员的门控 → 并行的按主机门控分支(休眠的搜索模块 vs 活跃的后门)→ 任意远程 JavaScript 执行

BLOG-3372 4.png

どのように隠れていたか

タグマネージャー経由で配信される行動とは異なり、このスクリプトは商家の HTML に直接埋め込まれている。最初の侵入経路は特定できない。実際、HTML への直接挿入はたいてい、ストア管理者の認証情報の漏洩、不正なテンプレート変更、あるいは感染したサードパーティ製テーマやプラグインが原因で起きる。

中身を見ると、このスクリプトはモジュール式のツールボックスであり、稼働中のコードと休眠中のコードを同時に抱えている。古いモジュール群(透明なクリックオーバーレイ、検索エンジンのクエリを横取りするもの、拡張ストアのリンクを書き換えるもの、buking[.]combooking[.]com を装うようなドメイン名スクワッティングのリダイレクト)は特定の標的サイトでしか動き出さないため、このストアでは動いていない。いくつかの埋め込みドメイン(sugabit[.]netvotetoda[.]comcdnpps[.]us、そしてテレメトリのエンドポイント hanstrackr[.]com)は、こうした無効化されたモジュールの中に残っている。

このストアで動いているのは、回避、テレメトリ、遠隔操作に特化した枝だ。

  • セキュリティ研究者に対して死んだふりをする。 ブラウザ拡張の時代から受け継がれた回避策で、スクリプトは検索入力欄と URL クエリを監視し、見覚えのあるアドウェア用語を探す。セキュリティ関連のキーワードを1つ見つけると、その訪問の間はスクリプトが停止する。2つ以上見つかると localStorage に永続的なオプトアウト記録を書き込み、その分析者のマシン上でスクリプトを永久に沈黙させ、繰り返しテストしても何も見つからなくする。もともとは検索エンジン上で分析者をやり過ごすために書かれたものだが、こちらの確認できる限り、このチェックは Google 検索の URL にハードコードされていて、この商家のストアページでは休眠したままだ。
  • 動的な遠隔コード実行。 スクリプトはストアを変更しなくても自分の挙動を変えられる。ハードコードされたドメイン(scrprime[.]comyouronlinesearches[.]comjullyambery[.]net)は以前の捕捉と完全に一致するが、これらのエンドポイントが何を返すかは攻撃者が完全に決められる。スクリプトは訪問者のテレメトリを送り返し、それらのサーバーに新しい指示を求め、新しい JavaScript を顧客のブラウザに直接引き込める。事実上、これは攻撃者にストアページ上で任意のコードを実行できる生きたバックドアを与えている。実際にどんな第二段階のペイロードが配信されたかは特定できない。

要するに、サイトの静的スナップショットを見ても正常なストアしか見えない。その下にある状態チェック、対分析の罠、遠隔読み込みの分岐が、このバックドアを露呈させる。

行動 4:配信されたトラフィックにだけ効くモバイルクローキング

ストアはすでに金を払って、この訪問者をモバイル広告やキャンペーンから連れてきている。悪意あるスクリプトは今回の訪問を素通しさせ、それから商家の可視性を断ち切る。分析データは真っ暗になり、リアルタイムのカスタマーチャットは消え、不正な観測者が、ストアが金を払って手に入れたばかりのこのセッションのテレメトリを記録し始める。

裏側では、ペイロードは訪問が綿密に設計された条件一式に一致しない限り動かない。正確な標的ストア、狭いモバイル画面、そして最初の2ページへのアクセスに特定のキャンペーンタグが付いていること。ノート PC、企業ネットワーク、クラウド事業者、VPN では休眠するので、ページをデバッグしに行きそうなエンジニアには決して発火が見えない。スクリプトはさらに、米国の特定の都市と地域でも休眠する。自動スキャナやセキュリティ分析者をかわすため、手作業で維持された325件の IP 文字列の拒否リストが背後にある。ここまで来て初めて、スクリプトはストアの監視を外し、広告と分析の識別情報を差し替え、家に電話をかける。別のデバイスやネットワークからもう一度見ても、決して発火しない。その間もストアは売り続けている。

ストアが失ったもの

直接消費者向けの小売業者にとって、このマルウェアが狙うのは、ストアが有料検索やキャンペーン(ppccpcsmspaid)で金を払って獲得した価値の高いトラフィックだ。これらの顧客は今でも注文できる。だがストアは3つの明確な脅威に直面している。広告アトリビューションの横取りと払う必要のないパブリッシャー報酬、9つの可観測性ツールにおける重要なセッション分析データの喪失、そしてヘルプチャットと問い合わせフォームの抑止(顧客が質問したり異常を報告したりできなくなる)。サンドボックスのブラウザ環境での動的分析により、差し替え用の分析スクリプトが実際に読み込まれ、追跡ビーコン(訪問者の活動を記録するための不可視のネットワークリクエスト)を発火させることが確認されたが、攻撃者が実際にセッションテレメトリの取得や広告収入の横領に成功したかは依然として確認されていない。

攻撃チェーン

带活动标签的移动端到达 → 多层斗篷与网络门控 → 监控被破坏 → 广告、分析与客服控件被改写

BLOG-3372 5.png

どうやって隠れていたか

店舗のマーケティングサプライチェーンに紛れ込むため、攻撃者は sdk-amazonaws[.]com からペイロードを配信した。2024年に登録された偽装ドメインで、公式の Amazon Web Services ドメイン(amazonaws.com、2005年登録)とは何の関係もない。さらに騙しの手を進め、攻撃者はこのドメインに、ある人気ECマーケティングプラットフォームを模したサブドメイン接頭辞まで付けている。信頼されたブランドを二重に重ねたこのドメインスクワッティングは、ざっとしたタグ検査をすり抜けることを狙って設計された、説得力のある偽装を作り出していた。Amazon Web Services も、なりすまされたマーケティングプラットフォームも、この攻撃には関与しておらず、侵害も受けていない。

ブラウザに読み込まれると、スクリプトは本命のペイロードを発火させる前に、極めて密度の高いクローキングのゲートを順に実行する。

  • 対象ホストと閲覧コンテキスト。 スクリプトは window.location.hostname が、それが狙って作られた特定の加盟店ホストと一致することを確認し(それ以外では即座に終了する)、現在のウィンドウがトップレベルであること(埋め込まれた iframe ではないこと)を確かめ、パスに /challenge が含まれていないことを検査する。さらに、追跡マーカー cookie(_cart_dr_logo_alt)がブラウザにまだ存在しないことも確認する。
  • デバイスとキャンペーンのフィルタリング。 訪問者のビューポート幅は 477 ピクセル未満(手持ちのスマートフォン)でなければならない。加えて、訪問者はファーストタッチ(訪問者の最初の流入元)キャンペーン経由で到達していなければならず、そのキャンペーンには6つの特定の UTM medium(Urchin Tracking Module、マーケティングキャンペーンを追跡する標準的な URL タグ)のいずれかが付いている必要がある:ppccpcsmspaidflowcampaign。しかも、それがセッション内の1ページ目か2ページ目でなければならない。興味深いことに、コードには名目上の非 UTM 経路が1つあるが、これはセッションのページ数が -1 より大きく、かつ -2 より小さいことを要求する(数学的に不可能な条件で、この分岐は完全に到達不能になっている)。これもまた別のミスディレクションかもしれないし、コード変更の名残かもしれない。
  • 決して通らない「ランダム」ゲート。 コードには確率的なスロットリングに見える判定(Math.random() <= threshold)があり、実行が断続的に見えるようになっている。だが、難読化を解除した算術を解くと、このしきい値はちょうど1に簡約される。JavaScript の Math.random() が返す値は常に厳密に1未満なので、このゲートは常に真になる。到達不能な非アクティブ分岐と同様、これは実際には何も決定しない条件だ。残り物のスロットリングかもしれないし、この難読化された算術を読む者を惑わすための意図的な偽装かもしれない。いずれにせよ、捕捉されたペイロードがこれを使って条件を満たす訪問者をスキップしたことは一度もない。
  • サードパーティの IP インテリジェンス。 スクリプトは埋め込まれたキーを使って外部のサードパーティ IP インテリジェンス API に問い合わせる。要求するのは米国のモバイル消費者向け接続で、応答が企業ネットワーク、ホスティング施設、クラウド事業者、bogon、Tor 出口ノード、VPN、プロキシ、リレー、あるいは一般的な脅威指標を示した場合は即座に断念する。
  • 地理的な除外。 ペイロードは特定の地域(US-NYUS-CAUS-NHDD)や、San Francisco、Plymouth、Compton、Hopkinton、Lafayette といった都市からの訪問者に対しては起動しない。
  • 325件の IP 部分文字列トラップ。 スクリプトは訪問者の IP を、埋め込まれた325件の完全な IPv4 アドレス文字列からなる拒否リストと照合する。重複を除くと、これらは249の異なる3オクテット接頭辞の下にある313個の一意なアドレスを表す。著者は構造化された CIDR(クラスレスドメイン間ルーティング)サブネットマッチングを行わず、訪問者の IPv4 アドレスの最後のオクテットを剥ぎ取って、生の部分文字列検索を1回走らせる:!denylistString.includes(visitorPrefix)

簡潔な擬似コードで表すと、この多段のメイン起動ファネルはこうなっている:

// 1. Context, device, and campaign gates
let eligible = isTopWindow && host === EXPECTED_HOST && !path.includes("/challenge");
eligible &&= !hasCookie("_cart_dr") && !hasCookie("_logo_alt");
eligible &&= viewportWidth < 477 && [1, 2].includes(sessionPage);
eligible &&= ["ppc", "cpc", "sms", "paid", "flow", "campaign"].includes(utmMedium);
eligible &&= Math.random() <= 1; // Apparent random gate always resolves to true
// 2. IP intelligence & geographic gates (fetching external API)
eligible &&= ipInfo.country === "US" && ipInfo.isMobile && !ipInfo.isBusiness;
eligible &&= !ipInfo.isCloud && !ipInfo.isProxy && !ipInfo.isVpn && !ipInfo.isTor && !ipInfo.isThreat;
eligible &&= !["US-NY", "US-CA", "US-NHDD"].includes(ipInfo.region);
eligible &&= !EXCLUDED_CITIES.includes(ipInfo.city);
// 3. 325-entry IP prefix check (raw substring matching)
let clientPrefix = ipInfo.ip.slice(0, ipInfo.ip.lastIndexOf("."));
eligible &&= !DENYLIST_STRING.includes(clientPrefix);
if (!eligible) return; // Cloak passes only for qualifying consumer mobile sessions

可観測性の破壊とアイデンティティの乗っ取り:

すべてのメインゲートを通過した後にだけ、スクリプトはペイロードを実行する。

  • 監視ツールに目隠しをする。 DOM を検索し、9つの異なる可観測性・分析サービスの script タグを削除する:Lucky Orange、Segment、Optimizely、New Relic、Bugsnag、LogRocket、Hotjar、Microsoft Clarity、そして店舗の Google Tag Manager コンテナ(GTM-)。残ったインラインスクリプト内では、これらのツールへの参照文字列を未定義の偽識別子(hji0)に置き換え、呼び出しを黙って失敗させることで、店舗のエラー報告と監視に目隠しをしようとする。
  • カスタマーサポートを抑え込む。 CSS を注入して要素を削除し、サポートチャットと問い合わせフォームのコンテナを隠し、顧客と店舗サポートの直接の窓口を断つ。
  • 広告と分析のアイデンティティを差し替える。 Google Ads のグローバル変数(google_ad_modificationsadsbygoogle)を消し、既存の広告スロット(ca-pub-)を解体し、差し替え用のパブリッシャー ID(ca-pub-)で Google Ads を読み込む。続いて、新たな Microsoft Clarity のセッションリプレイスクリプトを、不正な差し替えプロジェクト ID で設定して注入する。

より単純な独立ビーコンと、あの600日マーカー:

入念に作り込まれたメインのクローキングとは対照的に、ペイロードにはセカンダリビーコンの分岐(訪問を確認するために外部サーバーへ静かに ping を送る独立したルーチン)も含まれており、これらはビューポート、ホスト名、キャンペーン、地理、IP の各ゲートを完全に迂回する。訪問者がすでに2ページ目以降にいる場合、スクリプトは永続 cookie(_cart_dr=1)をちょうど600日間(51,840,000,000ミリ秒)有効で書き込み、maper[.]info 上のリモートテレメトリエンドポイントへ、不可視のゼロピクセル画像リクエスト(ブラウザがここまで来たことを記録する追跡ビーコン)を1回送信する。

もう一つの独立した分岐が別のマーカー(_logo_alt)を調べ、2つ目のテレメトリビーコン(.png)を発火させる。この cookie はスクリプトが探しには行くが自分では決して書き込まないもので、おそらく配套スクリプトが仕込んだものだ。これにより攻撃者は、店舗全体の全訪問者の基本トラフィック(IP と User-Agent はエンドポイントに記録される)を数える、単純で永続的なヒットカウンターを手に入れる。同時に、リスクの高い広告ハイジャックルーチンをモバイルクローキングの背後(価値の高い有料トラフィック)に厳重に隠している。これは、可視の効果を1つだけ分析しても多目的ペイロードの到達範囲の全体像は見えない、ということでもある。

侵害指標(IOC)

これらの指標を公開するのは、セキュリティチームと研究者が自分の環境でこれらの作戦を検知し追跡できるようにするためだ。すべての指標は、捕捉されたペイロードとそのネットワーク接続から直接取得した。掲載した URL は無害化してある。一部の指標は伏せたり一般化したりしている。公開すると影響を受けた組織の身元を意図せず漏らすおそれがあるためだ。掲載したドメインは、これらの攻撃中に配信、リダイレクト、テレメトリの連鎖に関与しているのが観測されたインフラを反映している。掲載されているからといって、共有サービスやホスティングプロバイダ自体が悪意あるものというわけではない。

行動指標種類と役割
1)退勤後のアフィリエイト報酬ハイジャッカーadtargett[.]comスクリプト配信とアフィリエイトリダイレクトのドメインスクワッティング
1)退勤後のアフィリエイト報酬ハイジャッカーgdataroute[.]com攻撃チェーンで観測されたアフィリエイトリダイレクトの短縮リンクサービス
3)かつての検索エンジン破壊者、今や店舗のバックドアscrprime[.]comブラウザハイジャックスクリプトの配信ドメイン
3)かつての検索エンジン破壊者、今や店舗のバックドアsearchvalidation[.]com検索ハイジャックとトラフィックリダイレクトのドメイン
3)かつての検索エンジン破壊者、今や店舗のバックドアsugabit[.]net強制検索リダイレクトのドメイン
3)かつての検索エンジン破壊者、今や店舗のバックドアyouronlinesearches[.]com条件付きリモートスクリプト配信ドメイン
3)かつての検索エンジン破壊者、今や店舗のバックドアhublosk[.]comリモートスクリプト配信ドメイン
3)かつての検索エンジン破壊者、今や店舗のバックドアjullyambery[.]netリモート JavaScript API と命令のドメイン
3)かつての検索エンジン破壊者、今や店舗のバックドアvotetoda[.]comインジェクションペイロードの配信ドメイン
3)かつての検索エンジン破壊者、今や店舗のバックドアhanstrackr[.]com隠された訪問者テレメトリのドメイン
3)かつての検索エンジン破壊者、今や店舗のバックドアadrs[.]me攻撃チェーンで観測されたスクワットトラフィックのリダイレクトサービス
3)かつての検索エンジン破壊者、今や店舗のバックドアyouradexchange[.]com攻撃チェーンで観測された収益化リダイレクトサービス
3)かつての検索エンジン破壊者、今や店舗のバックドアcdnpps[.]usインジェクション広告枠の配信ドメイン
4)配信トラフィックにだけ効くモバイルクローキングsdk-amazonaws[.]comブランドの信頼を悪用した偽装スクリプト配信ドメイン
4)配信トラフィックにだけ効くモバイルクローキングmaper[.]info条件付き訪問者テレメトリビーコンのドメイン

防御側のための4つの教訓

まとめて見ると、これらの作戦はエスカレートしていく物語を語っている。攻撃者は標的、配信経路、偽装を変えてきたが、ブラウザは依然として彼らのロジックを実行しなければならない。際立つ教訓は4つある。

振る舞いはシグネチャに勝る。 これらの作戦が狙う収益化と操作の形はそれぞれ違うが、どのペイロードもブラウザの中で行動しなければならない。イベントを監視し、状態を調べ、ページを改変し、タスクをスケジュールし、ネットワークリクエストを送る、あるいは次の段階を読み込む。まさにこれが構造化分析の探すものだ。URL、シグネチャ、標的が変わっても、敵対的ペイロードが必ず持ち歩くロジックである。

選択的実行は攻撃の一部であり、脚注ではない。 デバイス、時間、地理、参照元、セッション、ネットワーク、クールダウンのゲートはどれも、一度だけアクセスして静的なスナップショットを撮るクローラーを打ち負かす。継続的な可視性が重要なのは、ある攻撃が特定のブラウザの、ある状態の、ある瞬間にしか現れないことがあるからだ。

難読化は分析コストを上げるが、これらの事例では検知を止められなかった。 自己防衛のループ、コンソールの抑止、デバッガトラップ、ローテーションする文字列テーブル、デッドブランチは、いずれも分析を複雑にする。それでも Page Shield ML はこれらの障害の下で4つの作戦すべてを見つけ出した。高速な内部モデルが疑わしいコードを大規模に浮かび上がらせ、フロンティアモデルが最も難しい事例を調査する。両者の不一致が最も厄介な難読化とロジックを浮き彫りにし、焦点を絞る助けになる。

文脈が全体像を完成させる。 単独では平凡に見えるコードも、防御側が静的解析と動的な文脈をつなげれば、その悪意ある役割を露わにする。どうやって到達したのか、どのブラウザ状態がそれを起動したのか、どの接続を開いたのか、そして実行時に実際に何をしたのか。

クライアントサイド実行に対する継続的な可視性

これら4つの行動はそれぞれ異なる層のミスリードに依存しているが、すべて同じ制約を受けている。JavaScriptがブラウザ上で実行される必要がある。公開スキャナーや静的クロールでは、ゲートされた挙動を見逃す。継続的に観察すれば、実際の訪問者がページを操作したときにコードが何をしているのかを突き止められる。

Cloudflareのクライアントサイドセキュリティは、すべてのプランでこの可視性を提供する。セキュリティ設定で継続的なスクリプト監視を有効にすれば、ストア上のファーストパーティおよびサードパーティのスクリプトを追跡できる。悪意あるスクリプトの自動検出とアラートはクライアントサイドセキュリティ アドバンストで提供される。スクリプトのアクティビティはCloudflareダッシュボードで直接確認でき、検出結果もそこで管理できる。

出典: Cloudflare Blog← ホームへ戻る