web-dev-qa-db-fra.com

Comment savoir si un binaire est sûr de donner des autorisations Sudo à un utilisateur non fiable?

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.

12
MechMK1

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:

Le programme effectue-t-il l'une des actions suivantes?

  • Révélez le contenu de fichiers ou d'appareils arbitraires.
  • Copiez, déplacez, écrivez ou supprimez des fichiers arbitraires.
  • Définissez/modifiez des variables d'environnement arbitraires (qui seront récupérées par d'autres processus privilégiés) ou apportez des modifications arbitraires à des variables spécifiques.
  • Appelez des IOCTL ou interagissez d'une autre manière avec des périphériques arbitraires.
  • Modifier la propriété ou les autorisations sur des fichiers arbitraires.
  • Montez des systèmes de fichiers arbitraires ou modifiez les options de montage sur les systèmes existants.
  • Autorisez l'accès direct à la mémoire du système ou d'un processus arbitraire (tel qu'un débogueur).
  • Autoriser le lancement de programmes arbitraires.

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.

  • L'attaquant (utilisateur non fiable) est-il local sur la machine avec un accès physique ou est-il distant? Il est extrêmement difficile d'empêcher un attaquant déterminé avec un accès physique de se rooter, surtout s'il doit pouvoir (re) démarrer la machine sans assistance, alors réfléchissez aux risques que vous êtes prêt à accepter.
  • La machine est-elle partagée entre les utilisateurs? Ensuite, vous devez envisager d'autres attaques inter-utilisateurs, telles que le déni de service (en consommant des ressources excessives ou en rendant la machine inutilisable).
  • Avez-vous besoin de non-répudiation (la capacité de prouver qui a fait quelque chose)? Ensuite, vous devez vous assurer que vous pouvez lier toutes les actions effectuées via Sudo à l'utilisateur qui les a effectuées.
  • Avez-vous besoin d'empêcher l'utilisateur de faire certaines choses que même un utilisateur non root peut généralement faire (comme exécuter des programmes arbitraires dans leur propre contexte utilisateur même si ces programmes sont des jeux ou des cryptomètres, ou ouvrir TCP connexions client à des hôtes et ports arbitraires)? Ensuite, vous devez également considérer les moyens par lesquels vous appliquez cette restriction, et éviter d'exécuter en tant que Sudo tous les programmes qui pourraient conduire l'utilisateur à contourner le restriction.

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.

6
CBHacking

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.

5
wireghoul

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

1
camp0

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:

  • Fonctionnalités non prévues pour votre cas d'utilisation. D'une option pour afficher dans Shell à un fichier de configuration qui autorise désormais LUA intégré.
  • Vulnérabilités dans le programme. Un débordement de tampon dans un programme interactif n'est généralement pas critique, mais lorsqu'il est exécuté en tant que root, il devient un chemin vers l'élévation des privilèges.
  • Utilisation de bibliothèques nombreuses ou trop complexes. Par exemple. un programme graphique. Vous voudriez les rejeter tout de suite.

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;
}
1
Ángel