許可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プロパティを無視します。
このようなリスクを負うことになると仮定すると、実行ファイルと同様に、シェルスクリプトでもsetuidビットを同じように処理するようにLinuxに指示する方法はありますか?
そうでない場合、この問題に対する一般的な回避策はありますか?現在の回避策は、パスワードプロンプトを避けるために特定のスクリプトを実行したいユーザーとして実行できるsudoers
ようにエントリを追加することです。この方法の主な欠点は、これを行うたびに項目を入力する必要があり、呼び出し側は単に項目を入力するのではなく項目を入力する必要があることです。ALL
NOPASSWD
sudoers
sudo some-script
some-script
答え1
Linuxは、解釈されたすべての実行可能ファイル(つまり、lineで始まる実行可能ファイル)のsetuid1ビットを無視します#!
。これcomp.unix.questions よくある質問setuid シェルスクリプトのセキュリティ問題について説明しました。これらの問題は、Sheban関連の問題とShell関連の問題の2種類に分けられます。以下で詳しく説明します。
セキュリティに興味がなく、Linuxでsetuidスクリプトを許可するには、カーネルにパッチを適用する必要があります。 3.xカーネルから始めたら、以下を追加する必要があるようです。install_exec_creds
内部にload_script
関数を呼び出す前にテストopen_exec
しましたが、まだテストしていません。
セットイドシェイボン
#!
shebang( ) の一般的な実装には独自の競争条件があります。
- カーネルは実行可能ファイルを開き、ファイルが
#!
。 - カーネルは実行可能ファイルを閉じてインタプリタを開きます。
- カーネルはスクリプトパスを引数リスト(たとえば
argv[1]
)に挿入し、インタプリタを実行します。
この実装がsetuidスクリプトを許可する場合、攻撃者は既存のsetuidスクリプトへのシンボリックリンクを生成し、スクリプトを実行し、カーネルがステップ1を実行した後にインタプリタが実行を開始する前にリンクを変更するように調整します。スクリプトを呼び出すことができます。最初の引数を開始します。このため、ほとんどのUnixはsetuidビットを無視します。彼らがshebangを検出したとき。
この実装を安全にする1つの方法は、インタプリタがスクリプトファイルを開くまでカーネルがスクリプトファイルをロックすることです。 )。しかし、Unixシステムは強制ロックを避ける傾向があり、シンボリックリンクは適切なロック機能が特に困難で邪魔になる可能性があります。私は誰もそうは思いません。
一部のUnixシステム(主にOpenBSD、NetBSD、およびMac OS X、すべて有効にするにはカーネル設定が必要です)が実装されています。セキュリティ setuid shebangアドインの使用:パスは、ファイル記述子ですでに開いているファイルを参照します。/dev/fd/N
窒素(したがって、オープニングはほぼ同じです)。多くのUNIXシステム(Linuxを含む)にはsetuidスクリプトがありますが、ありません。/dev/fd/N
dup(N)
/dev/fd
- カーネルは実行可能ファイルを開き、.で始まるものを探します
#!
。実行ファイルのファイル記述子が3であると仮定します。 - カーネルがインタプリタを開きます。
- カーネルは
/dev/fd/3
引数リスト(例argv[1]
:)を挿入し、インタプリタを実行します。
Sven Mascheckのshebangページ以下を含む、unicesのshebangに関する多くの情報があります。setuid サポート。
Setuid通訳
sudo
オペレーティングシステムがsetuid shebangをサポートするか、デフォルトのバイナリラッパー(たとえば)を使用しているため、プログラムがrootとして実行されるように管理したとします。セキュリティホールを開けましたか?おそらく。ここで問題はいいえ通訳者とコンパイラについて。問題はあなたがランタイムシステム権限を使用して実行すると、動作は安全です。
動的にリンクされたデフォルトのバイナリ実行可能ファイルは、何らかの方法で生成されます。動的ローダー(例
/lib/ld.so
:)、プログラムに必要な動的ライブラリをロードします。多くのユニークでは、LD_LIBRARY_PATH
環境(環境変数の一般的な名前)を介して動的ライブラリの検索パスを設定でき、実行されたすべてのバイナリ(LD_PRELOAD
)に追加のライブラリをロードすることもできます。プログラム呼び出し元は、libc.so
特別に作成されたコード(他の戦略の中で)を配置して、そのプログラムのコンテキスト内で任意のコードを実行できます。$LD_LIBRARY_PATH
すべての正気システムは、LD_*
実行可能ファイルのsetuid変数を無視します。存在するシェルたとえば、sh、csh、およびその派生物では、環境変数は自動的にシェルパラメータになります。
PATH
などのパラメータにより、IFS
スクリプト呼び出し元はシェルスクリプトのコンテキストで任意のコードを実行する機会がたくさんあります。一部のシェルは、スクリプトが権限で呼び出されたことを検出すると、これらの変数を妥当なデフォルト値に設定しますが、私が信頼する特定の実装があるかどうかはわかりません。ほとんどのランタイム環境(ネイティブ、バイトコード、または解釈にかかわらず)同様の機能を持ちます。基本コードを実行する実行可能ファイルは通常、動的接続(予防措置を取る)よりも珍しい操作を実行しませんが、setuid実行可能ファイルで特別な予防措置を取る人はほとんどいません。
真珠注目すべき例外です。それsetuidスクリプトの明示的なサポート安全な方法で。実際、オペレーティングシステムがスクリプトの setuid ビットを無視しても、スクリプトは setuid を実行できます。これは、Perlが必要なチェックを実行し、必要な権限を持つ必須スクリプトのインタプリタを再度呼び出すsetuidルートヘルパープログラムに付属しているためです。これはペルセク手動。過去には
#!/usr/bin/suidperl -wT
代わりにsetuid perlスクリプトが必要でしたが、#!/usr/bin/perl -wT
ほとんどの最新システムでは#!/usr/bin/perl -wT
これで十分です。
ネイティブバイナリの使用に注意してください。ラッパー自体は、これらの問題を防ぐために何もしません。。実際に状況を作ることもできる悪いこれは、ランタイム環境が権限を持って呼び出されたことを検出できず、ランタイム構成機能をバイパスする可能性があるためです。
ネイティブバイナリラッパーは、ラッパーが次の場合にシェルスクリプトを安全にすることができます。環境を浄化する。スクリプトはあまりにも多くの仮定(たとえば、現在のディレクトリの仮定)をしないように注意する必要がありますが、それはすべてです。環境をクリーンアップするように設定されている場合は、sudoを使用してこれを実行できます。変数をブラックリストに追加するとエラーが発生しやすいため、常にホワイトリストに追加してください。 sudoを使用して、env_reset
オプションがオンになっているか、setenv
オフになっているか、無害な変数のみがenv_file
含まれていることを確認してください。env_keep
TL、博士:
- Setuid shebangは安全ではありませんが、しばしば見落とされます。
- sudoまたはsetuidを介して権限を使用してプログラムを実行する場合は、ネイティブコードまたはPerlを作成するか、環境をクリーンアップするラッパー(オプションを含むsudo
env_reset
)を使用してプログラムを起動してください。
↑この議論は、「setgid」を「setuid」に変更する場合にも適用されます。Linuxカーネルはスクリプトでこれを無視します。
答え2
この問題を解決する1つの方法は、setuidビットを使用できるプログラムからシェルスクリプトを呼び出すことです。
sudoに似ています。たとえば、Cプログラムでこれを行う方法は次のとおりです。
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
setuid( 0 ); // you can set it at run time also
system( "/home/pubuntu/setuid-test2.sh" );
return 0;
}
setuid-test2.cとして保存します。
これで
プログラムバイナリでsetuidを実行します。
su - nobody
[enter password]
chown nobody:nobody a.out
chmod 4755 a.out
これでこれを実行でき、他人の許可なしにスクリプトが実行されることがわかります。
ただし、ここでもスクリプトパスをハードコードするか、上記のexeにコマンドライン引数として渡す必要があります。
答え3
この船にいくつかのスクリプトプレフィックスを追加しました。
#!/bin/sh
[ "root" != "$USER" ] && exec sudo $0 "$@"
setuid
これは現在のファイルを使用せずに単に実行することに注意してくださいsudo
。
答え4
何らかの理由で利用できない場合は、sudo
Cでシンラッパースクリプトを作成できます。
#include <unistd.h>
int main() {
setuid(0);
execle("/bin/bash","bash","/full/path/to/script",(char*) NULL,(char*) NULL);
}
コンパイル後setuid
はchmod 4511 wrapper_script
。
これは、他の公開された回答と似ていますが、クリーンな環境でスクリプトを実行し、/bin/bash
呼び出されるのではなく、明示的にシェルを使用してsystem()
いくつかの潜在的なセキュリティホールを削除します。
これにより、環境が完全に削除されます。脆弱性を開かずにいくつかの環境変数を使用するには、実際にsudo
。
明らかに、スクリプト自体はルートでのみ書くことができることを確認したいと思います。