Ubuntu - Kann ein Benutzer ohne Rootberechtigung einen Prozess im chroot-Gefängnis ausführen?


18

Kann ein Benutzer ohne Rootberechtigung unter Ubuntu einen Chroot-Prozess ausführen?


Dieser alte FreeBSD-Thread behandelt dieselbe Frage: lists.freebsd.org/pipermail/freebsd-security/2003-April/… Kurze Antwort: Nein, Sie können keinen Prozess als root in einem nicht-root-chroot- Jail ausführen.
David Harrison

Chroot-Gefängnisse sind spezifisch für BSD. Eine Chroot unter Linux ist kein Gefängnis. Zuletzt habe ich überprüft, dass es nicht möglich war, als Benutzer zu chrooten.
Xenoterracide

1
@xenoterracide-Jails sind BSD-spezifisch, chroot wird in der Linux-Community jedoch allgemein als "chroot-Jail" bezeichnet. Es ist ziemlich verwirrt.
Pehrs

2
Was versuchst du zu tun und warum? Es gibt Tools wie fakechroot und schroot, die je nach Ihren Anforderungen eine praktikable Alternative darstellen.
Zoredache

Es gab auch mehr verwandte Diskussionen unter Wie kann man einen Prozess "ins Gefängnis setzen", ohne root zu sein? mit mehr Arbeit oder vorläufigen Ansätzen zur Lösung dieser Aufgabe aufgeführt.
imz - Ivan Zakharyaschev

Antworten:


12

Unter Linux kann der Systemaufruf chroot (2) nur von einem privilegierten Prozess ausgeführt werden. Die Fähigkeit, die der Prozess benötigt, ist CAP_SYS_CHROOT.

Der Grund, warum Sie als Benutzer nicht chroot können, ist ziemlich einfach. Angenommen, Sie haben ein Setuid-Programm wie sudo, das prüft, ob Sie etwas tun dürfen. Legen Sie es jetzt in eine Chroot-Chroot mit Ihren eigenen / etc / sudoers. Plötzlich haben Sie eine sofortige Privilegieneskalation.

Es ist möglich, ein Programm so zu entwerfen, dass es sich selbst in der Chroot-Umgebung befindet und als Setuid-Prozess ausgeführt wird. Dies wird jedoch im Allgemeinen als schlechtes Design angesehen. Die zusätzliche Sicherheit der Chroot motiviert die Sicherheitsprobleme mit der Setuid nicht.


3
Mit den neuen Möglichkeiten von Namespaces in Linux ist es vielleicht möglich, einen neuen "Benutzer" -Namespace zu erstellen (die Freigabe aufzuheben), in dem sich ein "eingebetteter" Root-Benutzer befindet, und chrootdann auszuführen .
imz - Ivan Zakharyaschev

1
@ imz - IvanZakharyaschev Sie haben absolut Recht, und ich hoffe, es macht Ihnen nichts aus, dass ich mir die Freiheit genommen habe, das als leicht überprüfbare Antwort aufzuschreiben.
HDV

@hvd Großartig! Es muss sehr nützlich sein, da es zeigt, wie die neuen ungewohnten Linux-Funktionen mit konkreten Befehlen verwendet werden.
imz - Ivan Zakharyaschev

6

@ imz - IvanZakharyaschev kommentiert die Antwort von pehrs, dass es mit der Einführung von Namespaces möglich sein könnte, aber dies wurde nicht getestet und als Antwort veröffentlicht. Ja, das ermöglicht es in der Tat einem Nicht-Root-Benutzer, chroot zu verwenden.

Bei einer statisch verknüpften dashund einer statisch verknüpften busyboxund einer ausgeführten bashShell, die als Nicht-Root ausgeführt wird:

$ mkdir root
$ cp /path/to/dash root
$ cp /path/to/busybox root
$ unshare -r bash -c 'chroot root /dash -c "/busybox ls -al /"'
total 2700
drwxr-xr-x    2 0        0             4096 Dec  2 19:16 .
drwxr-xr-x    2 0        0             4096 Dec  2 19:16 ..
drwxr-xr-x    1 0        0          1905240 Dec  2 19:15 busybox
drwxr-xr-x    1 0        0           847704 Dec  2 19:15 dash

Die Root - Benutzer - ID in diesem Namespace wird auf die Nicht-Root - Benutzer - ID außerhalb dieses Namensraumes abgebildet, und umgekehrt, weshalb die System zeigt Dateien , die von dem aktuellen Benutzer gehören , wie durch Benutzer - ID 0. Ein regelmäßigen Besitz ls -al root, ohne unshare, tun Zeigen Sie sie als Eigentum des aktuellen Benutzers an.


Hinweis: Es ist bekannt, dass Prozesse, die in der Lage sind, zu verwenden chroot, in der Lage sind, aus a auszubrechen chroot. Da einem normalen Benutzer Berechtigungen erteilt unshare -rwürden chroot, wäre dies ein Sicherheitsrisiko, wenn dies in einer chrootUmgebung zulässig wäre . In der Tat ist es nicht erlaubt und scheitert mit:

Freigabe aufheben: Freigabe fehlgeschlagen: Vorgang nicht zulässig

welche mit der Dokumentation von unshare (2) übereinstimmt :

EPERM (seit Linux 3.9)

CLONE_NEWUSER wurde in Flags angegeben und der Aufrufer befindet sich in einer Chroot-Umgebung (dh das Stammverzeichnis des Aufrufers stimmt nicht mit dem Stammverzeichnis des Mount-Namespaces überein, in dem er sich befindet).


Das Ausführen von pivot_root in einem Mount-Namespace hat einen ähnlichen Effekt wie chroot, vermeidet jedoch den Konflikt mit Benutzernamensräumen.
Timothy Baldwin

1
Man kann einem chroot- oder mount-Namespace entkommen, indem man nach / proc absteigt, wenn es sich um einen Prozess außerhalb mit derselben UID in demselben oder untergeordneten PID- und Benutzernamensräumen handelt.
Timothy Baldwin

2

In diesen Tagen möchten Sie sich mit LXC (Linux Containers) anstatt mit chroot / BSD befassen. Es liegt irgendwo zwischen einer Chroot und einer virtuellen Maschine und bietet Ihnen viel Sicherheitskontrolle und allgemeine Konfigurierbarkeit. Ich glaube, Sie müssen nur Mitglied der Gruppe sein, die die erforderlichen Dateien / Geräte besitzt. Möglicherweise sind jedoch auch Funktionen / Systemberechtigungen erforderlich. Auf jeden Fall sollte es sehr machbar sein, da LXC ziemlich neu ist, lange nachdem SELinux etc. zum Linux-Kernel hinzugefügt wurde.

Denken Sie auch daran, dass Sie Skripte nur als root schreiben können, den Benutzern jedoch die sichere Berechtigung erteilen, diese Skripte mit sudo auszuführen (wenn Sie möchten, müssen Sie jedoch sicherstellen, dass das Skript sicher ist).


1

Die Kombination von fakeroot / fakechroot ergibt eine Chroot-Simulation für einfache Anforderungen wie das Erstellen von Tar-Archiven, bei denen Dateien anscheinend Eigentum von root zu sein scheinen. Fakechroot-Manpage ist http://linux.die.net/man/1/fakechroot .

Sie erhalten zwar keine neue Berechtigung, aber wenn Sie ein Verzeichnis besitzen (z. B. Fake-Distribution), bevor Sie es aufrufen

fakechroot fakeroot chroot ~/fake-distro some-command

Es sieht jetzt so aus, als ob Sie root sind und alles in der gefälschten Distribution besitzen.


Dies ist eine nette Idee, aber sie scheint unvorhersehbar mit Symlinks umzugehen. Meiner ~/fake-distrobenutzt busybox, welche symlinks ls, mvund andere gängige Dienstprogramme dazu /bin/busybox. Wenn ich explizit anrufe /bin/busybox mv ..., funktionieren die Dinge, aber wenn ich anrufe, /bin/mv ...bekomme ich sh: /bin/mv: not found. Die Einstellung export FAKECHROOT_EXCLUDE_PATH=/vor dem Ausführen von fakechroot behebt dieses Symptom, bricht dann jedoch bei anderen Symlinks (z /usr/bin/vim -> /usr/bin/vim.vim. B. ) ab.
Ponkadoodle

Vielleicht würde FAKECHROOT_EXCLUDE_PATH = /: / usr dann helfen?
Sylvainulg

1

Es scheint, dass es mit Benutzernamensräumen tatsächlich möglich ist, ohne root zu chrooten. Hier ist ein Beispielprogramm, das zeigt, dass es möglich ist. Ich habe erst begonnen zu untersuchen, wie Linux-Namespaces funktionieren, und bin mir daher nicht ganz sicher, ob dieser Code die beste Vorgehensweise ist oder nicht.

Speichern unter user_chroot.cc. Kompilieren mit g++ -o user_chroot user_chroot.cc. Verwendung ist ./user_chroot /path/to/new_rootfs.

// references:
// [1]: http://man7.org/linux/man-pages/man7/user_namespaces.7.html
// [2]: http://man7.org/linux/man-pages/man2/unshare.2.html

#include <sched.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include <cerrno>
#include <cstdio>
#include <cstring>

int main(int argc, char** argv) {
    if(argc < 2) {
        printf("Usage: %s <rootfs>\n", argv[0]);
    }

    int uid = getuid();
    int gid = getgid();
    printf("Before unshare, uid=%d, gid=%d\n", uid, gid);

    // First, unshare the user namespace and assume admin capability in the
    // new namespace
    int err = unshare(CLONE_NEWUSER);
    if(err) {
        printf("Failed to unshare user namespace\n");
        return 1;
    }

    // write a uid/gid map
    char file_path_buf[100];
    int pid = getpid();
    printf("My pid: %d\n", pid);

    sprintf(file_path_buf, "/proc/%d/uid_map", pid);
    int fd = open(file_path_buf, O_WRONLY);
    if(fd == -1) {
        printf("Failed to open %s for write [%d] %s\n", file_path_buf, errno, 
               strerror(errno));
    } else {
        printf("Writing : %s (fd=%d)\n", file_path_buf, fd);
        err = dprintf(fd, "%d %d 1\n", uid, uid);
        if(err == -1) {
            printf("Failed to write contents [%d]: %s\n", errno, 
                   strerror(errno));
        }
        close(fd);
    }

    sprintf(file_path_buf, "/proc/%d/setgroups", pid);
    fd = open(file_path_buf, O_WRONLY);
    if(fd == -1) {
        printf("Failed to open %s for write [%d] %s\n", file_path_buf, errno, 
               strerror(errno));
    } else {
        dprintf(fd, "deny\n");
        close(fd);
    }

    sprintf(file_path_buf, "/proc/%d/gid_map", pid);
    fd = open(file_path_buf, O_WRONLY);
    if(fd == -1) {
        printf("Failed to open %s for write [%d] %s\n", file_path_buf, errno, 
               strerror(errno));
    } else {
        printf("Writing : %s (fd=%d)\n", file_path_buf, fd);
        err = dprintf(fd, "%d %d 1\n", gid, gid);
        if(err == -1) {
            printf("Failed to write contents [%d]: %s\n", errno, 
                   strerror(errno));
        }
        close(fd);
    }

    // Now chroot into the desired directory
    err = chroot(argv[1]);
    if(err) {
        printf("Failed to chroot\n");
        return 1;
    }

    // Now drop admin in our namespace
    err = setresuid(uid, uid, uid);
    if(err) {
        printf("Failed to set uid\n");
    }

    err = setresgid(gid, gid, gid);
    if(err) {
        printf("Failed to set gid\n");
    }

    // and start a shell
    char argv0[] = "bash";
    char* new_argv[] = {
        argv0,
        NULL
    };

    err = execvp("/bin/bash", new_argv);
    if(err) {
        perror("Failed to start shell");
        return -1;
    }
}

Ich habe dies auf einem minimalen rootfs getestet, das mit multistrap erzeugt wurde (ausgeführt als Nicht-root). Einige Systemdateien mögen /etc/passwdund /etc/groupswurden von den Host-Rootfs in die Gast-Rootfs kopiert.


Scheitert bei Failed to unshare user namespacemir unter Linux 4.12.10 (Arch Linux).
Ponkadoodle

@wallacoloo vielleicht printf () zu perror () ändern und sehen, was der eigentliche Fehler war. In man7.org/linux/man-pages/man2/unshare.2.html erfahren Sie, welche Fehlercodes aus einem erfolglosen unshareAnruf resultieren können . Sie können auch diese Python - Version versuchen , die besser Störmeldeversand haben könnte: github.com/cheshirekow/uchroot
cheshirekow

1
Eigentlich @wallacoloo es wie Bogen deaktiviert klingt unprivilegierte Benutzer Namespaces in seinen Kernel - Version: lists.archlinux.org/pipermail/arch-general/2017-February/...
cheshirekow

0

Nein. Wenn ich mich richtig erinnere, gibt es eine Kernel-Level-Sache, die Chroot tut, um dies zu verhindern. Ich kann mich nicht erinnern, was das für ein Ding war. Ich habe es untersucht, als ich mit Gentoos Catalyst Build-Tool rumgespielt habe (und ein Chroot unter Gentoo ist dasselbe wie ein Chroot unter Ubuntu). Es wäre zwar möglich, dies ohne ein Passwort zu erreichen ... aber solche Dinge sind dem Bereich potenzieller Sicherheitslücken überlassen und stellen sicher, dass Sie wissen, was Sie tun.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.