
現在、セキュリティチームが追跡しているAiTM(Adversary-in-the-Middle)フィッシング活動の多くは、ごく少数の公開ツールキットを利用したものです。Evilginx、Modlishka、Muraenaは、インシデントレポートで繰り返し確認されています。その主な理由は、高度な開発スキルを持たない攻撃者でも、独自のコードを一行も書くことなく、実際に動作するリバースプロキシ型のフィッシングサイトを構築できるためです。これらのツールキットが広く利用されているのには理由があります。無料で利用でき、ドキュメントも充実しているうえ、正規のサービスにログインしていると思っている被害者から、認証情報とセッションクッキーの両方を窃取するのに十分な機能を備えているためです。
OSKeySetupは、私たちが確認した独自構築のAiTMツールで、ボット検証用のチェックボックスに至るまで、すべて攻撃者によって独自に構築されていました。これにより、他の既知のツールに見られるインジケーターがOSKeySetupには含まれないため、検出がより困難になります。
この点こそが、この事例を詳しく取り上げる価値がある理由です。以下のセクションでは、ドメインがどのように設定されていたのか、ランディングページに実装された偽のボット検証がどのように機能するのか、Microsoftの正規のサインインフローを模倣するために、ログインおよびOTP認証フローがどのように再構築されていたのかを順に解説します。さらに、フォームフィールド内に仕込まれていた特徴的なキーロギングの仕組み、サイトが再訪問者を記憶する仕組みに見られる特徴的な挙動についても取り上げます。最後に、同一の攻撃者に関連付けることができたその他のサブドメインとインジケーターを一覧で紹介します。
ドメイン
ドメインを確認すると、IPアドレスが31.42.184.213であることが確認できます。このサイトには、ZeroSSLが発行したSSL証明書が使用されています。
VirusTotalでは、現在このドメインを悪意のあるものとして検出しているベンダーは90社中2社にとどまっており、検出率はかなり低い状況です。ただし、この数字だけでは実態を正確に捉えられない可能性があります。一方、関連するサブドメインをたどって調査すると、そのうち30以上がすでにさまざまなセキュリティエンジンによって悪意のあるものとして判定されています。このことは、このキャンペーンが実際にどの程度活発であるかを示す、より有力な指標となります。
フィッシングキャンペーン
ボット検証ページ
フィッシングのフローは、ボット検証から始まります。訪問者には、見慣れた「私はロボットではありません」というチェックボックスが表示されます。
一般的な手法では、攻撃者はフィッシングページの前段にCDNとCloudflare Turnstileのような正規のボット検証サービスを配置します。これに対し、この攻撃者は、ボット検証を模した独自のウィジェットをフィッシングページのHTMLに直接組み込んでいました。ここでは第三者サービスによる検証は一切行われていません。正規のボット検証と同じような見た目や操作感になるよう設計された、フロントエンド上の見せかけの仕組みにすぎません。
ログインページ
偽のボット検証が完了すると、ページは「/api/visitors/session」を介してセッションを開始し、サーバーから次の指示を取得するため、繰り返しポーリングするハートビートを開始します。サーバーからのレスポンスに、値が「signin」に設定された「panel」フィールドが含まれていると、ページは待機画面から偽のログインフォームへ切り替わります。
このログインページは、Microsoftの正規のサインイン画面を忠実に再現したもので、既存のテンプレートを流用するのではなく、攻撃者によってすべて独自に構築されています。これは、実際のMicrosoftアカウントに対するAiTM(Adversary-in-the-Middle)攻撃を成立させるため、正規のサインイン画面であるかのように見せ続けることを目的としています。
正しい形式に見えるメールアドレスが入力されると、ページはそのメールアドレスを含むリクエストをバックエンドに送信します。そのレスポンスの指示に従い、ページは次にパスワード入力フィールドを表示します。
パスワード入力ページ
前のステップと同様に、パスワードに関するリクエストに対するサーバーのレスポンスには、次に表示するパネルを指定する指示が含まれています。この場合は「password」が指定されています。
前のステップと同様に、パスワード入力フィールドのHTML要素はあらかじめページのコード内に含まれており、サーバーからクライアントに表示するよう指示されるまでは非表示になっています。
パスワード自体は、現在のパネル名および入力された値とともに「/api/visitors/event」へ送信されます。以降のフロー全体でも、同じイベント処理パイプラインが使用されます。
認証情報が入力されると、「サインインしています」という読み込み画面が表示されます。この画面も既存のキットから流用されたものではなく、攻撃者によってすべて独自に実装されています。
内部では、フィッシングサイトのバックエンドがMicrosoftのGetCredentialTypeエンドポイント(https://login.microsoftonline.com/{tenantid}/GetCredentialType)を呼び出しているとみられます。このエンドポイントはメールアドレスを受け取り、そのアカウントが実際に存在するかどうかに応じて異なる「IfExistsResult」値を返します。これにより、フィッシングサイトのバックエンドは、処理を続行する前に、実在する有効なユーザー名であるかを確認できます。この点は、特筆すべき点です。攻撃者は、どのメールアドレスが有効かを推測したりハードコードしたりするのではなく、Microsoftの正規インフラストラクチャを利用して、攻撃対象のメールアドレスが有効かどうかをリアルタイムで検証しています。
OTP
ログインに成功した後に表示されるワンタイムパスコード(OTP)の入力画面もすべて独自に構築されており、認証情報の入力に続いて、そのままOTP認証へ移行します。このフィッシングキットは、Microsoftアカウントで一般的に使用される3つの認証方法(メールで送信されるコード、SMSで送信されるコード、Authenticatorアプリへのプッシュ通知)をすべて想定しています。さらに、Microsoftの正規の「サインインの状態を維持しますか?」という確認画面を、アイコンに至るまで再現しています。
イベントベースのWebキーロガー
この仕組みを詳しく調査する中で、特に興味深かった点の一つが、「/api/visitors/event」に大量のリクエストが送信されていたことです。さらに詳しく確認したところ、ログイン、パスワード、OTPのいずれかの入力フィールドの値が変更されるたびに、新しいリクエストが送信されていることが分かりました。
調査の結果、これは攻撃者が独自に実装したキーロガーであることが分かりました。この仕組みが採用されている背景には、巧妙な狙いがあります。実際に、攻撃対象者が操作の途中で不審に感じるケースがあります。たとえば、本物のパスワードを入力した後に思い直し、そのパスワードを削除して偽のパスワードを入力してからサインインボタンを押すことがあります。そうすることで、本物の認証情報が攻撃者に渡るのを防げると考えるためです。しかし、このキーロガーは、フォーム送信時に入力内容を取得するのではなく、キー入力のたびに入力内容を取得し、即座に送信します。そのため、最終的にどのような値が送信されても、攻撃者は攻撃対象者が最初に入力した本物のパスワードを取得できます。
ここで、一点訂正しておく必要があります。ページ内の命名からは、この処理がkeydownイベントリスナーをトリガーとして実行されているように見えます。しかし、実際のコードを確認すると、各入力フィールドに設定されたinputイベントリスナーによって入力内容が取得されています。実際の挙動はどちらの場合も同じで、入力フィールドの値が変更されるとハンドラーが実行されます。ただし、厳密には、リクエストのトリガーとなっているのはキー入力そのものではなく、入力フィールドの値の変更です。このハンドラーは「reportEvent」という関数を呼び出し、この関数が実際にバックエンドへリクエストを送信します。
reportEvent 関数は、ブラウザから送信される前に同じデータを訪問者自身のローカルストレージにも書き込み、その後
visitorPost
ヘルパーを使ってバックエンドへ送信します。
通常のHTTPリクエストに加えて、ここではsocketオブジェクトが存在する点にも注目する必要があります。このことから、このフィッシングキットの攻撃者側には、WebSocketを利用したリアルタイムダッシュボードが用意されている可能性が高いと考えられます。攻撃者は、被害者が入力するのに合わせて、各入力フィールドの値やパネルの切り替わりをリアルタイムで確認でき、後からログを確認するだけの仕組みではないと考えられます。
フィッシング被害者のローカルストレージ
この攻撃で確認された興味深い挙動の一つは、最初のボット検証を一度通過すると、同じブラウザではページを再読み込みしても、その後ボット検証が再度求められないことです。当初、この挙動は少し不自然に思われました。ボット検証ウィジェットは、再訪問者を記憶していても不思議ではない第三者サービスから読み込まれているのではなく、ページ内に直接ハードコードされているためです。さらに、IPアドレスをまったく別のものに変更してテストしましたが、結果はまったく同じで、ボット検証が再度表示されることはありませんでした。
この挙動は、「writeSavedSession」関数によるものであることが分かりました。この関数は、「storageKey()」関数によって生成されたキーを使用して、セッションデータをブラウザのローカルストレージに保存します。以降のリクエストでは、ページが「readSavedSession()」を介して同じ保存済みデータを読み込み、ユーザーが前回どの段階まで進んでいたかを正確に特定します。これにより、同じブラウザから再度アクセスした場合は、ボット検証を完全にスキップできる仕組みになっています。
この方法で保存されるデータも、決して軽視できるものではありません。保存されるデータには、ユーザーが最初に入力したメールアドレスとパスワードそのものが含まれており、ブラウザプロファイルが存在する限り、ブラウザのローカルストレージに平文のまま保存され続けます。
その他の関連する可能性があるキャンペーン
crt.shで証明書透明性ログを検索したところ、この単一のルートドメインのサブドメインに対して発行された700件以上の証明書が確認されました。この事実だけでも、これが単発のテストではなく、大規模かつ継続的に運用されているキャンペーンであることを強く示しています。すべてのサブドメインのDNS Aレコードは、IPアドレス「31.42.184.213」を指しています。このIPアドレスは、フィッシングサイトがホストされていたものと同一です。
これらのサブドメインからいくつかを無作為に選んでアクセスしたところ、すべてでまったく同じコードが実行されていることを確認しました。このことから、これらのサブドメインは、異なる標的を狙った別々のブランド名のキャンペーン、または攻撃者がフィッシングキットの構築や改良に使用していたテスト環境やステージング環境のいずれかである可能性があります。また、サブドメイン名の中には、実際の標的を想定したものとは考えにくい、明らかに使い捨てや冗談と思われる名前も複数確認されました。この点からも、このリストの少なくとも一部は、実際の攻撃を目的としたものではなく、内部テストに使用されていた可能性があると考えられます。
まとめ
OsKeySetupは、確認されるAiTMフィッシング攻撃のすべてが、Evilginxやその類似ツールを使用しているわけではないことを改めて示す事例です。このツールの作成者は、独自のボット検証画面、Microsoftの正規のサインインおよびOTP認証フローをピクセル単位で忠実に再現した画面、訪問者ごとの独自のセッションおよびイベント処理パイプラインを構築しています。さらに、フォームが送信されるのを待つのではなく、キー入力のたびにその内容を取得する独自のキーロガーも実装しています。これらの仕組みはいずれも、防御側がフィンガープリントによって容易に識別し、ツール名に基づいてブロックできるような公開ツールキットには依存していません。
だからといって、この攻撃活動を検出できないわけではありません。証明書透明性データだけでも、単一のルートドメインに関連付けられた700以上のサブドメインを確認できました。また、そのうち相当数のサブドメインには、明らかに場当たり的でくだけた名前が付けられており、実際の標的に意図的に見せるためのものというより、内部テスト用で使用されていたことをうかがわせます。このような運用上の甘さが、最終的にこうしたキャンペーンの検出につながることは少なくありません。本物らしく作られたフィッシングページ自体ではなく、その周辺のインフラストラクチャが検出の手掛かりとなります。
防御側にとって、この事例から得られる実践的なポイントがいくつかあります。第一に、自社ブランド名や、そのスペルをわずかに変えた類似ドメインを対象とする証明書透明性(CT)の監視は、このような攻撃の検出に実際に有効です。この攻撃者は標的ごとに新しいサブドメインを作成していたため、その痕跡が公開CTログに継続的に蓄積されていました。しかも、その多くは一般的なブロックリストに掲載されるよりもかなり前からCTログで確認できました。第二に、Cloudflare、hCaptcha、Googleなど、既知の第三者ドメインから読み込まれていることが確認できない「人間であることを確認する」ウィジェットについては、注意深く確認する必要があります。攻撃者が自らホストする偽の検証ウィジェットは、もはや単なる理論上の手法ではなく、実際に使用可能な手法であることが明らかだからです。最後に、そしておそらく最も重要なのは、この攻撃チェーン全体の目的が、被害者のユーザー名、パスワード、ワンタイムコードをリアルタイムで攻撃者へ中継することにある点です。パスキーやハードウェアセキュリティキーなどのフィッシング耐性を備えた認証方式は、この種の中継型攻撃の影響を同じようには受けません。これらの認証方式が利用する暗号学的チャレンジは、正規のオリジンに紐付けられているためです。そのため、正規サイトに酷似したドメインのフロントエンドがどれほど精巧に作られていても、そのドメインを介して暗号学的チャレンジを再送して認証を成立させることはできません。
















