Linuxは、解釈されたすべての実行可能ファイル(つまり、#!
行で始まる実行可能ファイル)のsetuid¹ビットを無視します。comp.unix.questionsよくあるご質問は、 setuidさシェルスクリプトでのセキュリティ上の問題を説明しています。これらの問題には、シバン関連とシェル関連の2種類があります。以下で詳細を説明します。
セキュリティを気にせず、setuidスクリプトを許可したい場合、Linuxでは、カーネルにパッチを適用する必要があります。3.xカーネルの時点で、の呼び出しの前install_exec_creds
に、load_script
関数にの呼び出しを追加する必要があると思いますがopen_exec
、テストしていません。
セイド・シバン
shebang(#!
)の通常の実装方法に固有の競合状態があります。
- カーネルは実行可能ファイルを開き、で始まることを見つけ
#!
ます。
- カーネルは実行可能ファイルを閉じ、代わりにインタープリターを開きます。
- カーネルは、スクリプトへのパスを引数リスト(as
argv[1]
)に挿入し、インタープリターを実行します。
この実装でsetuidスクリプトが許可されている場合、攻撃者は、既存のsetuidスクリプトへのシンボリックリンクを作成して実行し、カーネルがステップ1を実行した後、インタープリターが移動する前にリンクを変更することにより、任意のスクリプトを呼び出すことができます最初の引数を開きます。このため、ほとんどの大学は、シバンを検出するとsetuidビットを無視します。
この実装を保護する1つの方法は、インタープリターが開くまでカーネルがスクリプトファイルをロックすることです(これにより、ファイルのリンク解除または上書きだけでなく、パス内のディレクトリ名の変更も防止する必要があります)。しかし、UNIXシステムは必須のロックから遠ざかる傾向があり、シンボリックリンクは正しいロック機能を特に難しく侵襲的にします。私は誰もこの方法でそれを行うとは思わない。
(有効にする設定のカーネルを必要とするすべては、主にOpenBSD、NetBSDのとMac OS X、)いくつかのUNIXシステムでは、実装安全なsetuidさシェバングを追加機能を使用する:パスは、既にファイルディスクリプタで開かれたファイルを参照するN(そう開口部がありますにほぼ等しい)。多くのUNIXシステム(Linuxを含む)にはsetuidスクリプトがありますが、ありません。/dev/fd/N
/dev/fd/N
dup(N)
/dev/fd
- カーネルは実行可能ファイルを開き、で始まることを見つけ
#!
ます。実行可能ファイルのファイル記述子が3だとしましょう。
- カーネルがインタープリターを開きます。
- カーネル
/dev/fd/3
は引数リストを(asとしてargv[1]
)挿入し、インタープリターを実行します。
Sven Mascheckのshebangページには、 setuidのサポートなど、大学全体のshebangに関する多くの情報があります。
Setuidインタープリター
OSがsetuid shebangをサポートしているため、またはネイティブバイナリラッパー(などsudo
)を使用しているため、プログラムをrootとして実行できたと仮定します。セキュリティホールを開けましたか?たぶん。ここでの問題は、解釈されたプログラムとコンパイルされたプログラムに関するものではありません。問題は、ランタイムシステムが特権で実行された場合に安全に動作するかどうかです。
動的にリンクされたネイティブバイナリ実行可能ファイルは、プログラムに必要な動的ライブラリをロードする動的ローダー(例/lib/ld.so
)によって解釈されます。多くの大学でLD_LIBRARY_PATH
は、環境(環境変数の共通名)を使用して動的ライブラリの検索パスを構成し、実行されたすべてのバイナリに追加のライブラリをロードすることもできます(LD_PRELOAD
)。プログラムの呼び出し側は、(他の戦術の中に)特別に細工libc.so
したものを配置することにより、そのプログラムのコンテキストで任意のコードを実行できます$LD_LIBRARY_PATH
。すべての健全なシステムはLD_*
、setuid実行可能ファイルの変数を無視します。
でシェルなどのsh、CSHおよび誘導体のような、環境変数は自動的にシェルパラメータとなります。PATH
、などのパラメーターを介してIFS
、スクリプトの呼び出し側はシェルスクリプトのコンテキストで任意のコードを実行する機会が多くあります。一部のシェルは、スクリプトが特権で呼び出されたことを検出した場合、これらの変数を正常なデフォルトに設定しますが、信頼できる特定の実装があることはわかりません。
ほとんどのランタイム環境(ネイティブ、バイトコードまたはインタープリター)に同様の機能があります。setuid実行可能ファイルに特別な予防措置を講じる人はほとんどいませんが、ネイティブコードを実行するものは多くの場合、動的リンク(予防措置をとる)よりも手の込んだことはしません。
Perlは注目に値する例外です。これは、明示的にsetuidスクリプトサポート安全な方法では。実際、OSがスクリプトのsetuidビットを無視した場合でも、スクリプトはsetuidを実行できます。これは、perlに必要なチェックを実行し、目的の特権で目的のスクリプトでインタープリターを再起動するsetuidルートヘルパーが付属しているためです。これはperlsecマニュアルで説明されています。以前はsetuid perlスクリプトがの#!/usr/bin/suidperl -wT
代わりに必要でした#!/usr/bin/perl -wT
が、ほとんどの最新のシステムで#!/usr/bin/perl -wT
は十分です。
ネイティブバイナリラッパーを使用しても、これらの問題を防ぐためにそれ自体は何もしないことに注意してください。実際、それは状況を悪化させる可能性があります。これは、ランタイム環境が特権で呼び出されたことを検出し、そのランタイム構成可能性をバイパスすることを妨げる可能性があるためです。
ネイティブバイナリラッパーは、ラッパーが環境をサニタイズする場合、シェルスクリプトを安全にすることができます。スクリプトは、あまりにも多くの仮定を行わないように注意する必要があります(たとえば、現在のディレクトリについて)。環境をサニタイズするように設定されていれば、これにsudoを使用できます。変数をブラックリストに登録するとエラーが発生しやすくなるため、常にホワイトリストに登録してください。sudoのでは、ということを確認するenv_reset
オプションがオンになって、それがされてsetenv
オフになって、そのenv_file
とenv_keep
だけ無害な変数が含まれています。
TL、DR:
- Setuid shebangは安全ではありませんが、通常は無視されます。
- (sudoまたはsetuidを介して)特権を使用してプログラムを実行する場合、ネイティブコードまたはperlを記述するか、環境をサニタイズするラッパーを使用してプログラムを起動します(
env_reset
オプションを使用したsudoなど)。
¹ この説明は、「setuid」を「setgid」に置き換えた場合にも同様に適用されます。これらは両方とも、スクリプト上のLinuxカーネルによって無視されます