web-dev-qa-db-ja.com

systemdの手で巻かれたDesktop-Bus-over-SSHトンネルはセキュリティの心配ですか?

2017-09-02にPeter Wullingerが書きました

remoteリモートdbusへのトンネル接続
☑ハードコードssh(パスなし)
☑エスケープ、解析、アンエスケープのバグがあります
☑これは文書化しないでください

systemctlプログラムの-Hまたは--Hostオプション を使用すると、systemdは、D-Busライブラリに、systemd-stdio-bridgeという名前のプログラムを実行している内部でsshを実行するように指示しますリモートマシン上。このプログラムは、リモートマシンのD-BusブローカーとローカルマシンのD-Busクライアントであるsystemctl間の単純なメッセージポンプとして機能します。 systemctlは、ローカルシステムと通信しているように、SSHとsystemd-stdio-bridgeを介してプロキシされているデスクトップバスと通信します。

それに応じて、これは別のsystemdセキュリティ問題かもしれないと他の人々は疑問に思いました。それは...ですか?

(これは一般的なSSHセキュリティに関する質問ではなく、この特定のsystemdメカニズムに関する質問です。 " SSHトンネリングのセキュリティへの影響は何ですか? "。これは" systemdのsystemv initと比較したセキュリティへの影響は何ですか? "のような質問でもありません。初心者にとって、これはvan Smoorenburg rcファイルについてはまったく意味がありません。)

14
JdeBP

Twitterでこれを議論することは、Fermatがマージナリアを介して数学的な証明を議論することに相当する現代のことです。だから、ピーター・ウリンジャーが収まるスペースがなかったものを拡大してみましょう マージン Twitterの投稿。

もちろん、systemdの人々がこれを行うことができる他の方法がありました:

  • システム管理者に使用を勧める
    ssh -x- アカウント@ホスト systemctl stuff
    の代わりに
    systemctl -H アカウント@ホストstuff
  • 内部的にsystemctlがのようなものを生成するように、ローカルドメインソケットにOpenSSHの組み込み転送メカニズムを使用します。
    ssh -xT -L/run/user /ユーザー/アカウント@ホスト/ bus:/ run/dbus/system_bus_socket- アカウント@ホスト/bin/true
    の代わりに(そうするように)
    ssh -xT- アカウント@ホスト systemd-stdio-bridge

are実際に取られたアプローチにはいくつかの問題があり、そのうちのいくつかはセキュリティです関連。しかしながら、これまでのところ、完全な脆弱性のレベルに上昇するようには見えません。

「この文書化されていないsystemd-stdio-bridgeプログラムは何ですか?」

まず、システム管理者がログとpsの出力を見て、これらすべての人がsystemd-stdio-bridgeをSSH経由で実行しているのではないかと考えます。 「 奇妙な 'agetty'プロセスが私のVPSで実行されています。 "からわかるように、 Weitse Venemaのagettyプログラム について不思議に思っている人がいます MacOSには、人々をだますためのsystemdというマルウェアがすでにあります なので、システム管理者がsystemd-stdio-bridgeについても不思議に思っていると想像するのは、一筋縄ではいきません。

問題は、これがsystemdのdocoが貧しいよりも悪い別の機会であるということです。まったくありません。 systemdの人々によって書かれた systemd-stdio-bridgeのマニュアルページ はまったくありません。したがって、システム管理者の最初の手段であるマニュアルを読むことは役に立ちません。 ( これはsystemd担当者の意図によるものです 、彼らはユースケースで実行中のプログラムを特定したいシステム管理者を含めていません。)

システム管理者が、プログラムがsystemd-bus-proxydと呼ばれるフェーズを通過したことを知るのに役立つ場合があります。このフェーズには、マニュアルページがありました。それとマニュアルページの両方がsystemdから削除されましたが、 古いプログラムが後でsystemd開発者のDavid Herrmannによって戻されたとき の場合、マニュアルページは一緒に復元されませんでした。 (注意して、掘り下げると、systemd-bus-proxydの古いマニュアルページに、systemd-stdio-bridgeの現在のコマンドラインの使用法が正しく記述されていないことに注意してください。)

Systemdの開発者がプロ​​グラムと一緒にdocoを検討した場合、現在のバグを1つ見つけた可能性があります。特定の状況でsystemctlsystemd-stdio-bridgeがサポートしないオプションを渡し、systemd-stdio-bridgesystemctlが使用しないさまざまなオプションをサポートします。

「このドキュメントに記載されていないsd_bus_set_addressのものは何ですか?」

Peter Wullingerのメモの1つは、これは文書化されていないということです。これは、少なくともsystemd-stdio-bridgeプログラムのコードを読み取ろうとするシステム管理者の場合にも当てはまります。これはコンパイルされたCプログラムであり、解釈されたスクリプト言語で書かれたものではありません。 Peter Wullingerが指摘するように、sd_bus_set_address()関数の呼び出しに依存しています。 systemdの人々はsd_bus_set_address() のマニュアルページを提供せず、他のsystemdマニュアルページにぶら下がっているハイパーリンクを残します(- the sd_bus_new() manualからのハイパーリンクなど) page たとえば)。

バグの解析

Peter Wullingerが「エスケープ、パース、エスケープされていないバグ」であると考えているものは、最初は明確ではありませんでした。しかし、内部では多くの解析が行われています。 systemdのデスクトップバスライブラリが、構成部品から "unixexec:path=ssh,argv1=-xT,argv2=--,argv3=account%40Host,argv4=systemd-stdio-bridge,arg5=--machine=fred"などの文字列を1か所で作成し、それらを別の場所の構成部品に戻すために解析することだけが重要です。そして、ダニエルJ.バーンスタイン(他の多くの人の間で)から、解析を回避するように設計していることを知っています。次に、アンマーシャリングして機械可読形式に戻すことをお勧めします。

Peter Wullingerがargv2=--が存在する理由について言及していたことがわかりました。もちろん、これはよく知られた問題であり、あまりに広く例示されているとは悲しいことです。ただし、前述の余分なシリアル化と逆シリアル化における追加のより微妙な解析関連の問題は、システムの非常にその場しのぎの性質です。 argv3で渡される等号文字は%3dとしてエスケープされることに注意してください。ただし、arg5=--machine=の等号はエスケープされません。シリアライゼーションは、デシリアライゼーションと同じ規則に従いません。このようにして、バグとセキュリティの問題が発生します。これは、ダニエルJ.バーンスタインが最初に解析しないことで回避することを推奨したまさにその1つです。

車輪の再発明

もちろん、systemd-stdio-bridgeは、十分な丸みを持たせるためにすべてのコーナーをノックオフしていないホイールの再発明であるという概念があります。結局のところ、前述のとおり、OpenSSHには、リモートホストからローカルマシンへのSSH接続を介してローカルドメインソケットへのアクセスを転送するための、はるかに広く使用およびテストされている組み込みメカニズムがあります。 (これは、systemd開発者のDavid Herrmannがsystemd-stdio-bridgeプログラムを再導入する前の年にリリースされたOpenSSH 6.7以降で使用されています。このパッチは、systemdが存在する前の2006年から存在します。)

これに対抗することは2つのことです。

まず、リモートでプログラムを生成し、SSH接続を介して送信される標準の入出力を介してプログラムと通信することは、SSHの珍しい使用法ではありません。結局のところ、それは物事を行うrexecモデルです。

次に、ローカルドメインソケットの転送は慎重に行う必要があります。標準のI/Oメカニズムでは、他のD-Busクライアントプログラムは(デバッグアクセスのようなトリックがなければ)転送メカニズムを使用して、リモートのD-Busブローカーに接続できません。ただし、前述のメカニズムは次のことに注意する必要があります。

  • ユーザー(およびスーパーユーザー)のプロセスのみがローカルプロキシソケットにアクセスできるように、ユーザー以外のユーザーに/run/user/user/account@Host/へのアクセスを許可しない
  • /run/user/user/がユーザー以外の誰かによって書き込み可能にならないように保護し、他の誰も一緒に来て、/run/user/user/account@Hostをこっそりとシンボリックリンクに置き換えたり、他のそのようなトリックを実行したりしないようにします。
  • /run/user/user/account@Host/bussystemctlの複数の呼び出しの間で衝突しないように注意してください(これは、busだけでなく、ローカルで一意の名前を使用することで実行できます)

参考文献

17
JdeBP

Systemdのドキュメントとソースコードの山を掘り下げた後に作成された短いツイートについて詳しく説明します(トーンを説明する可能性のある楽しいものはありません)。

すべてが this Tweet によってトリガーされました。これは、systemdが(メイン開発者が何度も指摘したように)すべての入力を検証しないことを示しています。

_systemctl --Host <Host>_ ドキュメントに記載されています 指定した操作をssh経由でリモートで実行します。

これがどのように機能するか

  1. systemctlは、Hostパラメータを sd_bus_open_system_remote() に渡します。これは、ドキュメントに記載されていない機能( バグレポート )-としても supports です。 = _<hostspec>:<machine>_表記を使用して、特定のコンテナ内のリモートホスト上のバスに接続するように指示します。

  2. sd_bus_open_system_remote()は、特別なバスアドレス_unixexec:path=ssh,argv1=-xT,argv2=--,argv3=<hostname>,argv4=systemd-stdio-bridge <container>_を作成します。これは、_$PATH_からsshを選択し、ターゲットマシン上のターゲットユーザーのリモート_systemd-stdio-bridge_から_$PATH_を選択することに注意してください。この特別なバスアドレスは、dbusの仕様と参照実装に追加されたようです systemd作成者の1人が

  3. この文字列は bus_start_address() によって(まだローカルに)解析され、任意のdbusプロキシコマンドをサポートします。 unixexec

  4. そして最後に、これは bus_start_address() をトリガーして、提供されたコマンドラインを実行し、そのプログラムのstdin/stdoutへのパイプを介してdbusを実行します。

私の考えでは、これは文書化されていない間接化の3つのレイヤーであり、_ssh <Host> systemctl --machine <machine>_でも取得できる単純な便利な機能を取得します。

このような暗黙の魔法により、通常、内部のバグサーチャーが自動操縦になります。

まあ、それはありましたが、それは重要ではありません: 最近のコミット の前に、systemctlは最初の_:_より後のすべてをホスト名から取り除きますが、その他すべてを最初のコマンドラインとしてsshに渡します引数。これはまだローカルで実行されており、コマンドラインからは非常に明白であるため、それほど問題とは思われません。

しかし、すべての複雑な性質を法として、リモートプロキシを持つことは、おそらくこれを処理するより安全な方法の1つです。 _-L_は、SSHポート転送とローカルソケットの適切なクリーンアップと適切なセキュリティを有効にする必要があるため、問題があります。 _-W_は、UNIXドメインソケットをサポートしていません(現時点では)。少なくとも現在の方法では、ForceCommandを使用できます。

本当のセキュリティの脅威は、プロセス全体が本質的に文書化されていない自動化されたプロセスで明示的に実行できるものを置き換え、途中でかなりの数の仮定をハードコード化することにあると考えられます。

4
dhke