Sudo
est parfois utilisé pour donner aux utilisateurs non fiables ou "semi-fiables" la possibilité d'effectuer certaines tâches en tant que root, sans leur donner un accès root illimité. Cela se fait généralement via une entrée dans /etc/sudoers
, spécifiant quels programmes peuvent être exécutés.
Cependant, certains programmes peuvent fournir plus de fonctionnalités (sans jeu de mots) que prévu, comme more
, less
, man
ou find
, qui proposent d'exécuter d'autres programmes - notamment un Shell.
Habituellement, les programmes à exécuter en toute sécurité dépendent de la connaissance de l'administrateur système. Certains binaires comme echo
ou cat
sont très probablement sûrs (c'est-à-dire qu'ils ne permettent pas à l'utilisateur de générer un shell), tandis que d'autres comme les exemples ci-dessus sont connus pour être exploitable.
Existe-t-il un moyen d'évaluer avec une confiance raisonnable si un exécutable est "sûr" lorsqu'il reçoit les autorisations Sudo
? Ou est-ce le seul moyen d'un audit complet du code source?
En réponse à cat
n'étant pas sûr: Oui, il peut être utilisé pour lire des fichiers sensibles en tant que root. Dans certaines configurations, cela peut être le cas d'utilisation prévu (par exemple, un utilisateur limité pouvant lire en tant que root, mais pas écrire).
De plus, des commentaires ou des réponses m'expliquant que Sudo
n'est pas la bonne façon d'accorder des autorisations de lecture comme ceci: je sais. Je suis absolument conscient de la façon dont un système de fichiers devrait être structuré, mais en raison de la nature de mon travail, je ne peux pas influencer la façon dont les systèmes de fichiers sont structurés sur ces serveurs . Tout ce que je peux faire est de voir quelle recommandation résout le problème immédiat. Alors s'il vous plaît, ne remettez pas en cause le cadre de la question. Je n'ai pas de problème XY.
En général, il est impossible de savoir avec certitude - même un programme apparemment parfaitement sûr pourrait avoir des vulnérabilités qui signifient qu'il peut être utilisé pour des actions arbitraires - mais voici quelques éléments à vérifier:
Tout programme qui fait cela est pas sûr pour accorder à un utilisateur à faible privilège Sudo
l'accès à. Cela exclut, par exemple, tout programme ayant la possibilité de spécifier un fichier de sortie (généralement via un -o
ou -f
paramètre), traite un fichier d'entrée d'une manière qui révèle son contenu (même juste via un message d'erreur suffisamment informatif sur le format d'entrée incorrect), et la grande majorité des exécutions de script (y compris les shells).
Si vous remplacez arbitraire dans ces vérifications par limité ou spécifique , vous avez ensuite résolu le problème d'une étape (ou de plusieurs): faites l'une des choses que le programme peut faire conduire à de tels événements arbitraires, éventuellement à travers plusieurs niveaux d'indirection? Par exemple, si votre programme permet à l'utilisateur de définir une variable d'environnement unique, un programme privilégié lira un fichier différent de celui attendu, et ce fichier différent amènera le système à permettre aux utilisateurs de monter un fichier image de leur choix comme un système de fichiers avec le bit setuid
respecté, vous ne devez pas autoriser les utilisateurs non fiables à exécuter ce programme.
Cependant, ce n'est pas parce qu'un programme réussit toutes ces vérifications qu'il est réellement sûr. Par exemple, s'il effectue certaines actions réseau (telles que l'écoute sur des ports restreints ou l'envoi de paquets bruts), il peut être dangereux car il peut y avoir un autre programme sur le réseau (ou sur la même machine) en supposant que chaque processus capable de le faire les choses appartiennent à un utilisateur de confiance - après tout, ces actions nécessitent un root - et vous avez brisé cette hypothèse. De plus, la liste des puces ci-dessus est juste une chose à laquelle j'ai pensé en quelques minutes; il y a presque certainement des voies pour privilégier l'escalade que je n'ai pas inclus.
Enfin, comme pour toutes les questions de sécurité, cela dépend de votre modèle de menace.
Sudo
à l'utilisateur qui les a effectuées.Etc. Une réponse vraiment complète ne sera pas possible ici; cela dépend de trop de choses. Cependant, je dirai ceci: il est très difficile d'assurer un utilisateur non fiable, étant donné la possibilité d'exécuter en tant que root tout programme non trivial (c'était pas explicitement conçu pour être exécuté de cette façon en toute sécurité), ne peut pas faire quelque chose d'inattendu. Même si l'un de ces programmes n'autorise pas ce que vous jugez important d'empêcher, il peut être possible de chaîner plusieurs de ces programmes ensemble pour atteindre l'objectif de l'attaquant.
Cela se résume essentiellement au problème d'arrêt, vous pouvez auditer le code ou faire de l'ingénierie inverse du binaire, mais même s'il n'y a pas de "fonctionnalités" qui vous permettent d'exécuter des commandes arbitraires, il pourrait toujours y avoir des vulnérabilités dans le binaire ou Sudo lui-même qui pourraient conduire à exécution de commandes arbitraires en tant que root pour les utilisateurs activés.
En général, ce que vous pouvez penser, au lieu des binaires, c'est sur les appels système. Par exemple, cat, de plus en moins, ils exécuteront les appels système, ouvriront, liront, écriront, fermeront et ainsi de suite. D'un autre côté, si le binaire (par exemple find) peut exécuter d'autres binaires, avec l'utilisation du paramètre -exec, les appels système impliqués dans ce processus sont fork, exec, mmap, etc. qui sont probablement les appels système que vous voulez protéger. Sur SELinux ou même ( secompfilter ), vous pouvez avoir des politiques pour des appels système spécifiques et combiner avec les autorisations avec Sudo ou avoir directement les politiques sur SELinux. Un bon exemple est de ptrace binaire et de voir les appels système impliqués, puis de commencer à ajouter ou supprimer les autorisations sur ces appels système en fonction de vos besoins
Fondamentalement, vous dépendrez de l'expert (s) évaluant la sécurité du programme ayant une connaissance approfondie de ce que les programmes qui sont autorisés à des droits élevés peuvent faire.
La phrase ci-dessus comprend la connaissance des bibliothèques utilisées par le programme et le système que vous utilisez (Linux? * BSD?).
Il n'est peut-être pas nécessaire de descendre jusqu'à un audit complet du code source. Pour un programme bien documenté, une lecture complète de la documentation peut être suffisante pour trouver des options non sécurisées. Cela dépendra également du temps et de l'expertise dont vous disposez.
Comme c'est souvent le cas, prouver qu'un programme n'est pas sûr sera généralement simple à montrer (une fois trouvé), mais prouver qu'il est sûr serait très difficile.
Les principaux points problématiques seraient:
Vous voudrez permettre à ces utilisateurs de fonctionner avec les programmes Sudo aussi simples et "fermés" que possible. Si le programme autorise plusieurs options, fournissez-les afin qu'elles soient corrigées, s'il y a un fichier de configuration, faites-en en utiliser un non configurable par l'utilisateur, etc.
Je recommanderais d'autoriser un script Shell limité ou un programme court au lieu du programme à part entière.
Par exemple, pour le problème déclaré de "l'utilisateur non fiable doit lire absolument n'importe quel fichier avec moins" (ou emacs, vi…), je pourrais utiliser:
/**
* 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;
}