WhatsAppのクリックジャッキング脆弱性によりフィッシング攻撃が可能に
(00xbyte.github.io)- WhatsAppのメッセージで正規サイトのように見えるリンクとプレビューを表示しながら、実際のクリックは攻撃者のサイトへ送るフィッシング脆弱性が発見された
- 原因は、メッセージ本文のリンクとプレビューデータが別々に送信され、
matchedTextを削除することでプレビューの不一致を作れる構造にある U+202ERight-To-Left Override文字はURLの表示方向を反転させ、実際のドメインを正規ドメインのように見せることができる- 攻撃者はなりすまし対象のミラードメインを用意したうえで、元サイトのプレビューを維持し、
text値だけを変えて被害者を欺ける - MetaはURL正規化ロジックを動的に調整できると回答しており、ユーザーはリンクをクリックする前にコピーして実際のアドレスを確認する必要がある
WhatsAppのリンクプレビューと実際のリンクが分離する箇所
- 研究者は、WhatsAppメッセージの受信者がリンクプレビューをレンダリングする際にHTTPリクエストを発生させるか確認するため、
webhook.siteのリンクを友人に送信した - HTTPリクエストは送信者側で一度だけ発生し、受信者が別途リンクをレンダリングしていないことが確認された
- この挙動から、WhatsAppメッセージにはリンクとプレビュー情報が一緒に含まれて送信されると見て、両者を別々の内容にできるか実験した
Issue #1: リンクプレビューの不一致
- WhatsApp Webのメッセージをプロキシで直接変更しようとしたが、WhatsAppのE2EEにより、Burp Suiteのようなツールでは単純な改ざんが難しかった
- 代わりに、メッセージが暗号化されてWebSocketで送信される直前のJavaScriptにブレークポイントを設定し、メッセージオブジェクトを確認した
- メッセージオブジェクトにはリンク本文とプレビュー情報が別々のプロパティとして存在していた
text: メッセージ本文canonicalURL: プレビュー下部に表示されるドメインmatchedText:canonicalURLと比較される値とみられ、この値がtext内にも現れるかテストされる
instagram.com用のメッセージオブジェクトでtextをgoogle.comに変えると、プレビューが消え、Googleリンクだけが残ったmatchedTextプロパティを削除すると、実際のリンクとプレビューが異なる不一致メッセージを作成できた
Issue #2: U+202Eによるリンク表示の偽装
- 実際のリンク本文が露出しないよう、Unicode文字がテキスト表示を変えるかファジングした
U+202EはRight-To-Left Override文字で、テキストをユーザーに逆順表示させる- 単に
U+202Eだけを使うとリンクの見た目が不自然でクリックされる可能性が低そうだったため、正規URLのように見えるよう反転した文字列を構成する必要があった
ミラーURLの構成方法
- 目標は、反転したときに
https://instagram.comのように見えるURLを作ることだった - 単純な逆順文字列は
moc.margatsni//:sttphになるが、.margatsniのようなTLDは登録できない - 解決策は、実際に登録可能なTLDをサブドメインのように見せて使う方法である
- 例としてオランダのTLD
.nlを使うと、ln.instagram.comのように見える文字列を作れる
- 例としてオランダのTLD
- URLが
https://で始まるように見える必要があるため、有効なパスである//:sptthを後ろに付ける - 結果として、
https://moc.margatsni.nl//:sptthはU+202Eと組み合わせると、https://ln.instagram.com//:sptthのように見える可能性がある - 研究者はこの手法を2K2Eと呼んでいる
攻撃の流れ
- 攻撃者は、なりすまそうとするサイトのミラードメインを購入する
- 例:
ln.instagram.comのように見せるには、moc.margatsni.nlを購入する
- 例:
- まず元ドメインのリンクを含むメッセージを作り、そのサイトのプレビューを取得する
- 例のオブジェクトでは、
text、matchedText、canonicalUrlがすべてhttps://instagram.com/になっている description、title、jpegThumbnail、thumbnailDirectPathなどのプレビュー関連の値も含まれる
- 例のオブジェクトでは、
- その後、
matchedTextを削除し、text値を\u202ehttps://moc.margatsni.nl//:sptthの形式に変更する - 最終メッセージはInstagramのプレビューを表示するが、クリックすると攻撃者が用意したドメインへ移動する可能性がある
Metaの対応と他プラットフォームとの比較
- Metaは、複数のプラットフォームと環境をサポートしているため、プラットフォームごとのURL正規化方式がサーバー側ロジックと異なる場合があると回答した
- 実際にスパムや悪用が発生した場合、URL正規化ロジックを動的に調整できるシステムがあると明らかにした
- 研究者は、Metaがこのセキュリティ問題を積極的に解決しようとしているというより、システムがスパムとして検知した場合にのみ対応しようとしているように見えると評価した
- X、TikTok、Pinterestは
U+202E文字に対するサニタイズ処理を行っており、WhatsAppとは異なる
ユーザーが確認できる緩和策
- WhatsAppのリンクは、表示された見た目だけでは信頼しにくい
- 2K2Eフィッシングを避けるには、リンクをクリックする前にコピーし、クリップボードのプレビューで実際のアドレスを確認する必要がある
- クリップボードのプレビューは、
U+202E文字がサニタイズされた状態のリンクアドレスを表示できる - 研究者はその後、適切なサニタイズ処理がなく2K2Eに脆弱な他のサービスも発見した
1件のコメント
Hacker Newsのコメント
かなり巧妙に機能を悪用した組み合わせではあるが、全体としてのセキュリティ上の影響は低いと見るだろう
最良のケースでも、受信者にブラウザでリンクを開かせる程度なので、警察や情報機関のような攻撃者でもない限り、通常は端末上の未パッチのソフトウェアを悪用するような後続攻撃が必要になる
技術的に正確に言えば、これをクリックジャッキングと呼ぶのは難しい。クリックジャッキングは通常、見えないHTMLフレームを別のコンテンツの上に重ねる非常に特定の手法を指す
https://owasp.org/www-community/attacks/Clickjacking
https://portswigger.net/web-security/clickjacking
みんなUTFの右から左への文字ばかりに注目しているが、Metaは少なくとも、プレビューURLがメッセージ内のURLと異なりうるという問題を認めるべきだった
短縮URLを展開するための動作だというのは理解できるが、MetaやWhatsAppが実装できる賢い回避策はきっとあるはずだ
クリックジャッキングとは、ある要素をクリックしているつもりでも、実際には通常その上に透明に重ねられた別の要素がクリックイベントを横取りする仕組みだ
見えている下層レイヤーにフォーカスを与え、
onblurイベントの発生を検知すれば、ユーザーがイベントを受け取らなくても攻撃者はクリックを把握できるOPが見つけたものは面白いが、クリックジャッキングではない。私も以前、RTL文字を使ってスクリーンセーバーファイル、つまりWindowsで拡張子だけが異なる普通の実行ファイルをWord文書のように見せたことがある。友人や先生にいたずらしようとしていたのだと思うが、理由はよく覚えていない
OPはさらに一歩進んで、別のシステムで表示が変わる方法を見つけた。ユーザーがどの要素をクリックしているかを誤認するのではなく、リンク先がどこかを誤認するので、クリックジャッキングではなく、冒頭でリンクされているWikipediaのページもその点を確認してくれる
実際にクリックジャッキングが悪用されるのは見たことがないが、OPが見つけた手法は悪用されうるとは思う
正直、ユーザーがリンクをクリックするときに最終的なドメインを見分けられると期待するのは、かなり前に諦めた。大半の人はその概念自体を理解しておらず、残りの人でも見分けるのは難しい
見分けられると思っている人ですら、すべてのリンクが
sendgrid.tld/j3ovi3bfogobbledypoop93jnri2oのような場所に飛ぶならお手上げになる。私たちは毎日、追跡用に難読化された怪しいゴミのようなリンクをクリックするよう人々を訓練しているのに、誰も気にしていない面白いハックだ。本当の問題はWhatsAppやUnicodeの逆方向文字ではなく、URLが難しいことにある
visa.securesite.comのような単純な例だけでも多くの人がだまされる。近い将来に良い解決策は見当たらないホスト名やドメインをめぐる一般的な混乱はもっと難しい問題だが、ブラウザはドメイン名の部分を強調するなどして、ある程度は緩和しようとしてきた。大半のフィッシング手法と同じく、最終的にはパスキーが終わらせる気がする
RTLは、その存在以来ずっと巨大なセキュリティ脆弱性の源泉だった。そうした言語を知らない人たちが、何の利益もないのに危険にさらされないよう、OSにすべてのRTLを無効化する設定がなぜないのかわからない
TextViewも含まれる開発者が特定のテキスト範囲を明示的にレビューして許可しない限り、デフォルトではすべての双方向テキストの抜け道を無効にすべきだ
世界人口の1%未満に配慮するという名目で、テキストレンダリングスタック全体をデフォルトで脆弱にするのは理にかなっていない
Metaがこの問題を修正せず、この研究者にバグバウンティも支払わないことにしたのは残念だ
詳細はここでは述べないが、Google SearchがときどきURLを書き換えるやり方のせいで、攻撃者が実際のURLを偽装できる
ウェブサイトやアプリに表示されるURLは絶対に信用しないほうがいい
「予想どおり、リンクとプレビューが別々に送信されていた!」という点のほうが、より大きなUI設計の問題だ。なぜ普通のユーザーが安全のためにリンクとプレビューを照合しなければならないのかと思う
全体としては、1が最善だと思う。送信者はどうせ自分のすべてのメッセージを「偽造」できるし、プレビューをメッセージの一部として含めるのも大差ない
ここでの問題は、そのコンテンツが送信者から来たものだと明確でないことだ。別の吹き出しのように表示されるので、ユーザーの99%はそのコンテンツが送信者提供だとわからない気がする
しかも結局、URLこそが重要だ。攻撃者が制御するURLをクリックするなら、攻撃者はプレビューに好きなものを何でも表示できる。だからプレビューを「本物」に強制して得られる利益は非常に小さい
3も悪くないかもしれない。特にダブルブラインドのような形で実装するなら、一方に接続して、そこから第二の先へ転送させることができる。そうすれば、最初の側はIPを見て、二番目の側は宛先を見るが、共謀しない限り両方を同時には見られない
ただし、その程度のインフラを構築して維持するには、得られる利益が比較的小さい
記事のいちばん下で、これがリバースエンジニアリングに分類されているのが気に入った
これはクリックジャッキングではない。クリックジャッキングとは、攻撃者がクリックを横取りし、ユーザーに意図していない、あるいは認識していない別の対象を実際にクリックさせることだ
テキストを右から左へ流すRTLコードポイントは国際化機能であり、それで人を混乱させるのは新しい脆弱性ではない