GNU/Linux >> Linux の 問題 >  >> Linux

Setuidビットを適切に使用していますか?

通常のユーザーが実行するときにroot権限を必要とするプロセスがあります。どうやら私はこれを達成するために「setuidビット」を使用することができます。 POSIXシステムでこれを行う適切な方法は何ですか?

また、インタプリタ(bash、perl、python、phpなど)を使用するスクリプトでこれを行うにはどうすればよいですか?

承認された回答:

setuidビットを実行可能ファイルに設定して、実行時に、プログラムが実際のユーザーではなくファイルの所有者の特権を持っているようにすることができます。これが効果的の違いです uid(ユーザーID)と real uid。

passwdなどの一般的なユーティリティ 、rootが所有し、必要に応じてこのように構成されます(passwd /etc/shadowにアクセスする必要があります ルートでのみ読み取ることができます。

これを行うときの最善の戦略は、スーパーユーザーとして必要なことをすぐに実行してから特権を下げて、rootの実行中にバグや誤用が発生する可能性を低くすることです。これを行うには、プロセスの有効を設定します uidから実際のuidへ。 POSIX Cの場合:

#define _POSIX_C_SOURCE 200112L // Needed with glibc (e.g., linux).
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

void report (uid_t real) {
    printf (
        "Real UID: %d Effective UID: %dn",
        real,
        geteuid()
    );
}

int main (void) {
    uid_t real = getuid();
    report(real);
    seteuid(real);
    report(real);
    return 0;
}

関連する関数。POSIXシステムで一般的に使用されている場合、ほとんどの高級言語で同等のものが必要です。

  • getuid()本物のを入手する uid。
  • geteuid()効果的を取得する uid。
  • seteuid()効果的なを設定します uid。

実行可能ファイルにsetuidビットが設定されている場合を除いて、実際のuidに不適切な最後の1つでは何もできません 。したがって、これを試すには、gcc test.c -o testuidをコンパイルします。 。次に、特権を使用して、次のことを行う必要があります:

chown root testuid
chmod u+s testuid

最後のものはsetuidビットを設定します。ここで./testuidを実行した場合 通常のユーザーとして、プロセスはデフォルトで有効なuid 0、rootで実行されます。

スクリプトはどうですか?

これはプラットフォームによって異なりますが、Linuxでは、バイトコードなどのインタープリターを必要とするものは、インタープリターに設定されていない限り、setuidビットを利用できません(これは非常に愚かです)。上記のCコードを模倣した簡単なperlスクリプトは次のとおりです。

#!/usr/bin/perl
use strict;
use warnings FATAL => qw(all);

print "Real UID: $< Effective UID: $>n";
$> = $<; # Not an ASCII art greedy face, but genuine perl...
print "Real UID: $< Effective UID: $>n"; 

* nixyのルーツに忠実に、perlには効果的なuid($>用の特別な変数が組み込まれています )および実際のuid($< )。ただし、同じchownを試してみると およびchmod コンパイルされた(C、前の例から)実行可能ファイルで使用すると、違いはありません。スクリプトは特権を取得できません。

関連:bashをv4.0 +に正しくアップグレードする方法は?

これに対する答えは、setuidバイナリを使用してスクリプトを実行することです:

#include <stdio.h>
#include <unistd.h> 

int main (int argc, char *argv[]) {
    if (argc < 2) {
        puts("Path to perl script required.");
        return 1;
    }
    const char *perl = "perl";
    argv[0] = (char*)perl;
    return execv("/usr/bin/perl", argv);
}

このgcc --std=c99 whatever.c -o perlsuidをコンパイルします 、次にchown root perlsuid && chmod u+s perlsuid 。これで、任意のを実行できます 有効なuidが0のperlスクリプト。所有者に関係なく。

同様の戦略は、php、pythonなどでも機能します。しかし…

# Think hard, very important:
>_< # Genuine ASCII art "Oh tish!" face

どうぞこの種のものを横に置いたままにしないでください ほとんどの場合、実際には、スクリプトの名前で絶対パスとしてコンパイルする必要があります。 、つまり、main()のすべてのコードを置き換えます と:

    const char *args[] = { "perl", "/opt/suid_scripts/whatever.pl" }
    return execv("/usr/bin/perl", (char * const*)args);

/opt/suid_scriptsを確認してください その中のすべては、root以外のユーザーに対して読み取り専用です。そうでなければ、誰かがwhatever.plに何かを交換する可能性があります 。

さらに、多くのスクリプト言語では、環境変数がスクリプトの実行方法を変更できることに注意してください 。たとえば、環境変数を使用すると、呼び出し元から提供されたライブラリが読み込まれ、呼び出し元がルートとして任意のコードを実行できるようになる場合があります。したがって、インタプリタとスクリプト自体の両方がすべての可能な環境変数に対して堅牢であることがわかっている場合を除き、これを行わないでください

では、代わりに何をすればよいですか?

root以外のユーザーがrootとしてスクリプトを実行できるようにするためのより安全な方法は、sudoルールを追加し、ユーザーにsudo /path/to/scriptを実行させることです。 。 Sudoはほとんどの環境変数を取り除き、管理者がコマンドを実行できるユーザーと引数を細かく選択できるようにします。パスワードプロンプトなしでrootとして特定のプログラムを実行する方法を参照してください。例として。


Linux
  1. Linuxでprocファイルシステムを使用してトラブルシューティングする

  2. Linuxコマンドラインで力を使用する

  3. ローリングリリースLinuxとは何ですか?それを使用することの本当の利点は何ですか

  1. スティッキービットはどのように機能しますか?

  2. Duコマンドで–excludeを使用しますか?

  3. ユニバーサル チェス インターフェイスの使用

  1. SuidプログラムでSetuid()を使用する目的は?

  2. CPU全体を使用するkdevtmpfsi

  3. setuid ビットの動作に一貫性がないのはなぜですか?