
CVE2021-38297 GO WASM buffer-overflow の悪用のための概念実証シナリオ
WebAssembly (WASM) は、最新の Web ブラウザの大部分で実行可能なバイナリ命令フォーマットです。C、C++、Rust、GO などのさまざまな高水準言語のコンパイルターゲットとして機能し、これらの言語で記述されたコードを WASM にコンパイルできます。
CVE-2021-38297 は、GO による GO コンパイル済み WASM バイナリのコンパイルとロードにおける重大なバグを浮き彫りにしています。この脆弱性は、GO が提供する JS wasm ローダー (wasm_exec.js) に存在し、argv 引数内のデータに制限なく WASM バイナリをロードできるようにします。argv は WASM の線形メモリに保存されるため、悪意のある攻撃者は過度に大きな argv 入力を使用して、GO コンパイル済み WASM プログラムの線形メモリを上書きする可能性があります。
この脆弱性は、GO バージョン 1.17.2 より前のバージョンで継続していました。
この概念実証は、ソーシャルメディアアプリケーション Vuln-Twitter を示しています。これにより、複数のユーザーが投稿やコメントを投稿できます。Node.js 上に構築された Web サーバーは、SQLite を使用して投稿データとコメントデータを保存します。
フロントエンドは、wordprocessor.wasm という名前の GO WASM モジュールとともにプレーンな JS を採用しています。このモジュールは、入力文字列を「LeetSpeak」に変換する toLeetSpeak などのメソッドを公開します(例:「Hello!」は「h3ll0!」になります)。
GO WASM モジュールは、LeetSpeak での投稿とコメントのレンダリングを支援します。

フロントエンドのレンダリングプロセス中、サーバーから投稿とコメントを受信すると、各コメントは GO WASM モジュールを使用して「LeetSpeak」にレンダリングされます。各投稿のコメントは、GO WASM モジュールのロード後に argv 変数の一部として渡されます。
さらに、GO モジュールには processSharedVar() というメソッドがあり、アドレス 0x5000 にある文字列を読み取り、簡略化されたスピーチに変換するように設計されています(例:「How are you?」は「How r u?」になります)。元の投稿は、このメソッドでアクセスできるように線形メモリの 0x5000 に明示的に追加され、投稿内容が変更されます。
同じことを行うコードセクションを参照してください:

コメントレンダリング時の WASM 線形メモリ図:

まとめると:
argv 変数を介してコメント、メモリアドレス 0x5000 の投稿を処理します。toLeetSpeak、投稿コンテンツには processSharedVar などの関数がそれぞれ使用されます。CVE-2021-38297 に基づく argv のサイズチェックの欠如を考慮すると、潜在的な脅威が発生します。悪意のあるユーザーが自分が所有していない投稿に過度に大きなコメントを付けた場合、このコメントはレンダリング中に argv を介して渡されます。サイズ制限がないため、アドレス 0x5000 のコンテンツ(元の投稿を表す)が上書きされる可能性があります。
この欠陥を悪用することで、悪意のあるユーザーは実質的に元の投稿コンテンツを変更し、Stored XSS 攻撃と同様の効果をもたらします。その後、他のユーザーがページを表示すると、変更されたコンテンツが表示されます。これは、全員のレンダリングに適用される共有フロントエンドロジックによって永続化され、その結果、上書きされた投稿が全員に見えるようになります。

注: これを再現するには、ローカルに Go バージョン go1.17.1 をインストールする必要があります。これは、このシナリオで使用される脆弱なバージョンです。特定の Go バージョンをインストールする方法については、公式の Go ドキュメントを参照してください。
それでは、上記のシナリオを再現してみましょう:
git clone [email protected]:gkrishnan724/CVE-2021-38297.git && cd vuln-twitternpm install を実行してすべての依存関係をインストールしますnpm run resetDB を実行します。これにより、いくつかの投稿とコメントでデータベースが初期化されます。npm run dev を実行してローカルサーバーを起動し、ブラウザで localhost:3000 を開くと、ログインページが表示されるはずです。それでは、悪意のあるアカウントでログインしましょう。資格情報はユーザー名: I_CANT_HACK、パスワード: hacker です。ログインすると、いくつかの投稿を含むフィードが表示されるはずです。
この投稿はかなり興味深いようです:
Amazon: ready 4 black friday? https://www.amazon.com/blackfriday
上記の手法を使用して、Amazon.com の投稿を悪意のあるリンクに上書きできたらどうでしょうか?
exploit.txt ファイルを参照してください。これには、アドレス 0x5000 まで全てを上書きするような "A" のパディングで埋められたコメントが含まれており、最後にテキスト ready for black friday? https://evil.com/blackfriday が表示されます。このテキストをコピーして、上記の投稿にコメントすると、元の投稿を上記のテキストで上書きできるはずです。
自分で試してみてください :)

このアプリケーションでは、パッチスクリプトも提供しています。これは新しいバージョンの Go を使用します:
npm run patchServer を実行しますこれにより、Go ファイルが新しいバージョンで再コンパイルされ、パッチバージョンでサーバーが起動します。
投稿が上書きされなくなったことに気づくはずです。また、コンソールを観察すると、代わりにエラー Argument length too long が表示されます。

線形メモリ上の WASM バッファオーバーフローを活用して、Stored XSS 攻撃を実行できるシナリオを示しました。ただし、このエクスプロイトの特異性に注意することが重要です: 線形メモリのハードコードされたアドレスのテキストを操作する必要がありました。実際の Web アプリケーションでは、このような特異性のため、このような脆弱性を発見することは非常に困難な場合があります。さらに、システムクラッシュを引き起こさずに線形メモリ内の任意のデータを上書きすることは複雑であり、特に GO の内部モジュールとデータを扱う場合、GO のメモリレイアウトに関する包括的なドキュメントが不足しているため、その複雑さはさらに増します。
私たちの理解に基づくと、GO の線形メモリレイアウトは以下のように描かれていると考えられます:

この悪用は、特に WASM における Web 開発において興味深い攻撃ベクトルを導入しますが、同時にプログラミング言語に固有のセキュリティリスクももたらします。たとえば、C プログラムが WASM にコンパイルされるシナリオを考えてみましょう。元の C プログラムにオーバーフローや脆弱性がある場合、これらのリスクは WASM 環境に移行し、同様の脆弱性や脅威にさらされることになります。
私たちはカーネギーメロン大学の学生であり、この CVE の概念実証を授業 (18-739D Hacking101) の1つで発表しました。スライドデッキはこちらから参照できます: GOWasm.pptx