「パスワード不要で完全乗っ取り」Plexの4つの設計ミスが生んだマイニング乗っ取りチェーン

「パスワード不要で完全乗っ取り」Plexの4つの設計ミスが生んだマイニング乗っ取りチェーン

サイバーセキュリティPlex脆弱性分析エッジコンピューティング

データソース:HN + web research

リビングの静音PCが突然轟音、バックグラウンドで仮想通貨マイニング

リビングの片隅に置かれた静音ミニPCが、突如として夜通し冷却ファンを高速回転させ始めた。普段は4K動画のストリーミング再生にしか使っておらず、負荷はごくわずかのはずだった。管理画面を開いて確認すると、CPU使用率は連日100%に張り付いていた。

バックグラウンドでは見知らぬ2つのプロセスが計算資源を激しく消費していた。1つはプロキシを装う myawesomeproxy、もう1つは仮想通貨マイニングを行う mylovelyminer である。管理者は不審なファイルをダウンロードした覚えはなく、管理ダッシュボードにも固有の強固なパスワードを設定していた。

原因はメディアサーバーソフトウェア「Plex Media Server」にあった。セキュリティ研究者により、未認証リモートコード実行を可能にするエクスプロイトチェーン「plex2shell」(CVE-2026-96652、-96654、-96655、-96656)が報告された。対象はバージョン1.43.2およびそれ以前。外部ネットワークの攻撃者はパスワードを一切知らなくても、細工したリクエストを送り込むだけでマシン全体を完全に乗っ取ることができた。

ハニーポット捕捉ログ 図:ハニーポットに記録された、攻撃者の自動化スクリプトによる不正ペイロード取得ログ。出典:BoredHackerBlog。

検証不備のコールバックを突き、サーバー自身を攻撃させる

多くのローカルサービスには「内部ループバックから届くリクエストは安全である」という暗黙の前提が存在する。内部通信の検証コストを省くため、Plexはローカル通信に対する制約を大幅に緩和していた。攻撃者はまさにこの信頼関係を突いた。サーバー自身に自身を攻撃させることができれば、内部防壁は一瞬で無力化される。

最初の足がかりとなったのは、再生進捗を受け取るプレイヤータイムラインAPI /player/timeline である。仕様上は X-Plex-Token ヘッダーを要求するが、サーバー側コードは hasParam() メソッドのみを呼んでいた。このメソッドはヘッダーの存在有無だけを確認し、値の妥当性や認証状態を検証しないため、適当な文字列を渡すだけで通過できてしまう。

このゲートを越えると、サーバーはプレイヤーのアドレスへイベント購読の通知を返送する。内部処理では boost::format("%1%://%2%:%3%") によってコールバックURLを組み立てていたが、プロトコル指定パラメータ protocol に対するフォーマット検証やエスケープ処理が一切行われていなかった。

攻撃者はこのパラメータにループバックアドレスを含む完全なURLを挿入した。その結果、Plex自身が自らの内部管理ポートに向けてHTTP POSTを送信した。ネットワーク接続上、リクエスト元のIPは正真正銘の 127.0.0.1 となり、攻撃者は「信頼されたローカル発の身元」を手に入れた。

文字列の前方一致ミス、いとも簡単に渡された管理者トークン

ローカルリクエストに偽装した攻撃者は、内部プラグイン管理API /system/agents/* へ侵入した。このAPIは接続元がループバックアドレスであれば認証をスキップする仕様だった。サーバーサイドスクリプト agentservice.py には本来 searchOne 関数内にアクセス制御のホワイトリストが実装されていた。

しかし、この関数には @lock ミューテックスデコレータが付与されていた。このデコレータが内部関数 inner() の戻り値を正しく伝播していなかったため、アクセス制限によって早期リターンが発生しても戻り値が握りつぶされ、防御機構がまったく機能していなかった。

さらに、リクエストパラメータ identifier のサニタイズ処理も不十分だった。クエスチョンマーク ? を渡せばクエリパラメータを任意に追加でき、ハッシュ # を入れればデフォルトの /messaging/... パスを切り捨てることができた。これで2つ目の穴が成立した。

続いて攻撃者はグローバル管理者権限の奪取を狙った。Plexのプラグイン機構には「宛先が 127.0.0.1 で始まるアウトバウンドリクエストに対し、システムが自動的に管理者専用の local-* 認証情報を付与する」という便宜上の設計が存在した。ところが、フレームワークはホスト名の境界を解析せず、単純な前方一致判定を行っていた。そのため、127.0.0.1.evil.com のようなアドレス宛のリクエストも条件を満たしてしまう。

攻撃者はワイルドカードDNSサービス sslip.io を使い、127.0.0.1.10-0-0-9.sslip.io というドメインを構成した。このドメインは前方一致のルールを満たしつつ、パブリックDNS上では攻撃者のサーバー 10.0.0.9 を指す。Plexは検証通過と判断して管理者トークンを外部へ自ら送信し、3つ目の脆弱性が成立した。

攻撃ログ記録 図:外部の悪意あるIPによる脆弱性スキャンおよび悪用試行のリアルタイムログ。出典:BoredHackerBlog。

悪意あるコードを動画ピクセルに偽装、トランスコーダーを悪用してディスク書き込み

管理者トークンを手にした攻撃者は、サーバー設定を任意に変更する権限を得た。Plexはデバイスごとの動画再生を最適化するため、内蔵のトランスコーダーを使用している。内部のx264エンコードコンポーネントにはデバッグ用パラメータが存在し、攻撃者はここに細工したオプションを注入した:TranscoderH264Options=dump-yuv=<パス>:qp=0。

dump-yuv オプションは内部で fopen(path, "w") を呼び出し、デコードされた生の映像フレームを指定パスに直接書き出す。量子化パラメータ qp を0に指定するとロスレスモードとなり、画面ピクセルの値は一切劣化しない。攻撃者はあらかじめ、初期化用コンストラクタのみを含む最小限のELF形式共有ライブラリ(.so)をコンパイルしていた。

そして、そのバイナリデータをMP4動画の第1フレームにおける輝度プレーン(Y成分)のピクセル値として1バイトずつ埋め込んだ。外見上は何の変哲もない、正常に再生可能なH.264動画が完成した。

攻撃者は管理者トークンを用いてトランスコードリクエストを発行し、path パラメータに自身のサーバー上の item.xml プレイリストを指定した。Plexはそのキャリア動画を取得し、トランスコーダーを起動した。第1フレームがデコードされた瞬間デバッグルーチンが走り、ピクセルの中に隠されていた悪意ある共有ライブラリが、Plex自身のトランスコードエンジンによってシステムの Codecs ディレクトリへ直接書き込まれた。

署名検証のないライブラリ読み込み、無名の共有ライブラリが権限を掌握

不正なファイルをディスクに配置しただけでは完了しない。プロセスにそれを読み込ませて実行させることが最後の目的である。Plex同梱のコンポーネント libavutil.so.58 は、トランスコーダー起動時に avpriv_load_new_libs 関数を呼び出す。この関数は Codecs ディレクトリ内のファイルを走査し、ファイル名が .so で終わっていれば無差別に dlopen(path, RTLD_NOW) を実行していた。

この読み込み処理には不可欠な防衛ステップが抜けていた。標準プレフィックスの確認を行わず、実行権限ビットのチェックもなく、デジタル署名の検証も存在しない。たとえファイルのパーミッションが一般の読み取り専用であっても、そのままメモリ空間へロードされてしまう。

ELF共有ライブラリの仕様により、dlopen でロードされたライブラリはシンボルのエクスポートがなくても DT_INIT_ARRAY に定義されたコンストラクタを自動実行する。そのコンストラクタ内部で fork() と execve() を呼び出し、リバースシェルを瞬時に確立した。これにより攻撃者はデーモンプロセスの uid=1000(plex) 権限を直接手中に収め、チェーンは完結した。

大規模言語モデルが脆弱性チェーン構築の敷居を下げ、狙われる家庭用エッジ機器

一連のタイムラインは非常に迅速だった。発見者は2026年7月27日にPlex公式へ報告。Plexチームは8月4日に確認を終えて報奨金を支払い、9月23日に4つのCVEが割り当てられ、10月16日にパッチと詳細が公開された。

詳細公開後、イン・ザ・ワイルドでの攻撃が即座に観測された。ハニーポットは 45.194.92.222、91.92.40.202、176.65.139.228 からの自動スキャン通信を記録し、攻撃者は 217.60.194.116 からマルウェアを展開していた。

捕捉された検体には、ハッシュ値 5712ef510481f15fe8b18fdd10b73026d57cb3d9d151878a692358b99a464441 のコンテナイメージや、UPXでパックされたバイナリ 68938fb428f2bcfef4ede62f7b29cd0f15f37ed59e94462c099f2ca64e36baa7 が含まれていた。アンパック後のコアバイナリのハッシュ値は b20f39fc00d242e706b6c30367ad811c676e0575050a4ec2f30104b696944b49 だった。攻撃者は24時間稼働している家庭用サーバーを標的に、プロキシを稼働させつつ仮想通貨を密かに採掘していた。

今回の脆弱性発見のアプローチも注目を集めている。発見者はLLM支援ワークフローを導入したことを明かしている。全体の手順を「偵察・トリアージ・検証・チェーン構築」の4段階に分割し、独立したエージェントに各仮説の反証を試みさせる手法を採用したという。

人間のアナリストが全体のアーキテクチャ設計や攻撃ロジックの優先度付けを担い、AIツールがコード調査の労力を大幅に引き下げた。個別の低リスクな欠陥を組み合わせて深刻な攻撃チェーンに仕立てるコストが急減しており、その最初の打撃を被ったのが専門的な防護が薄い家庭用エッジデバイスだった。

このチェーンには複雑なメモリ破壊は存在しない。未検証のヘッダー、デコレータに握りつぶされた制限指示、境界のない前方一致、無防備なライブラリロード。いずれも単体ではよくある実装上の見落としに過ぎない。

Plexが設けていた「ローカルからの通信は無条件で信用する」という設計前提が、それらの粗削りな隙間を致命的なバックドアへと結合させてしまった。利便性のための認証免除が、防御崩壊の最短ルートとなったのである。すでに野外での自動スキャンが始まっており、修正版ソフトウェアへの速やかなアップデートが強く求められている。

参考リンク:

  • zmain.info: plex2shell 脆弱性レポート
  • BoredHackerBlog: plex2shell イン・ザ・ワイルド分析
  • GitHub code-zm/plex2shell
  • GitHub BoredHackerBlog/plex2shell_pcap
  • Hacker News の議論 (item?id=50152321)