環境変数によって識別されるディレクトリ内のファイルへの安全なアクセス?
-
10-07-2019 - |
質問
環境変数によって (部分的に) 指定されたパスを介したファイル アクセスのセキュリティを扱うコード (特に Unix とその亜種向け) を誰かが指摘できますか? Windows ソリューションにも興味がありますか?
これは非常に長い質問です。これが SO パラダイムにどの程度適合するかわかりません。
次のシナリオを考えてみましょう。
背景:
- ソフトウェア パッケージ PQR は、ユーザーが選択した場所にインストールできます。
- 環境変数 $PQRHOME は、インストール ディレクトリを識別するために使用されます。
- デフォルトでは、$PQRHOME の下にあるすべてのプログラムとファイルは、特別なグループ pqrgrp に属します。
- 同様に、$PQRHOME の下にあるすべてのプログラムとファイルは、特別なユーザー pqrusr またはユーザー root (これらは SUID ルート プログラム) に属します。
- いくつかのプログラムは SUID pqrusr です。さらにいくつかのプログラムは SGID pqrgrp です。
- ほとんどのディレクトリは pqrusr によって所有され、pqrgrp に属します。一部は他のグループに属することができ、それらのグループのメンバーはソフトウェアに関する追加の権限を取得します。
- 特権付き実行可能ファイルの多くは、pqrgrp のメンバーではない人が実行する必要があります。プログラムは、この問題とは直接関係のない難解なルールによって、ユーザーがプログラムの実行を許可されていることを検証する必要があります。
- 一部の特権プログラムは、起動後、昇格された特権を保持する必要があります。これは、それらが存続期間中に多くのユーザーの代わりに動作する可能性がある長時間実行されるデーモンであるためです。
- プログラムには、さまざまな難解な理由により、ディレクトリを $PQRHOME に変更する権限がありません。
現在のチェック中:
- プログラムは現在、$PQRHOME とその下の主要なディレクトリが「安全」であることをチェックしています (pqrusr が所有し、pqrgrp に属し、パブリック書き込みアクセス権を持っていません)。
- その後、プログラムは環境変数の完全な値を介して $PQRHOME 下のファイルにアクセスします。
- 特に、G11N と L10N は、「安全な」ディレクトリ内のファイルにアクセスし、$PQRHOME と既知の部分構造 (たとえば、$PQRHOME/g11n/en_us/messages.l10n)。
$PQRHOME の「インストール時の」値が /opt/pqr であると仮定します。
既知の攻撃:
- 攻撃者は PQRHOME=/home/攻撃者/pqr を設定します。
- これは実際には /opt/pqr へのシンボリックリンクなので、pqr-victim と呼ばれる PQR プログラムの 1 つがディレクトリをチェックすると、正しい権限が与えられます。
- セキュリティ チェックが正常に完了した直後に、攻撃者はシンボリック リンクを変更して、/home/攻撃者/bogus-pqr を指すようにします。これは明らかに攻撃者の制御下にあります。
- pqr-victim が安全であるはずのディレクトリにあるファイルにアクセスすると、悲惨なことが起こります。
現在、PQR が説明どおりに動作し、大規模なパッケージ (数百万行のコードがあり、さまざまなコーディング標準に合わせて 10 年以上にわたって開発され、いずれにしても頻繁に無視されてきました) であることを考慮すると、この問題を修復するにはどのような手法を使用しますか?問題?
既知のオプションには次のものがあります。
- すべての書式設定呼び出しを変更して、実際の引数を書式文字列と照合してチェックする関数を使用し、関数に渡される実際の型を示す追加の引数を使用します。(これは注意が必要で、変更するフォーマット操作の数が非常に多いため、潜在的にエラーが発生しやすくなります。ただし、チェック機能自体が適切であれば、正常に動作します。)
- PQRHOME への直接パスを確立し、セキュリティを検証し (詳細は後述)、安全でない場合は開始を拒否し、その後は $PQRHOME の値ではなく直接パスを使用します (値が異なる場合)。(これには、$PQRHOME を使用するすべてのファイル操作が、getenv() からの値ではなく、マップされたパスを使用する必要があります。たとえば、これには、ファイルが $PQRHOME/some として参照されるたびに、/home/攻撃者/pqr が /opt/pqr へのシンボリックリンクであること、/opt/pqr へのパスが安全であることをソフトウェアが確立する必要があります。 /thing の場合、使用される名前は /home/攻撃者/pqr/some/thing ではなく、/opt/pqr/some/thing になります。これは大規模なコード ベースであるため、修正するのは簡単ではありません。)
- $PQRHOME 上のすべてのディレクトリが、シンボリックリンクを介した追跡も含めて安全であることを確認し (詳細は後述)、安全でないものがあればソフトウェアは起動を拒否します。
- ソフトウェアのインストール場所へのパスをハードコーディングします。(これは PQR では機能しません。少なくとも、テストは地獄になります。ユーザーにとって、これは、インストールできるバージョンは 1 つだけであり、アップグレードなどは並行して実行する必要があることを意味します。これは PQR では機能しません。)
安全なパスの提案された基準:
- 各ディレクトリの所有者は信頼されている必要があります。(理論的根拠:所有者はいつでも権限を変更できるため、所有者はソフトウェアのセキュリティを侵害するような変更を無作為に行わないという信頼を得る必要があります。)
- 各ディレクトリについて、グループは書き込み権限を持たないか (そのため、グループのメンバーはディレクトリの内容を変更できません)、またはグループが信頼されている必要があります。(理論的根拠:グループ メンバーがディレクトリを変更できる場合は、ソフトウェアのセキュリティを破る可能性があるため、グループ メンバーがディレクトリを変更できないようにするか、変更しないと信頼される必要があります。)
- 各ディレクトリについて、「others」はディレクトリに対する書き込み権限を持っていてはなりません。
- デフォルトでは、ユーザー root、bin、sys、および pqrusr は信頼できます (bin と sys が存在する場合)。
- デフォルトでは、GID=0 のグループ (ルート、ホイール、またはシステムとしてさまざまに知られています)、bin、sys、および pqrgrp が信頼できます。さらに、ルート ディレクトリを所有するグループ (MacOS X では admin と呼ばれます) は信頼できます。
POSIX関数 realpath()
/home/攻撃者/pqr を /opt/pqr にマッピングするマッピング サービスを提供します。セキュリティ チェックは実行されませんが、解決されたパス上でのみ実行する必要があります。
では、これらすべてを背景として、セキュリティを確保するために漠然と関連する循環を通過する既知のソフトウェアはあるのでしょうか?これは過度に偏執的でしょうか?(もしそうなら、その理由は何ですか?そして本当にそう思いますか?)
編集:
さまざまなコメントをありがとうございます。
@S.ロット:この攻撃(質問で概説されている)は、少なくとも 1 つの setuid ルート プログラムが、(特権のない)ユーザーが選択したフォーマット文字列を使用できるようになり、少なくともプログラムをクラッシュさせることができるため、ルート シェルを取得できる可能性が高いことを意味します。幸いなことに、ローカル シェル アクセスが必要です。遠隔攻撃ではありません。そこに到達するには無視できない量の知識が必要ですが、その専門知識が「世の中にない」と考えるのは賢明ではないと私は考えています。
つまり、私が説明しているのは「フォーマット文字列の脆弱性」であり、既知の攻撃経路には、プログラムが安全なメッセージ ファイルにアクセスしていると思わせながら、実際にはメッセージ ファイル (フォーマット文字列を含む) を使用するように偽装することが含まれています。ソフトウェアの制御下ではなく、ユーザーの制御下にあります。
解決
オプション 2 は、新しい値を書き込んだ場合に機能します。 $PQRHOME
実際のパスを解決した後、そのセキュリティを確認してください。そうすれば、その後変更する必要のあるコードはほとんどなくなります。
setuid 権限を保持する限り、実際のユーザーからの入力を伴う操作が実際の uid で実行されるように、何らかの権限を分離できれば役立ちます。特権プロセスと Real-Uid プロセスは、 socketpair
またはそのようなもの。
他のヒント
まあ、それは 音 偏執的ですが、そうなるかどうかは、アプリケーションがどのシステムで実行されているか、および攻撃者がどのような損害を与えることができるかによって決まります。
したがって、ユーザーベースが敵対的である可能性があり、被害が非常に大きい可能性がある場合は、オプション 4 を選択しますが、その欠点を取り除くために次のように変更します。
関連する事柄を 2 つ引用させてください。
1)
プログラムは現在、$ PQRHOMEとキーディレクトリを その下には「安全」( pqrusrが所有し、 pqrgrpに属し、公開されていません 書き込みアクセス)。
2)
その後、プログラムは以下を介して$ PQRHOMEの下のファイルにアクセスします。 環境変数の値。
実際にフルパスをハードコーディングする必要はありません。1) で述べた「プログラム」から 2) で述べたファイルが存在するパスまでの相対パスだけをハードコーディングできます。
管理すべき問題:
a) 「攻撃者がアクセスできる」ものがないことを確認する必要があります (例:シンボリックリンクの観点から) 実行可能ファイルのパスとファイルのパスの間
b) 実行可能ファイルが自身のパスを信頼できる方法でチェックしていることを確認する必要がありますが、これは私が知っているすべての Unix で問題になるはずはありません (ただし、すべてを知っているわけではありませんし、Windows についても知りません)まったく)。
3 番目のコメント後に編集:
OS が /proc をサポートしている場合、syslink /proc/${pid}/exe が b) を解決する最良の方法です。
寝た後に編集:
インストールは「安全な」プロセスですか?その場合は、(インストール時に) ラッパー スクリプトを作成できます。このスクリプトは実行可能である必要がありますが、書き込み可能ではありません (読み取り不可能である可能性もあります)。$PQRHOME 環境変数を「安全な」値に設定し、実際のプログラムを呼び出します (最終的には他の便利な機能も実行する可能性があります)。UNIX では、実行中のプロセスの環境変数 できない 実行中のプロセス以外のものによって変更される可能性はありますが、安全です (もちろん環境変数 できる 親に変えられる 前に プロセスが開始されます)。ただし、このアプローチが Windows で機能するかどうかはわかりません。