- qBittorrentのDownloadManagerは、2010年4月6日から2024年10月12日まで約14年6か月にわたりSSL証明書の検証エラーを無視しており、ネットワーク傍受環境で複数のダウンロード経路が攻撃面となっていた
- この問題はCVE-2024-51774として指定されており、悪用にはMITMアクセスまたはDNSスプーフィングが必要
- 検索、
.torrentダウンロード、RSSフィード、faviconダウンロードなど、DownloadManagerを使う経路が影響を受け、期限切れ証明書や自己署名証明書も受け入れていた可能性がある
- WindowsのPythonインストールプロンプトと更新確認RSSフローは、ハードコードされたURLの応答が改ざんされると、実行ファイルのダウンロードや更新リンクの操作につながるおそれがある
- ユーザーはアプリ内更新プロンプトではなく、ブラウザでv5.0.1を直接手動ダウンロードしてアップグレードするほうが安全
14年以上続いた証明書検証のバイパス
- qBittorrentのDownloadManagerクラスは、2010年4月6日のcommit
9824d86以降、すべてのSSL証明書検証エラーを無視していた
- 既定の動作は、2024年10月12日のcommit
3d9e971で証明書を検証する方式へ変更された
- この最初のパッチリリースは、記事執筆時点で2日前に公開されたqBittorrent v5.0.1
- この問題はCVE-2024-51774として指定された
- 悪用条件はMITMアクセスまたはDNSスプーフィング
DownloadManagerが生んだ広い攻撃面
- DownloadManagerの利用範囲が広く、検索、
.torrentダウンロード、RSSフィード、faviconダウンロードなどが影響を受ける
- これらの経路は、期限切れ証明書、自己署名証明書、またはその両方に該当する証明書も受け入れ得た
- 主な影響経路は、WindowsのPythonインストール、ソフトウェア更新、RSSフィード、展開ライブラリの攻撃面に分けられる
WindowsのPythonインストールフローによる実行ファイルのダウンロード
- Windowsで十分に新しいPythonがインストールされていない場合、qBittorrentは検索プラグイン利用のためにPythonのインストールまたは更新を促すダイアログを表示する
- ユーザーが既定で選択されているYesをクリックするかEnterを押すと、ハードコードされた
python.orgのURLからPythonインストーラーをダウンロードする
- ダウンロード後、qBittorrentはそのファイル名を
.exeに変更して実行し、完了後に一時ファイルを削除する
- この動作は2015年6月から現在まで存在しており、
v3.2.1からv5.0.0までが影響を受ける
- 他のOS系統では、Pythonがないか十分に新しくない場合に検索ウィジェットを無効化するため、同様の動作は再現しないとみられる
- 実行ファイルは、たとえば
C:\Users\_user_\AppData\Local\Temp\is-G61QK.tmpのようなパスに保存されうる
QProcessの挙動による可能性があるが、実行ファイルのスレッドが2つ生成され、1つだけ終了し、もう1つがsleeping状態で残る場合がある
更新確認RSSを通じたURL改ざん
- インストール済みのWindows版またはLinux版のqBittorrentは、
appImageファイルでない場合、起動時に既定で更新確認を行う
- 更新確認は、ハードコードされたFosshubのRSS URLからXML文書をダウンロードし、プログラムのリリース情報を解析する方式
- XML内で現在実行中のバージョンより新しいバージョンが見つかると、update URLを抽出し、追加のフィルタリングや検証なしにユーザーへそのURLを開くか促すフローがある
- ユーザーがプロンプトを受け入れると、既定のブラウザでそのURLが開かれる
- ユーザーは、ソフトウェアが提示したリンクという信頼文脈から、
.exeファイルを期待するようになる
- 攻撃者がMediaFireのようなファイル共有サイトへ誘導すれば、ユーザーは攻撃者制御の実行ファイルをアップグレードのように受け取ってしまう可能性がある
- qBittorrentはオープンソースであるため、最新版にバックドア機能を加えて再コンパイルすることも容易
- 開発者はバイナリ署名確認用の鍵を提供しているが、ユーザーが実際に検証し、検証失敗を無視しないことが保護の前提となる
RSSフィードとリンク注入
- アプリケーションが解析するすべてのRSSフィードはDownloadManagerを通るため、ハイジャックされうる
- 被害者が訪れるURLは観察・一覧化されうえ、RSS URLは性質上静的で長期間維持される
- 各項目の
link要素は直接解析され、ユーザーがダブルクリックするとダウンロードされうる
- MITM改ざんがなくても、ユーザーが購読しているRSSフィードに作成者やフィード汚染攻撃者が入れた任意のURLは、ダブルクリック1回で開かれうる
- CVE-2019-13640は、torrent名または現在のtrackerパラメータに含まれるシェルメタ文字を通じてリモートコード実行を許していた脆弱性であり、MITM攻撃者がRSSに悪性データを入れられるため、組み合わせた際の危険が大きい
GeoIPデータベースのダウンロードと展開の攻撃面
- qBittorrentは起動時に既定で、ハードコードされたURLから
.gz拡張子のバイナリMaxMind GeoIPデータベースを自動ダウンロードして展開する
- zlibの展開処理に脆弱性があれば、攻撃者は最大64MBの任意ファイルでこの攻撃面を狙える
- 例として挙げられているCVE-2022-37434は、2022年のCVSS 9.8 Criticalのバッファオーバーフローだが、ここでは
inflateGetHeader()関数が呼ばれないため該当しない
- 展開後にバイナリのMaxMindデータベースを解析するコードは、2024年時点では十分に保護されているが、過去はそうではなく、追加の攻撃面が存在した可能性がある
gzip::decompress()関数のあるcommitでは、対象バッファがスタックの静的割り当てからヒープの動的割り当てに変更されており、書き込み前の検査があるため悪用可能ではなかった
自動化可能な攻撃シナリオ
- PythonインストーラーURLと更新RSSフィードURLはどちらもハードコードされているため、MITM環境の悪性スクリプトが脆弱バージョンを列挙して攻撃できる
- RSSフィードURLはqBittorrent起動中以外にアクセスされる理由がないため、ソフトウェアのフィンガープリントとして使える
- 証明書検証がないため、攻撃者はQUANTUMのような複雑なMan-On-The-Side展開なしに対象サーバーをスプーフィングできる
- ハードコードURLの性質上、ブラウザや他のアプリケーションの安全な接続失敗で被害者に警告を出させることなく、qBittorrentの未検証リクエストだけを選択的に傍受できる
- mitmproxyの
-sオプションとPythonスクリプトを併用すると、次の自動化が可能
- Python
.exeを任意の実行ファイルに置き換え: 1クリックRCE
- qBittorrent更新RSSのURLを自動置換: ブラウザハイジャック/RCE、中程度のユーザー操作が必要
- qBittorrent RSSビューアの全体または特定リンクを置換: 2019年までRCE、ダウンロードハイジャック
アップグレードと回避策
- qBittorrent v5.0.1へアップグレードする必要がある
- アップグレードはアプリ内更新プロンプトではなく、ブラウザから直接手動ダウンロードする方法が推奨される
- 代替として、Deluge、Transmissionなどこの脆弱性のないクライアントを利用することもできる
- MITMが必要な攻撃を単なる理論上のリスクとして片付けるのは難しく、近年の事例や一部の国における現実的な状況を考慮する必要がある
- リポジトリメンテナーとは連絡があったが、GitHubセキュリティアドバイザリを出す意向があるかについては回答を得られていない
1件のコメント
Hacker News のコメント
qBittorrent の DownloadManager クラスは、2010年4月6日のコミット 9824d86 以降、14年6か月にわたり、すべてのプラットフォームで発生するあらゆる SSL 証明書検証エラーを無視してきた
かなり深刻に見える
これはバグではなく「機能」だった、という点が目を引く
void downloadThread::ignoreSslErrors(QNetworkReply* reply,QList errors) {
// Ignore all SSL errors
reply->ignoreSslErrors(errors);
}
https://github.com/qbittorrent/qBittorrent/commit/9824d86a3c...
この脆弱性を軽く見るつもりはないが、リモートコード実行が可能な経路で、有効な TLS 証明書とドメイン名の組み合わせだけを唯一の防御線にするのは、ほとんど惨事だと思う
少なくとも、アプリケーションがインターネットから何らかの成果物をダウンロードして実行するなら、特定バージョンに固定し、実行前にダウンロードしたファイルの ハッシュを検証すべきだ
だとすると、自動アップデートは不可能ということか?
最低ラインは 署名検証だと思う
ソフトウェアを十分頻繁に更新しているなら、鍵を入れ替える機会も十分にあるはずだ
Windows では、ビルドツールで コード署名証明書を使い、ダウンロードしたバイナリを OS に検証させることができる
ただし、コード署名にはタイムスタンプサーバーを必ず使わないと、証明書の期限切れ後に壊れてしまう
ここでは、潜在的な 中間者攻撃という性質のせいで、ハッシュ検査は難しいと思う
攻撃者がリクエスト内容を見て改変できるなら、ハッシュ検査も整合性確認以外には役に立たなくなる
デスクトップアプリが特定ドメインに自動アップデートや確認リクエストを送る方式は、全体としてセキュリティ観点で十分注目されていないように思う
元の作者がドメイン更新をやめて敵対的に乗っ取られる、といったシナリオもあるが、まだ良い解決策を見つけられていない
過去約15年の間に、実際にこの問題の影響を受けた人がどれだけいるのか分かれば驚きだと思う
インターネットのちょっと怪しい側でも、群衆に紛れられる攻撃者にとって SSL 検証がどれほど重要だったのだろうかと思う
あまりにも多くのものが「ただ動く」のは、誰も気にしていないからであり、今この問題に光が当たった以上、自動アップデートしない人にとって状況は悪くなる一方だ
このコードは python.org から Python をダウンロードする役割のもので、悪用は可能だがかなり標的を絞る必要があり、対象へのアクセス権をすでにある程度持っている必要があったはずだ
別の方法で悪用するには python.org ドメインの乗っ取りのようなことが必要で、そうなれば誰もが気づいた可能性が高い
影響を受けたとすれば、たいていは 標的型攻撃だった可能性が高い
記事のかなりの部分は誇張されている感じがあり、何か問題があるのは確かだが、「qBittorrent リモートコード実行」という表現は技術的には正しくても 過度に警告的だ
実際のデータを得るのはほぼ不可能に見えるが、見られるなら面白そうだ
qBittorrent のコードを見たことがあるなら分かるだろうが、本当に ひどいコードだった
コメントのない関数が何ページも続き、行間も詰まっていて、不当に収監された精神病患者の獄中ノートのように見えた
私が見た小さな部分、圧縮された数ページ程度の中でも、戻り値チェックがまったくなかった
あるフィールドに通常の正しい2文字の値ではなく、正しい3文字の値が入ると、1分ほど後にプログラムがクラッシュしたりしたと記憶している
20年ほど前に C++ で報酬をもらってプログラミングしたことが2回あり、「では自分で一度見てください」というメンテナーのメッセージを受けてデバッガで走らせてみた
GUI で不正な値と正しい値が読み取られる地点まではたどり着き、その値を追っていくと、いつの間にか -1 があちこちに渡されていて、プログラムはしばらくそのまま進み続けた
結局、不正な値で実行した方は、かなり離れた関数で、不当に収監された精神病患者のようなエラーメッセージとともにクラッシュした
その後、実際の qBittorrent 開発者の一人が次のリリースで修正はしたが、ともかくそういうコードだった
“BUGFIX: Don't ignore SSL errors (sledgehammer999)”とだけ書かれている
https://www.qbittorrent.org/news
個人的には セキュリティ告知があるべきだと思う
正しい証明書検査をしていたとしても、リモートの実行ファイルをダウンロードして実行するのは、定義上 リモートコード実行脆弱性だと思う
Syncthing もこの方式を使っていて、おそらく証明書検査はしているだろうが、無人の自動アップデートは論理的に RAT/トロイの木馬と区別しにくい
脆弱性という部分は、第三者が悪用できるときに生じる
ソフトウェア提供者はどうせ信頼しなければならないので、自動アップデート自体が即リモートコード実行脆弱性というわけではない
この脆弱性の直接原因ではなかったが、潜在的に悪意ある多数のノードと通信するこうしたアプリケーションは、メモリ安全性の恩恵を大きく受けそうだ
ところが現在の実装はすべて C++ で書かれているように見える
記事でも4番目の項目で、この種の脆弱性の可能性を扱っている
Pythonで書かれたDelugeでさえ、C++製のlibtorrentに依存している
かつてのJavaベースのAzureusクライアントの現代的なフォークがあるのかは分からない
最近の多くのBitTorrentクライアントは、GUIと実際のトレント処理を担うデーモンプロセスを分離しているので、デーモンをJavaで作ってネイティブGUIに接続すれば、セキュリティ・性能・ユーザー体験の間で悪くないバランスが取れるかもしれない
ざっと探しただけでも、純粋なGo BitTorrentライブラリはいくつかある
Rustで書かれており、libtorrentに依存しないrqbitがある: https://github.com/ikatson/rqbit
議論のために自分で調べる代わりに、怠惰な質問をしてみると、libtorrentの代替を作るにはどこから始めればいいのだろうか?
試みや成功例があったのか、別の実装を使う実際に動作するクライアントがあるのかも気になる
特に後ろの項目に行くほど、少し誇張されているように見える
1番の「隠蔽機能を持つ悪意ある実行ファイルローダー」は、クライアントがHTTPSでpython.orgからPythonをダウンロードするという内容
良くはないし、特に3.12.4にハードコードされている点も問題だが、中間者攻撃とユーザー操作の両方を必要としない明確な悪用経路は見当たらない
2番の「ブラウザハイジャック+実行ファイルダウンロード」は、クライアントがHTTPSでRSSファイルをダウンロードし、条件付きでそのファイル内のURLを開くかどうかをユーザーに尋ねるという内容
1番よりリスクはさらに低く、ユーザーに中間者攻撃を仕掛けて「update」をクリックさせたとしても、結局見せられるのはWebページだけ
3番の「RSSフィードへの任意URL注入」は、研究者がRSSクライアントの期待される動作を混同しているように思える
4番の「展開ライブラリの攻撃対象領域」は、zlibの脆弱性を見つけられるなら、トレントクライアント攻撃よりはるかに悪いことができる
入力の展開は基本的に安全だと仮定される処理だ
ストリーム圧縮をサポートするHTTPサーバーのようなものがすぐ思い浮かぶ
そうだね
あまり否定的に言いたくはないが、セキュリティ「研究者」たちが少しの知名度のために、ごく薄い可能性までつかんでいるように見える
正直に文書化していればもっと敬意を払えたのに、ここでのやり方は眉をひそめるだけだ
証明書エラーを無視していなければ、これらの項目は些細なものだったはず
本来の問題はSSLエラーを無視することにあるので、実際にはすべてのHTTPSダウンロードがHTTPダウンロードへ格下げされたのと同じで、中間者攻撃がなくても攻撃可能になる
言い換えると、SSL検証がないせいで、HTTPS URLがレビュー担当者に安全であるかのような誤った安心感を与えていた
同意する
これを「リモートコード実行脆弱性」と呼ぶのは、とんでもない誇張だ
次は、Webブラウザが安全かもしれないし安全でないかもしれない任意のサイトからプログラムをダウンロードして実行できるという理由で、「リモートコード実行脆弱性」があると言うのだろうか?
それとも、権威主義国家に住んでいれば政府が悪事を働けるという事実も、今さら発表するのだろうか?
記事に出ている他の選択肢よりqBittorrentは1000倍性能が良いクライアントなのに、こうした指摘の質がこれほど低いのは衝撃的だ
性能を出しているのはlibtorrent-rasterbar(libtorrent.org)だ
最新版をコンパイルして実行するなら、https://github.com/userdocs/qbittorrent-nox-staticはDockerで静的バイナリをビルドしてくれる、なかなか良い補助スクリプトだ
libtorrent 1.2を使って5.0.0を実行したかったのだが、このスクリプトが圧倒的にいちばん簡単だった