方法シバンに固有の競合状態があります (#!
) が通常実装されます:
#!
で始まることを確認します。 .argv[1]
のように) )、インタプリタを実行します。この実装で setuid スクリプトが許可されている場合、攻撃者は、既存の setuid スクリプトへのシンボリック リンクを作成して実行し、カーネルが手順 1 を実行した後、インタプリタがそのスクリプトを回避する前にリンクを変更するように手配することで、任意のスクリプトを呼び出すことができます。最初の引数を開きます。このため、最新のユニックスはすべて、シバンを検出したときに setuid ビットを無視します。
この実装を保護する 1 つの方法は、インタープリターがスクリプト ファイルを開くまでカーネルがスクリプト ファイルをロックすることです (これにより、ファイルのリンク解除や上書きだけでなく、パス内のディレクトリの名前変更も防止する必要があることに注意してください)。しかし、UNIX システムは強制的なロックを敬遠する傾向があり、シンボリック リンクを使用すると、正しいロック機能が特に困難で侵襲的になります。誰もこのようにしないと思います。
一部の UNIX システムでは、追加機能を使用してセキュアな setuid シバンを実装しています:パス /dev/fd/N
ファイル記述子 N ですでに開かれているファイルを参照します (だから /dev/fd/N
を開く dup(N)
とほぼ同等です )。
#!
で始まることを確認します。 .実行可能ファイルのファイル記述子が 3 だとしましょう。/dev/fd/3
を挿入します 引数リスト (argv[1]
など) )、インタプリタを実行します。
Linux を含む最新の UNIX バリアントはすべて /dev/fd
を実装しています ですが、ほとんどの場合、setuid スクリプトは許可されていません。デフォルト以外のカーネル設定を有効にすると、OpenBSD、NetBSD、および Mac OS X でサポートされます。 Linux では、人々はそれを可能にするパッチを書きましたが、それらのパッチは決してマージされませんでした。 Sven Mascheck のシバン ページには、setuid のサポートを含む、ユニックス全体のシバンに関する多くの情報があります。
さらに、昇格された特権で実行されるプログラムには固有のリスクがあり、インタープリターが特別に設計されていない限り、通常、高レベルのプログラミング言語では制御が困難です。その理由は、プログラム自体のコードがこのデータをサニタイズする機会を得る前に、プログラミング言語ランタイムの初期化コードが、より低い特権の呼び出し元から継承されたデータに基づいて、昇格された特権でアクションを実行する可能性があるためです。 C ランタイムはプログラマーにとってほとんど何もしないので、C プログラムは何か問題が発生する前にデータを制御してサニタイズするより良い機会を得ることができます。
OS が setuid shebang をサポートしているか、ネイティブ バイナリ ラッパー (sudo
など) を使用しているため、プログラムをルートとして実行できたとします。 )。セキュリティホールを開けていませんか?多分。ここでの問題はではない 解釈されたプログラムとコンパイルされたプログラムについて。問題は、ランタイム システムが特権で実行された場合に安全に動作するかどうかです。
-
動的にリンクされたネイティブバイナリ実行可能ファイルは、動的ローダーによって解釈されます (例:
/lib/ld.so
)、プログラムに必要な動的ライブラリをロードします。多くの Unice では、動的ライブラリの検索パスを環境 (LD_LIBRARY_PATH
) で構成できます。 は環境変数の一般的な名前です)、実行されたすべてのバイナリに追加のライブラリをロードします (LD_PRELOAD
)。プログラムの呼び出し元は、特別に細工されたlibc.so
を配置することにより、そのプログラムのコンテキストで任意のコードを実行できます。$LD_LIBRARY_PATH
で (他の戦術の中でも)。すべての正常なシステムはLD_*
を無視します setuid 実行可能ファイルの変数。 -
sh、csh、および派生物などのシェルでは、環境変数は自動的にシェル パラメーターになります。
PATH
などのパラメータを介して 、IFS
など、スクリプトの呼び出し元には、シェル スクリプトのコンテキストで任意のコードを実行する機会が数多くあります。一部のシェルは、スクリプトが特権で呼び出されたことを検出すると、これらの変数を正常なデフォルトに設定しますが、信頼できる特定の実装があるかどうかはわかりません. -
ほとんどのランタイム環境 (ネイティブ、バイトコード、またはインタープリター) には、同様の機能があります。 setuid 実行可能ファイルで特別な予防措置を講じている人はほとんどいませんが、ネイティブ コードを実行するものは、動的リンク (予防措置を講じます) よりも手の込んだことはほとんど行いません。
-
Perl は顕著な例外です。安全な方法で setuid スクリプトを明示的にサポートします。実際、OS がスクリプトの setuid ビットを無視したとしても、スクリプトは setuid を実行できます。これは、必要なチェックを実行し、必要な権限で目的のスクリプトのインタープリターを再起動する setuid ルート ヘルパーが perl に同梱されているためです。これは perlsec マニュアルで説明されています。以前は setuid perl スクリプトが必要でした
#!/usr/bin/suidperl -wT
#!/usr/bin/perl -wT
の代わりに 、しかし最近のほとんどのシステムでは#!/usr/bin/perl -wT
で十分です。
ネイティブ バイナリ ラッパーを使用しても、それ自体ではこれらの問題を防ぐことはできないことに注意してください。実際、ランタイム環境が特権で呼び出されていることを検出できず、ランタイム環境の構成可能性をバイパスする可能性があるため、状況が悪化する可能性があります。
ネイティブ バイナリ ラッパーは、ラッパーが環境をサニタイズする場合、シェル スクリプトを安全にすることができます。スクリプトは、あまりにも多くの仮定 (たとえば、現在のディレクトリについて) を行わないように注意する必要がありますが、これは当てはまります。環境をサニタイズするように設定されている場合は、これに sudo を使用できます。変数をブラックリストに登録するとエラーが発生しやすいため、常にホワイトリストに登録してください。 sudo を使用して、env_reset
が オプションがオンになっている、その setenv
オフで、その env_file
と env_keep
無害な変数のみを含みます。
これらすべての考慮事項は、setuid、setgid、setcap などの特権の昇格に等しく適用されます。
https://unix.stackexchange.com/questions/364/allow-setuid-on-shell-scripts/2910#2910 からリサイクル
主な理由
<ブロック引用>多くのカーネルは、新しく exec() されたプロセスが setuid になったときと、コマンド インタープリターが起動したときとの間に、選択した別の実行可能ファイルとシェルスクリプトを交換できる競合状態に苦しんでいます。あなたが十分に粘り強ければ、理論的には、カーネルに任意のプログラムを実行させることができます.
そのリンクで見つかった他の理由と同様に(ただし、カーネルの競合状態が最も有害です)。もちろん、スクリプトはバイナリ プログラムとは異なる方法でロードされますが、そこに問題が潜んでいます。
この 2001 年の Dr. Dobb の記事を読むと面白いかもしれません。この記事では、より安全な SUID シェル スクリプトを作成するための 6 つのステップを経て、ステップ 7 に到達するだけです:
<ブロック引用>レッスン 7 -- SUID シェル スクリプトを使用しない
すべての作業を行った後でも、安全な SUIDshell スクリプトを作成することはほぼ不可能です。 (ほとんどのシステムでは不可能です。) これらの問題のため、一部のシステム (Linux など) はシェルスクリプトで SUID を受け入れません。
この履歴では、競合状態が修正されたバリアントについて説明しています。リストはあなたが思っているよりも大きいです... しかし、setuid スクリプトは、他の問題のために、または安全なバリアントで実行しているか安全でないバリアントで実行しているかを思い出すよりも、それらを思いとどまらせる方が簡単であるため、依然として大部分が推奨されていません.
これは当時、Perl がそれを補うためにどれほど積極的にアプローチしたかを読むのに十分なほど大きな問題でした.