Sudo
は、信頼できないユーザーや「準信頼できる」ユーザーに、特定のタスクをrootとして実行できるようにする一方で、無制限のrootアクセスを許可しない場合に使用されることがあります。これは通常、/etc/sudoers
へのエントリを介して実行され、実行できるプログラムを指定します。
ただし、プログラムによっては、more
、less
、man
、find
など、予想よりも多くの機能を提供することがあります(しゃれは意図されていません)。他のプログラム-特にシェル。
通常、どのプログラムを実行しても安全かは、sysadminの知識に依存します。 echo
やcat
のような特定のバイナリは可能性が高い安全です(つまり、ユーザーがシェルを起動できないようにします)一方で、上記の例のような他のバイナリは悪用される。
Sudo
権限が与えられたときに実行可能ファイルが「安全」かどうかを妥当な自信を持って評価する方法はありますか?または、包括的なソースコード監査の唯一の方法ですか?
安全でないcat
への対応:はい、機密ファイルをrootとして読み取るために使用できます。一部の設定では、これは意図されたユースケースである可能性があります(たとえば、制限されたユーザーがrootとして読み取ることはできるが、書き込むことはできない)。
さらに、Sudo
はこのような読み取り権限を付与する正しい方法ではないことを説明するコメントまたは回答:わかっています。私はファイルシステムすべきがどのように構造化されているかを完全に認識していますが、私の仕事の性質上、これらのサーバーでファイルシステムががどのように構造化されているかに影響を与えることはできません。私がcanすることは、当面の問題を修正する推奨事項を確認することです。ですから、質問の枠に挑戦しないでください。 XY問題はありません。
一般に、確実に知ることは不可能です。一見すると完全に安全なプログラムであっても、任意のアクションに使用される可能性があることを意味する脆弱性が存在する可能性があります。ただし、次の点を確認してください。
これらのいずれかを実行するプログラムはどれもnot低特権ユーザーにSudo
アクセスを許可しても安全です。これにより、たとえば、出力ファイルを指定する機能(通常は-o
または-f
パラメータ)、入力ファイルの内容を明らかにする方法で入力ファイルを処理します(入力フォーマットが間違っていることについて十分に情報を提供するエラーメッセージを介しても)、およびスクリプトランタイムの大部分(シェルを含む)。
これらのチェックでarbitraryをlimitedまたは特定、それからあなたは問題を1つまたは複数の段階で蹴り下げました:プログラムができることのいずれかを行いますそのような恣意的な出来事につながる、おそらく複数レベルの間接参照を通じて?たとえば、プログラムがユーザーに一意の環境変数を設定することを許可している場合、特権プログラムは予想とは異なるファイルを読み取らせ、その異なるファイルはユーザーが選択したイメージファイルをユーザーがマウントできるようにします。 setuid
ビットが尊重されるファイルシステムの場合、信頼できないユーザーにそのプログラムの実行を許可してはなりません。
ただし、プログラムがこれらすべてのチェックに合格したからといって、それが実際に安全であるとは限りません。たとえば、特定のネットワークアクション(制限されたポートでのリッスンやrawパケットの送信など)を実行する場合、ネットワーク上(または同じマシン上)に別のプログラムが存在する可能性があるため、そのようなすべてのプロセスが物事は信頼できるユーザーによって所有されています-結局のところ、これらのアクションにはrootが必要です-そしてあなたはその仮定を破っています。さらに、上記の箇条書きのリストは、数分で思いついたものです。ほぼ確実に、私が含めなかった特権昇格へのいくつかの手段があります。
最後に、すべてのセキュリティの質問と同様に、脅威のモデルによって異なります。
Sudo
を介して実行されたアクションを、それらを実行したユーザーに関連付けることができることを確認する必要があります。ここでは、真に包括的な答えはここでは不可能です。それはあまりにも多くに依存しています。しかし、私はこれを言います:rootとして重要なプログラムを実行する能力を考えると、信頼されていないユーザーを保証することは非常に困難です安全にそのように実行するように明示的に設計されていない)、予期しない何かを行うことはできません。そのようなプログラムのいずれかが、防止することが重要であると認めるものを許可しない場合でも、攻撃者の目標を達成するために複数のそのようなプログラムをチェーン化することが可能かもしれません。
それは本質的に停止問題に要約されます。コードを監査するか、バイナリをリバースエンジニアリングできますが、任意のコマンドを実行できる「機能」がない場合でも、バイナリまたはSudo自体に脆弱性があり、有効なユーザーのrootとしての任意のコマンド実行。
一般的に、バイナリの代わりに、あなたが考えることができるのは、syscallsです。たとえば猫の場合、おそらくシステムコール、オープン、読み取り、書き込み、クローズなどを実行します。一方、バイナリ(たとえば、find)が-execパラメータを使用して他のバイナリを実行できる場合、このプロセスに暗黙的に含まれるsyscallはfork、exec、mmapなどであり、おそらく必要なsyscallです。守ること。 SELinuxまたは( secompfilter )でも、特定のsyscallのポリシーを設定し、Sudoを使用してアクセス許可と組み合わせるか、SELinuxのポリシーを直接設定できます。良い例の1つは、バイナリをptraceして暗黙のsyscallを確認し、要件に応じてこれらのsyscallへのアクセス許可を追加または削除します。
基本的に、あなたは、プログラムのセキュリティを評価する専門家が、昇格された権利が許可されているプログラムが何ができるかについて深い知識を持つことに依存します。
上記の文には、プログラムが使用するライブラリと使用しているシステム(Linux?* BSD?)に関する知識が含まれています。
完全なソースコード監査に進む必要はないかもしれません。適切に文書化されたプログラムの場合、安全でないオプションを見つけるには、文書を完全に読むだけで十分な場合があります。また、利用できる時間と専門知識によっても異なります。
よくあることですが、プログラムが安全でないことを証明することは、一般に簡単に表示できます(見つかったら)が、安全であることを証明することは非常に困難です。
主な問題点は次のとおりです。
これらのユーザーが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;
}