setuid
パーミッションビットは、エグゼキュータではなく所有者の有効なユーザーIDでプログラムを実行するようにLinuxに指示します。
> cat setuid-test.c
#include <stdio.h>
#include <unistd.h>
int main(int argc, char** argv) {
printf("%d", geteuid());
return 0;
}
> gcc -o setuid-test setuid-test.c
> ./setuid-test
1000
> sudo chown nobody ./setuid-test; sudo chmod +s ./setuid-test
> ./setuid-test
65534
ただし、これは実行可能ファイルにのみ適用されます。シェルスクリプトはsetuidビットを無視します:
> cat setuid-test2
#!/bin/bash
id -u
> ./setuid-test2
1000
> sudo chown nobody ./setuid-test2; sudo chmod +s ./setuid-test2
> ./setuid-test2
1000
ウィキペディアによると:
セキュリティ上の欠陥の可能性が高まるため、多くのオペレーティングシステムは、実行可能なシェルスクリプトに適用されるときにsetuid属性を無視します。
私がこれらのリスクを受け入れるつもりだと仮定すると、Linuxにシェルスクリプトで実行可能ファイルと同じようにsetuidビットを処理するように指示する方法はありますか?
そうでない場合、この問題の一般的な回避策はありますか?私の現在の解決策は、sudoers
を追加することです ALL
を許可するエントリ NOPASSWD
を使用して、特定のスクリプトを実行したいユーザーとして実行するには パスワードプロンプトを回避します。その主な欠点は、sudoers
の必要性です。 これを実行するたびにエントリを入力し、呼び出し元がsudo some-script
を実行する必要がある some-script
の代わりに
承認された回答:
Linuxは、解釈されたすべての実行可能ファイル(つまり、#!
で始まる実行可能ファイル)のsetuid¹ビットを無視します。 ライン)。 comp.unix.questions FAQは、setuidシェルスクリプトのセキュリティ問題について説明しています。これらの問題には、シバン関連とシェル関連の2種類があります。以下で詳細を説明します。
セキュリティを気にせず、setuidスクリプトを許可したい場合は、Linuxでカーネルにパッチを適用する必要があります。 3.xカーネルの時点で、install_exec_creds
への呼び出しを追加する必要があると思います load_script
で 関数、open_exec
を呼び出す前 、しかし私はテストしていません。
Setuid shebang
シバンの方法に固有の競合状態があります(#!
)通常は実装されます:
- カーネルが実行可能ファイルを開き、
#!
で始まることを検出します。 。 - カーネルは実行可能ファイルを閉じ、代わりにインタプリタを開きます。
- カーネルは、スクリプトへのパスを引数リストに挿入します(
argv[1]
として) )、インタプリタを実行します。
この実装でsetuidスクリプトが許可されている場合、攻撃者は既存のsetuidスクリプトへのシンボリックリンクを作成して実行し、カーネルがステップ1を実行した後、インタープリターが最初の引数を開きます。このため、ほとんどのユニスはsetuidビットを無視します 彼らがシバンを検出したとき。
この実装を保護する1つの方法は、インタープリターがスクリプトファイルを開くまで、カーネルがスクリプトファイルをロックすることです(これにより、ファイルのリンク解除や上書きを防ぐだけでなく、パス内のディレクトリの名前を変更することもできなくなります)。しかし、UNIXシステムは必須のロックを敬遠する傾向があり、シンボリックリンクは正しいロック機能を特に困難かつ侵襲的にします。誰もこのようにやっていないと思います。
いくつかのUNIXシステム(主にOpenBSD、NetBSD、Mac OS X、これらはすべてカーネル設定を有効にする必要があります)は、 secure setuid shebangを実装しています。 追加機能の使用:パス/dev/fd/N
ファイル記述子Nですでに開かれているファイルを指します (したがって、/dev/fd/N
dup(N)
)。多くのUNIXシステム(Linuxを含む)には/dev/fd
があります ただし、setuidスクリプトではありません。
- カーネルが実行可能ファイルを開き、
#!
で始まることを検出します。 。実行可能ファイルのファイル記述子が3であるとしましょう。 - カーネルがインタプリタを開きます。
- カーネルは
/dev/fd/3
を挿入します 引数リスト(argv[1]
として) )、インタプリタを実行します。
SvenMascheckのシバンページ setuidのサポートなど、ユニス全体のシバンに関する多くの情報があります。
Setuidインタープリター
OSがsetuidshebangをサポートしているため、またはネイティブのバイナリラッパー(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マニュアルで説明されています。以前は、setuidperlスクリプトに
#!/usr/bin/suidperl -wT
が必要でした。#!/usr/bin/perl -wT
の代わりに 、ただし、最近のほとんどのシステムでは、#!/usr/bin/perl -wT
十分です。
ネイティブバイナリのラッパーを使用しても、これらの問題を防ぐためにそれ自体は何もしませんことに注意してください。 。実際、状況を悪化させる可能性があります 、ランタイム環境が特権で呼び出されたことを検出できず、ランタイム構成可能性をバイパスできない可能性があるためです。
ネイティブバイナリラッパーは、ラッパーが環境をサニタイズする場合、シェルスクリプトを安全にすることができます 。スクリプトは、(現在のディレクトリなどについて)あまり多くの仮定をしないように注意する必要がありますが、これは当てはまります。環境をサニタイズするように設定されている場合は、sudoを使用できます。変数をブラックリストに登録するとエラーが発生しやすいため、常にホワイトリストに登録してください。 sudoを使用する場合は、env_reset
を確認してください。 オプションがオンになっている場合、そのsetenv
がオフで、そのenv_file
およびenv_keep
無害な変数のみが含まれています。
TL、DR:
- Setuidシバンは安全ではありませんが、通常は無視されます。
- 特権を使用して(sudoまたはsetuidを介して)プログラムを実行する場合は、ネイティブコードまたはperlを作成するか、環境をサニタイズするラッパー(
env_reset
を使用したsudoなど)を使用してプログラムを起動します。 オプション)。
¹この説明は、「setuid」を「setuid」に置き換えた場合にも同様に当てはまります。これらは両方とも、スクリプト上のLinuxカーネルによって無視されます