web-dev-qa-db-ja.com

バイナリが信頼できないユーザーにSudoアクセス許可を与えるのに安全であるかどうかをどのようにして知ることができますか?

Sudoは、信頼できないユーザーや「準信頼できる」ユーザーに、特定のタスクをrootとして実行できるようにする一方で、無制限のrootアクセスを許可しない場合に使用されることがあります。これは通常、/etc/sudoersへのエントリを介して実行され、実行できるプログラムを指定します。

ただし、プログラムによっては、morelessmanfindなど、予想よりも多くの機能を提供することがあります(しゃれは意図されていません)。他のプログラム-特にシェル。


通常、どのプログラムを実行しても安全かは、sysadminの知識に依存します。 echocatのような特定のバイナリは可能性が高い安全です(つまり、ユーザーがシェルを起動できないようにします)一方で、上記の例のような他のバイナリは悪用される。

Sudo権限が与えられたときに実行可能ファイルが「安全」かどうかを妥当な自信を持って評価する方法はありますか?または、包括的なソースコード監査の唯一の方法ですか?


安全でないcatへの対応:はい、機密ファイルをrootとして読み取るために使用できます。一部の設定では、これは意図されたユースケースである可能性があります(たとえば、制限されたユーザーがrootとして読み取ることはできるが、書き込むことはできない)。

さらに、Sudoはこのような読み取り権限を付与する正しい方法ではないことを説明するコメントまたは回答:わかっています。私はファイルシステムすべきがどのように構造化されているかを完全に認識していますが、私の仕事の性質上、これらのサーバーでファイルシステムがどのように構造化されているかに影響を与えることはできません。私がcanすることは、当面の問題を修正する推奨事項を確認することです。ですから、質問の枠に挑戦しないでください。 XY問題はありません。

12
MechMK1

一般に、確実に知ることは不可能です。一見すると完全に安全なプログラムであっても、任意のアクションに使用される可能性があることを意味する脆弱性が存在する可能性があります。ただし、次の点を確認してください。

プログラムは次のいずれかを行いますか?

  • 任意のファイルまたはデバイスの内容を明らかにします。
  • 任意のファイルをコピー、移動、書き込み、または削除します。
  • 任意の環境変数(他の特権プロセスによって取得される)を設定または変更するか、特定の環境変数を任意に変更します。
  • IOCTLを呼び出すか、他の方法で任意のデバイスと対話します。
  • 任意のファイルの所有権または権限を変更します。
  • 任意のファイルシステムをマウントするか、既存のファイルシステムのマウントオプションを変更します。
  • システムまたは任意のプロセス(デバッガーなど)のメモリーへの直接アクセスを許可します。
  • 任意のプログラムの起動を許可します。

これらのいずれかを実行するプログラムはどれもnot低特権ユーザーにSudoアクセスを許可しても安全です。これにより、たとえば、出力ファイルを指定する機能(通常は-oまたは-fパラメータ)、入力ファイルの内容を明らかにする方法で入力ファイルを処理します(入力フォーマットが間違っていることについて十分に情報を提供するエラーメッセージを介しても)、およびスクリプトランタイムの大部分(シェルを含む)。

これらのチェックでarbitrarylimitedまたは特定、それからあなたは問題を1つまたは複数の段階で蹴り下げました:プログラムができることのいずれかを行いますそのような恣意的な出来事につながる、おそらく複数レベルの間接参照を通じて?たとえば、プログラムがユーザーに一意の環境変数を設定することを許可している場合、特権プログラムは予想とは異なるファイルを読み取らせ、その異なるファイルはユーザーが選択したイメージファイルをユーザーがマウントできるようにします。 setuidビットが尊重されるファイルシステムの場合、信頼できないユーザーにそのプログラムの実行を許可してはなりません。

ただし、プログラムがこれらすべてのチェックに合格したからといって、それが実際に安全であるとは限りません。たとえば、特定のネットワークアクション(制限されたポートでのリッスンやrawパケットの送信など)を実行する場合、ネットワーク上(または同じマシン上)に別のプログラムが存在する可能性があるため、そのようなすべてのプロセスが物事は信頼できるユーザーによって所有されています-結局のところ、これらのアクションにはrootが必要です-そしてあなたはその仮定を破っています。さらに、上記の箇条書きのリストは、数分で思いついたものです。ほぼ確実に、私が含めなかった特権昇格へのいくつかの手段があります。

最後に、すべてのセキュリティの質問と同様に、脅威のモデルによって異なります。

  • 攻撃者(信頼できないユーザー)は、物理的にアクセスできるマシンにローカルですか、それともリモートですか?特に支援なしにマシンを(再)起動できるようにする必要がある場合は、物理的なアクセス権を持つ攻撃者がroot権限を取得するのを防ぐのは非常に難しいので、受け入れるリスクを検討してください。
  • マシンはユーザー間で共有されていますか?次に、サービス拒否攻撃などの追加のクロスユーザー攻撃を検討する必要があります(過剰なリソースを消費するか、マシンを使用不可にする)。
  • 否認防止(だれが何かをしたかを証明する能力)が必要ですか?次に、Sudoを介して実行されたアクションを、それらを実行したユーザーに関連付けることができることを確認する必要があります。
  • Root以外のユーザーでも通常実行できるいくつかのことをユーザーが実行できないようにする必要がありますか(たとえば、プログラムがゲームや暗号マイナーのようなものであっても、独自のユーザーコンテキストで任意のプログラムを実行したり、open TCP任意のホストおよびポートへのクライアント接続)?次に、この制限を適用する手段を追加で検討し、ユーザーがをバイパスする方法につながる可能性のあるプログラムをSudoとして実行しないようにする必要があります。制限。

ここでは、真に包括的な答えはここでは不可能です。それはあまりにも多くに依存しています。しかし、私はこれを言います:rootとして重要なプログラムを実行する能力を考えると、信頼されていないユーザーを保証することは非常に困難です安全にそのように実行するように明示的に設計されていない)、予期しない何かを行うことはできません。そのようなプログラムのいずれかが、防止することが重要であると認めるものを許可しない場合でも、攻撃者の目標を達成するために複数のそのようなプログラムをチェーン化することが可能かもしれません。

6
CBHacking

それは本質的に停止問題に要約されます。コードを監査するか、バイナリをリバースエンジニアリングできますが、任意のコマンドを実行できる「機能」がない場合でも、バイナリまたはSudo自体に脆弱性があり、有効なユーザーのrootとしての任意のコマンド実行。

5
wireghoul

一般的に、バイナリの代わりに、あなたが考えることができるのは、syscallsです。たとえば猫の場合、おそらくシステムコール、オープン、読み取り、書き込み、クローズなどを実行します。一方、バイナリ(たとえば、find)が-execパラメータを使用して他のバイナリを実行できる場合、このプロセスに暗黙的に含まれるsyscallはfork、exec、mmapなどであり、おそらく必要なsyscallです。守ること。 SELinuxまたは( secompfilter )でも、特定のsyscallのポリシーを設定し、Sudoを使用してアクセス許可と組み合わせるか、SELinuxのポリシーを直接設定できます。良い例の1つは、バイナリをptraceして暗黙のsyscallを確認し、要件に応じてこれらのsyscallへのアクセス許可を追加または削除します。

1
camp0

基本的に、あなたは、プログラムのセキュリティを評価する専門家が、昇格された権利が許可されているプログラムが何ができるかについて深い知識を持つことに依存します。

上記の文には、プログラムが使用するライブラリと使用しているシステム(Linux?* BSD?)に関する知識が含まれています。

完全なソースコード監査に進む必要はないかもしれません。適切に文書化されたプログラムの場合、安全でないオプションを見つけるには、文書を完全に読むだけで十分な場合があります。また、利用できる時間と専門知識によっても異なります。

よくあることですが、プログラムが安全でないことを証明することは、一般に簡単に表示できます(見つかったら)が、安全であることを証明することは非常に困難です。

主な問題点は次のとおりです。

  • ユースケースに意図しない機能。シェルで表示するオプションから、今では埋め込みLUAを許可する構成ファイルまで。
  • プログラムの脆弱性。対話型プログラムのバッファオーバーフローは一般的に重要ではありませんが、rootとして実行すると、特権昇格のパスになります。
  • 多くのまたは複雑すぎるライブラリの使用。例えば。グラフィカルなプログラム。あなたはすぐにこれらを拒否したいと思うでしょう。

これらのユーザーがSudoプログラムをできるだけシンプルかつ「閉じた」状態で実行できるようにする必要があります。プログラムが複数のオプションを許可する場合は、それらを修正してそれらを修正します。構成ファイルがある場合は、ユーザーが構成できないものを使用するようにします。

本格的なプログラムではなく、限られたシェルスクリプトや短いプログラムを許可することをお勧めします。

たとえば、「信頼できないユーザーは絶対に少ないファイルをすべて読み取る必要がある」という問題(またはemacs、vi…)の場合、次のように使用します。

/**
 * This program when run by Sudo allows reading as root an arbitrary file via less(1)
 */
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>

int Sudo_var(const char* varname) {
    char *value, *endptr;
    int number;

    value = getenv(varname);
    if (!value) {
        fprintf(stderr, "Environment doesn't contain %s!\n", varname);
        exit(5);
    }

    errno = 0;
    number = strtol(value, &endptr, 10);
    if (*endptr != '\0') {
        fprintf(stderr, "Bad environment variable %s!\n", varname);
        exit(5);
    }
    if (errno || number <= 0) {
        fprintf(stderr, "Bad value for environment variable %s!\n", varname);
        exit(5);
    }
    return number;
}

int main(int argc, char **argv, char **envp) {
    gid_t gid;
    uid_t uid;
    int fd, err;
    struct stat stat_variable;
    char *less_argv[] = {"/usr/bin/less", NULL};

    if (argc < 2) {
        fprintf(stderr, "Provide the file to read\n");
        return 1;
    }
    fd = open(argv[1], O_RDONLY | O_NOCTTY);
    if (fd == -1) {
        perror("Error opening file");
        return 2;
    }

    err = fstat(fd, &stat_variable);
    if (err) {
        perror("stat error");
        return 3;
    }

    if (!S_ISREG(stat_variable.st_mode)) {
        fprintf(stderr, "Not a regular file\n");
        return 3;
    }

    err = dup2(fd, STDIN_FILENO);
    if (err) {
        perror("dup2 failed");
        return 4;
    }

    gid = Sudo_var("Sudo_GID");
    uid = Sudo_var("Sudo_UID");

    err = setgid(gid);
    if (err) {
        perror("Error setting group id");
        return 6;
    }

    err = setuid(uid);
    if (err) {
        perror("Error setting user id");
        return 7;
    }

    execve(less_argv[0], less_argv, envp);
    perror("exec failed");
    return 8;
}
1
Ángel