- ElectronベースのデスクトップアプリであるDiscordは、内部的にはChromiumウィンドウとして動作しており、Web開発者ツールを開けるため、クライアント側のコードを変更可能
- 一部の改造クライアントやプラグインは、Nitroの有料サブスクリプションが必要な機能の一部をクライアント側で解除
- Webpackのcode splittingで分割されたモジュールを
webpackChunkdiscord_app変数に注入し、内部関数を探索・置換する手法が核心
- 画面共有の画質チェック関数はクライアント側のみで検証されるため迂回可能だが、プレミアムテーマにはサーバー同期の検証も追加で動作
- デモ手法はいずれもDiscordの利用規約違反であり、アカウント停止のリスクや、未検証コード実行によるアカウント乗っ取りのリスクがある
概要
- 外観を変更したり機能を追加したりする改造Discordクライアントは多数存在し、一部のプラグインはNitroの有料サブスクリプションが必要な機能まで解除する
- こうした動作が可能になる技術的原理を、クライアント構造の分析を通じて説明
開発者ツールの有効化
- DiscordはWeb技術でクロスプラットフォームアプリを作るElectronフレームワークで開発されており、Webブラウザ内で実行されるWebサイトに近い
- 本質的にはChromiumウィンドウなので開発者ツールを開けるが、デフォルトでは無効化されている
- 多くのユーザーが攻撃者のソーシャルエンジニアリングによる誘導で悪意あるコマンドを貼り付け、アカウントを奪われた事例があるためブロックされている
- リスクを理解している場合は、
%appdata%/discord/settings.json設定ファイルにDANGEROUS_ENABLE_DEVTOOLS_ONLY_ENABLE_IF_YOU_KNOW_WHAT_YOURE_DOINGの値をtrueとして追加し、有効化する
- その後、
ctrl + shift + iで開発者コンソールを起動
Discordの関数パッチ
- 初期ロード最適化のため、コードは複数のチャンクに分割され、並列または遅延読み込み(lazy-loaded)されており、Webpackのcode splitting機能を使用
- ロード済みのすべてのチャンクは
webpackChunkdiscord_app変数に保存される
- Discordの変数・関数を使うコードを実行するには、この変数にコードを**注入(inject)**する必要がある
a.cはすべてのモジュールを格納したオブジェクトで、各モジュールはchunk_id、loaded、exportsの形式で構成される
exportsには、モジュールからエクスポートされた関数・オブジェクト・プリミティブ値が含まれる
- 複数のJavaScriptモジュールを巡回する
find関数を作れば、特定の関数を探索して呼び出せる
- 例:
getCurrentUser()関数を探して呼び出す
- 元の関数を別の関数に**置き換える(replace)**ことで動作を変更でき、直接的なコード変更が可能
高画質ストリーミングの解除
- ここから先の内容はDiscordの利用規約に明確に違反し、アカウント停止につながる可能性があるため、リスクを負う必要がある
- ユーザーのサブスクリプション等級を確認する
canStreamMidQuality、canStreamHighQualityの2つの関数が、画面共有の画質選択画面の直前に呼び出される
- 2つの関数の戻り値を
trueに強制すると、Nitro未加入でも元解像度60 FPSの画面共有を選択可能
- 現在のDiscordは、送信されるストリームが未加入者向け基準を実際に満たしているかをサーバー側で検証していないように見える
- ただしDiscordはまだ**エンドツーエンド暗号化(End-to-End encryption)**を使用していないため、検知される可能性はある
- 参照記事によると、Discordはすでにユーザーの音声・動画コンテンツを検査しており、将来的に画面共有前のサーバー側検証を追加する可能性がある
プレミアムテーマの解除
- ユーザーがNitroテーマを使用できるかを返す
canUseClientThemes関数の値をtrueに変えると、プレミアムテーマの選択ボタンが解除される
- しかし、テーマはいったん適用された後、すぐにデフォルトテーマへ戻る
- クライアントがテーマ変更を保存しようとするが、サーバーが権限がないことを検証し、応答を受信するとデフォルトテーマを再適用するため
- 外観設定の同期だけをブロックするように
shouldSync関数をパッチし、appearanceの値のときにfalseを返させると、テーマ変更が維持される
- テーマは完全にクライアント側で管理されており、CSSを直接変更することも常に可能なため、Discordがこれを防ぐのは難しい
結論
- 実演されたハックを簡単に適用するコードはあるが、クライアントの変更や改造版の使用前には慎重さが重要
- Discordは利用規約違反のアカウントをいつでも停止でき、アカウントへのアクセス権を持つ未検証コードの実行は非常に危険
- 記事内のエンコードされたメッセージ:「理解していないコードを開発者コンソールに貼り付けないこと — アカウントを乗っ取られる最も簡単な方法」
1件のコメント
Hacker Newsのコメント
末尾に付いた単なるbase64エンコードされたblobを実行すると全機能が有効になる、という作りなら、かなり簡単な攻撃ベクトルになり得るのではと思う
投稿者を疑うという意味ではなかったが、今デコードしてみたら一本取られた
base64 --decodeを回すのが面倒な人向けに結果を貼るとこうなる:// Here's a cake if you thought about inspecting the code before executing it:let css = 'font-size: 36px; font-weight: bold; color: red';console.log("%cNEVER paste code you don't understand into the development console.", css);console.log("%cThis is the best way to compromise your account.", css);「現在のDiscordは、送信中のストリームが実際に非購読者向けの基準を守っているかをサーバー側で検証していないようだ」とのことだが、誰がこれを良い実装だと思ったのか気になる
クライアント側検証は本当に初歩的なミスに見える
Discordを何年も使ってきたが、Nitroのアクセス権構造を回避しようとする試み自体を初めて聞いたし、広く出回っていないならわざわざ気にする理由もなさそうだ
それとは別に、今月だけで5つ目の新しい仕事を始めたのだが、どうもプロジェクトマネージャーとは相性が悪いらしい
こういうハックを理解して、しかもNitroにお金を払う意思まである人がどれくらいいるのかと思う。Nitro機能の一部または全部を有効にする各種Discordクライアントmodを使っている人は数千人、ひょっとすると数万人いるだろうが、これを防いだからといって実際にどれだけ売上が生まれるのかは疑わしい
個人的には、その機能が必要または欲しいなら月10ドル払うほうがずっと手間が少ない。Discordのアップデートのたびに壊れるmodを追い続けたり、メンテナーが悪意あるコードを入れないことを祈ったりするよりましだと思う
チャンネルはクライアント側で隠されているだけだ。はっきり言っておくと、それでもそのチャンネルのメッセージ内容まで見られるわけではない
音声サーバーは参加権限があるかだけをAPIに確認し、その後は一対多のパケットブロードキャスターのように動作する
これは、好奇心旺盛で熟練しているという意味での古典的なハッカーに近い
深刻な被害もなく、アプリは魔法ではなくコードはクールだということを改めて思い出させてくれる
そうすれば、抵抗なく私たちからもっと金を搾り取ろうとできるからだ
念のため改めて言うと、Discordに送るものはすべて、DMを含めて、Discordに平文で記録され、Discordおよびその会社を買収する主体がアクセスできる
一時期はMicrosoftが買いそうに見えたし、今はIPOに向かっているようだ
アカウントを持っているだけで、AI向けのデータマイニングや、Discordおよびデータベース/システム管理者が利用しやすい個人的な会話が常態化する。FISA Amendments ActのSection 702(FAA702)は、連邦捜査機関が令状なしでそうしたデータにアクセスできるようにしている
暗号資産のフロントランニングの可能性だけでも、1日あたり数千万ドルの価値がありそうだ
友人なら、友人にエンドツーエンド暗号化されていないチャットシステムを使うよう勧めるべきではない。罠の中の蜜になってはいけない
ユーザー自身が鍵を管理する真のゼロトラストモデルを実装した数少ないサービスでも使っていない限り、当たり前のことだ。メッセージを保存する理由は、ユーザーが再びアクセスできるようにするためだ
Matrixのように比較的使いやすい形でエンドツーエンド暗号化のグループメッセージングを実現しているサービスもあるが、例外に近い。電子通信プラットフォームの95%がやってきたのと同じ方式だというだけでDiscordだけを特別に悪質だと決めつけるのは公平ではない
良いという意味ではないが、参加しない以外に選択肢がないコミュニティもある
昔の「みんながWhatsAppを使う」よりもさらに悪い。当時は相手の番号があるので別の方法で連絡しやすかったが、Discordの魅力は個人的な会話ではなく、半公開の空間を持つコミュニティにある。ここでの公開とは誰にでも開かれているという意味ではなく、100人くらいが読むという意味に近い
メッセージを消せば、もうデータベースには保存されない
最近OpenAIがベータテスター向けDiscordを突然無効化したせいで、私たちが誰と何を議論していたのかをもう見られなくなった
サーバー管理者が記録を見返す手段も残さずに、コミュニティを互いに切り離せないようにしつつチャットをエクスポートする方法があるのか気になっていた
DiscordチャットをエクスポートするChrome拡張はいくつもあるが、たいていは一部機能を有料でロックしているようだ
調べてみると、Chromeフォルダから拡張機能のソースをコピーし、
is_proのような真偽値チェックをJavaScriptで書き換えてから、展開済み拡張機能として再読み込みするのはとても簡単だったAPIを非標準な方法で使うスタンドアロンプログラムだが、これを使ったことでまだBANされた人は見たことがない気がする
こういうトリックを使うとBANされる可能性があると正しく警告しているが、DiscordがこうしたことでユーザーをBANした前例はあるのだろうか?
代替クライアントを使うことも禁じている。アカウントが大事ならDiscordをいじらないほうがいい
「クライアントの改変はDiscord利用規約に違反します。」
ただしDiscordはこれについてかなり無頓着で、クライアントmodを使ったという理由だけでBANされた既知の事例はない。なので、悪用行為を実装したプラグインだけ避ければ、たいていは大丈夫だろう。心配しなくていい点として、内蔵プラグインはすべて安全だとされている
一部のテーマがこういう形で有効になるのは理解できるが、ストリーミング品質をサーバー側ではなくクライアント側のチェックで決めるようにしたのはかなり理解しがたい
実際の映像にアクセスする必要もなく、完全に暗号化されていても転送データ量を見ればどの品質でストリーミングしているか分かる
フロントエンドエンジニアリングの大原則がまたしても当てはまった
「絶対に、絶対にクライアントを信用するな」
クライアント側だけの処理で済むと分かってから、ずっと開発者ツールで1080p60ストリーミングボタンを有効にして使ってきたが、実際に動作する
何年になるのか分からないが、Discord側では誰も気にしていないようだ
昔この道を試そうとしたことがあるが、特にアップデート後にクライアントへ一貫してパッチを当てる方法が見つけられず、結局あきらめた
だがこの方法を見ると、また「分解して突っついてみたい」という衝動が湧いてくる
この方式で使えるAPIをざっと調べる簡単な方法はあるだろうか? すべてログしようともしたが、マップや国際化などであまりに混沌としていた。誰かが苦労してリバースエンジニアリング文書のようなものを作っていたりするのだろうか