3 ポイント 投稿者 GN⁺ 2023-07-14 | 1件のコメント | WhatsAppで共有
  • macOSのデフォルトのローカルホスト名にはユーザー名が含まれることがあり、Webサイトは権限なしで mDNS名前解決の時間差 を使って名前候補を絞り込める
  • 攻撃者は国・性別ごとの人気名50個とデバイス名候補を組み合わせ、実験では平均 65% のケースでmacOSユーザーの名前を特定した
  • ブラウザのJavaScriptは任意のUDPソケットを開けないが、fetchiframeImageWebRTC リクエストで .local アドレスの 応答遅延 を比較できる
  • タイムゾーン、言語、IP位置情報、Safariの navigator.language、画面解像度、screen.isExtended のような情報が、ロケールやデバイスモデル候補を絞るのに使われる
  • 実用性は低く、開発者ツールのネットワークタブで見つかりやすいが、同じmDNS探索手法はプリンター、スマートTV、スマートスピーカー、IoT機器の検出にも使える

macOSのローカルホスト名から名前が漏れる仕組み

  • macOSユーザーの実名は権限要求なしでブラウザから推定でき、その中核は mDNSプロトコル とデフォルトのローカルホスト名の形式にある
  • 特定の国出身者について性別別の人気名50個のリストだけを使っても、平均 65% のケースでmacOSユーザーの名前を正しく特定できた
  • Fingerprintはこの手法を製品に使用しておらず、クロスサイトトラッキングサービスも提供していない
  • 公開議論の目的は、ブラウザ提供者がこうした手法を迅速に修正できるようにすることにある

mDNSとApple Bonjourの動作方式

  • multicast DNS は、ローカルネットワーク上でデバイス名を登録・探索・ブロードキャストするためのプロトコル
  • プリンターのような機器は 224.0.0.251 の予約内部IPへUDP登録パケットを送り、HP_LaserJet_Printer.local のようなホスト名を含めることがある
  • .local トップレベルドメインは、そのホスト名が mDNS で解決されるべきであることを示す
  • ルーターはこのようなパケットをローカルネットワーク上の他の機器へ自動的にブロードキャストし、ホスト名をキャッシュできるようにする
  • 機器は同じ予約IPへクエリパケットを送り、ネットワーク上に存在するかもしれない特定名の機器を探す
  • ホスト名の例は次のとおり
    • johns-mac-mini.local
    • david-ZenBook-UX431DA-UM431DA.local
    • james-iphone.local
    • canon-mf644c.local
    • bedroom-appletv.local
    • dlinkrouter.local
  • Appleデバイスでは、mDNSは Apple Bonjour 機能の一部として広く使われている
  • デフォルトのローカルホスト名にユーザー名が現れることがあり、macOSでは System Settings > Sharing でローカルホスト名を確認または変更できる

ブラウザでmDNSホスト名を確認する回避手法

  • mDNSはUDPパケットベースのため、ブラウザのJavaScript環境では任意のUDPソケットとして直接利用できない
  • その代わり、ブラウザがURLのホスト名を解決しようとする性質を利用して タイミング攻撃 を行う
  • 概念実証では、存在する device-1.local と存在しない device-2.local に通常の fetch GETリクエストを送る
  • アドレスが解決されると、ブラウザは80番ポートへTCPパケットを送るが、このポートはたいてい閉じている可能性が高い
  • ネットワークレベルでは異なるエラーが現れる
    • 存在する device-1.local: ERR_CONNECTION_REFUSED
    • 存在しない device-2.local: ERR_NAME_NOT_RESOLVED
  • JavaScriptでは両方のエラーが同じ Failed to fetch エラーにマップされるため、エラー種別そのものには依存できない
  • ローカルネットワークは高速なので、有効なmDNSホスト名はデフォルトの接続タイムアウトよりはるかに速く解決される
  • 例では、有効なアドレスは 4ms、無効なアドレスは 5秒 で分かれた
  • このアプローチは概念実証には十分な一貫性があり、主要ブラウザで同様に動作する
  • 実際には fetch 以外にも、iframeImageWebRTC のようなネットワークJavaScript APIでDNS解決のタイミング攻撃を行える

macOSユーザー名をブルートフォースする方法

  • デフォルトのmacOSローカルホスト名にはユーザー名とデバイス名が含まれ、その形式はシステム言語のロケールによって変わる
    • English: <name>s-macbook-pro.local
    • French: macbook-air-de-<name>.local
    • Russian: mac-mini-<name>.local
  • 単純な方法として、上位1,000個の名前、上位10個のロケール、一般的なmacOSデバイス名5個を組み合わせると、50,000個 のホスト名を調べる必要がある
  • この場合、全件の検査に1時間以上かかる可能性がある
  • より効率的な戦略は、探索範囲を単一ロケール・単一デバイス・そのロケールで一般的な名前50個に絞る方法
  • 範囲を狭めると精度は下がるが、攻撃時間が短くなり、より現実的なシナリオになる
  • ロケールの選択には、ブラウザのタイムゾーン、言語、IPアドレスの位置情報を利用できる
  • Safariは navigator.language プロパティでシステムロケールを公開しており、この値は通常、対象ホスト名のロケールと一致する
  • ユーザーの出身国を見つける別の回避手法として、以前に扱われた Apple ID region detection の方法がある
  • デバイス候補は画面解像度で絞り込める
    • たとえば 1728x1117 の解像度は16インチMacBook Proである可能性が高い
    • 拡張画面は screen.isExtended プロパティで検出できる
    • 拡張画面が検出された場合、デバイス候補を最も一般的なApple製macOSデバイス3〜5個に戻せる

制限と他の応用可能性

  • この攻撃は本質的な弱点と複数の制約のため 実用的ではない
  • Webサイト運営者が訪問者を意図的に匿名解除しようとするのでなければ、ブラウザの開発者ツールのネットワークタブで簡単に検出される
  • この方法を installed applications detection と組み合わせると、権限なしでユーザーの実名や使用中の専門アプリケーション一覧に基づく役職を表示する有害なWebサイトを作れる可能性がある
  • AppleデバイスでmacOSを実行しているケースが主な例だが、mDNS探索手法はさまざまな形に拡張できる
  • ローカルネットワークのスキャンを通じて、プリンター、スマートTV、スマートスピーカー、その他の家庭用IoT機器の検出にも利用できる
  • iPhoneとiPadにも適用可能で、条件は Wi-Fi syncing またはSafariのリモートデバッグ機能が有効であること

1件のコメント

 
GN⁺ 2023-07-14
Hacker News のコメント
  • macOS で Little Snitch を使っているが、ネットワークリクエストを許可する前にローカルユーザーへ明示的に確認するよう設定できる、よくできた UI だと思う
    https://www.obdev.at/products/littlesnitch/index.html
    リモートログイン中にたまに引っかかることがあり、たいてい SSH セッションが NPM から NodeJS コンポーネントを取得するような形で何かを新しくダウンロードしようとしたとき。テキスト端末上の SSH ダウンロードが止まり、原因が Little Snitch だと突き止めると、階下の机まで行ってマウスを動かしてモニターを起こし、スクリーンセーバーを解除して Little Snitch のダイアログで「Allow」を押さなければならない
    意図どおりに動いているということではある。ただ、こうしたツールはデフォルトでローカルネットワークへのリクエストを静かに許可する設定になっていることが多いので、元記事のいたずらが自分の環境でも通用するかは分からない

    • 自分の場合、ブラウザで特定のホスト名だけを許可するよう LittleSnitch を設定するのは想像しにくい。「53/80/443 宛てのすべてのトラフィックを許可」というルールを置いていて、そうでなければほとんどの Web サイトが LittleSnitch のポップアップを何百個も出すことになる
    • 脱獄した iPhone で NetFence を使っている
      アプリが裏でどんなソケット接続を開いているかを見ると驚く。銀行アプリも例外ではない
      https://havoc.app/package/netfence
    • ただし Little Snitch はブロックするときでも IP が漏れる :(
      https://news.ycombinator.com/item?id=35363343
    • Linux で似たソフトウェアの OpenSnitch を使ってみたことがある。怪しいものは見つからなかったが、基本的な作業全般でかなり面倒になった
    • 参考までに、DNS 解決は接続の許可/拒否ポップアップより先に発生する。たとえば www.example.com は 1.1.1.1 に解決されるが、Confirm を押すまでは 1.1.1.1 への実際の接続は作られない
      ネットワークに Pi-hole を追加すれば、時間・お金・投資を後悔することはないはず
  • より広いインターネット上の Web サイトが、自分のローカルネットワークへネットワークリクエストを送れないようにする方法はあるのだろうか。これがデフォルトで許可されるべき理由が想像しにくい
    IE の Local Intranet Zone 権限を復活させようという意味ではない

    • 一般的には CORS のためできない。この「ハック」が動作する唯一の理由は、解決できないドメインへのリクエストと、解決はされたが拒否されるリクエストとの間で、拒否されるタイミングが異なるため
      しかし https://192.168.2.1 で何かを動かしていたとしても、192.168.2.1 のサービスが Origin として my-own-domain.com を許可していない限り、https://my-own-domain.com で動作する Web アプリからはアクセスできない
    • Brave は最近、ローカルネットワークアクセスに権限を要求する機能を追加した
      https://brave.com/privacy-updates/27-localhost-permission/
      HN の投稿: https://news.ycombinator.com/item?id=36574775
    • この手法をよく悪用しているアプリが Discord デスクトップアプリで、ローカルポートを開いて待ち受けている
      ブラウザが Discord チャンネルの招待ページへ移動すると、このポート経由で localhost にリクエストを送り、チャンネル ID をクライアントに渡す。するとアプリはネイティブな「Join Channel」体験を表示できる
      シークレットモードでも動作し、ブラウザ側で Discord からログアウトしていた状態でもこの挙動が続くのを見て気づいた。よくない。デスクトップの世界では、すべてのアプリケーションのサンドボックス化を大幅に改善する必要がある
    • uBlock Origin の静的フィルタでブロックできる:
      ||local^$all
      これにより、.local 自体から来たリクエストも含め、.local 宛てのすべてのリクエストをブロックする。Web サーバーを動かすなどの理由で foo.local が自分自身と通信することを許可したい場合は、ドメインごとに追加の例外が必要になる:
      @@||foo.local^$domain=foo.local,all
      あるいは .local 全体を信頼して、任意の foo.local が任意の bar.local と通信できるよう許可したいなら、.local 全体の例外を 1 つ追加できる:
      @@||local^$domain=local,all
    • 混同を避けるために言うと、これはインターネット上のサーバーがローカルネットワークへリクエストを送る問題ではなく、ローカルの Web ブラウザがそのリクエストを送る問題である。もちろん、ブラウザで実行される JavaScript はインターネット上のサーバーから読み込まれる可能性がある
  • 時間がたつほど、インターネットは基本的に Qubes マシン上で、使い捨ての Whonix/Tor VM から、JavaScript をオフにして使うほうが気が楽になってくる
    これは本当に気持ち悪い。驚きはしないが、それが可能だという事実自体が多くの意味でひどい
    fingerprint.com を知らないなら、彼らは「深いユーザープロファイリング」を行っている。コンピューター、ブラウザ、OS が違っても同じユーザー ID を維持し続けるようなものだと思えばいい。メインページにデモがあり、どれほど正確に当てるか少しぞっとする

    • 異なる VPN IP でも同じデバイスだと完全に認識する。本当にぞっとする
    • これは気持ち悪い。素の iPhone のシークレットモードで IP を 2 つ変えてもやり遂げるのは印象的だが、他の iPhone とまったく同じに見えるはずなのにそうなる
      デモを壊す uBlock Origin フィルタ:
      ||fpjscdn.net
  • 同種のタイミング攻撃により、ブラウザからローカルマシンやローカルネットワーク上の他のデバイスをポートスキャンできる
    https://github.com/Flu1dTeam/PortScanner
    以前、eBayがこれをやって発覚した
    https://blog.nem.ec/2020/05/24/ebay-port-scanning/

    • 何それ、かなり気味が悪いのに、なぜ今まで聞いたことがなかったんだろう?
  • デバイス名をいつも変更しておいてよかった
    Appleのデフォルトの命名はプライバシー上の失敗だ。以前、法執行機関にいる人と初デートしたことがある。相手は一人で来た女性で、自分の身を守ることに明らかに気を配る人だったので、私の身元調査をしていて、周囲のコミュニティの何人かにも私たちの居場所を知らせておいたと言っていた
    一方で私は相手の姓すら知らず、それを冗談のネタにしていた。夕食後に車に乗ったとき、ダッシュボードの画面にiPhoneが自動ペアリングされたと表示され、そのiPhone名が相手の名と姓になっているのを見て興味を引かれた。私はそれを指摘せず、ドライブが終わるまで、どうやって名前を知ったのか当ててみてと言った

    • レンタカーには、以前ペアリングされた携帯電話のプロファイルが十数個残っていて、電話帳、保存済みの地図上の場所、履歴まで紐づいていることが本当に多い。もちろん大して役には立たないが、何気なく情報が漏れている
      問題は、車を返す前に自分のプロファイルを消すよう自分に思い出させるのが一番難しい点だ
  • 上の例では、有効なアドレスは4ミリ秒、無効なアドレスは5秒かかっている
    これは意外だ。DNSルックアップの失敗は、成功したDNSルックアップの後に発生するデフォルトの接続タイムアウトよりずっと速いと思っていた
    それでも、s-mac-xxxxは常に少し妙な選択だと思っていた。特にプライバシーを大きな売り文句にしている会社だと考えるとなおさらだ。実名を使わないだろうと期待していたのか、ここでは「ユーザーフレンドリーさ」が優先されたのだろう。プライバシーの観点では、Windowsのランダム生成ホスト名のほうがましだ

    • 通常のDNSは単一IP上の単一サーバーにイエス/ノーの答えを尋ねるが、mDNSはマルチキャストなので、どこか1台のサーバーが権威を持って「ノー」と言うことはできない†。サーバーが応答せず、問い合わせがタイムアウトして初めて、そのレコードが存在しないと検知できる
      † 厳密には完全に正しいわけではない。あるデバイスがその名前を自分のものだと認識している場合は、ノーと言うことができる
    • ユーザーの実名がホスト名に入る理由は、おそらくAirDropのためかもしれない。システムはPersonal HotspotやAirDropのような機能でホスト名を使っているように見え、別種の名前にするとファイル共有時に広範な混乱を招く可能性が高い
    • デフォルトの接続タイムアウトという点に加えて、ここではconnection refused、つまりRSTを受け取っており、接続タイムアウトではなかったという点もある
  • 記事はよく書けていて興味深い。特に「内在する弱点と多くの制約を考えると、この攻撃は実用的ではない」のような誇張のないトーンが気に入った

    • 別の宇宙なら、これは「FINGERBleed」になっていて、格好いいWebサイトとロゴまで付いていただろう
    • 確信はない
      この方法は、ネットワーク上に特定のホスト名が存在するかをテストできるようにする
      一意のホスト名1つなら大した問題ではないかもしれないが、IoTの世界でよくある固定ホスト名やデフォルトホスト名はどうだろう
      Webサイトが、ユーザーが特定のデバイスを所有しているかをこっそり推測できるようになる。標的型攻撃に使えばさらに悪い。ネットワーク内の一部のデバイスを知っていれば、アクセスしてきたユーザーが標的ネットワーク内にいるかを推測できる
  • JavaScriptをオフにすることが、エンドユーザー体験までオフにすることにならなければよかったのに

    • これが、私がJavaScriptをグローバルに無効化できない唯一の理由だ
      それでも今後は、プライバシー上の懸念からデフォルトでオフにせざるを得なくなりそうだ
    • JavaScriptエンジンにできることを強く制限する方法はないのか?
  • 幸い、自分のデバイス名はたいてい「xxxs's MacBook Pro (34)」のような形式だ。バグではなく機能だ

    • ノートPCのユーザー名はuser、ホスト名はhostnameに設定しよう。こうする人が多いほどよい
  • 興味深く、記事もよく書けていて、ちゃんとした概念実証まである。よくできている
    面白い対策として、デバイスのホスト名をatemptingurl.localのようなものに変えて、攻撃者がそのWebサイトを訪れてみたくなるようにできそうだ。そのページは同じ手法を攻撃者に対して実行するよう巧妙に作っておき、こんなメッセージを返すというわけだ:
    「こんにちは、[ハッカーのデバイス名]さん!あなたのマシン情報、IPアドレス、地理的位置、その他のフィンガープリント情報が収集され、[恐ろしげなサイバー機関名を挿入]に報告されました。」熟練のベテランでスクリプトキディでなくても、少なくとも笑わせることはできるだろう
    人々には笑う理由がもっと必要だ :-)

    • そのためには、CORS全許可を有効にしたHTTPサーバーを動かす必要がある。そうすると、選んだHTTPサーバーのあらゆるバグにさらされるので、自分のセキュリティも低下する