Ubuntu - czy użytkownik inny niż root może uruchamiać proces w więzieniu chroot?

18

Czy użytkownik inny niż root może uruchomić proces chroot na Ubuntu?

Sokole Oko
źródło
Ten stary wątek FreeBSD obejmuje to samo pytanie: lists.freebsd.org/pipermail/freebsd-security/2003-April/... Krótka odpowiedź: Nie, nie można uruchomić procesu jako root w więzieniu chroot, który nie jest rootem.
David Harrison,
więzienia chroot są specyficzne dla bsd. chroot w systemie Linux nie jest więzieniem. Ostatnio sprawdziłem, że nie można chrootować jako użytkownik.
ksenoterrakid
1
@ Xenoterracide Więzienia są specyficzne dla BSD, ale chroot jest powszechnie znany jako „więzienie chroot” w społeczności Linuksa. Jest dość zdezorientowany.
pehrs
2
Co próbujesz zrobić i dlaczego? Istnieją narzędzia takie jak fakechroot i schroot, które sprawiają, że stanowią praktyczną alternatywę w zależności od twoich wymagań.
Zoredache
Dyskusja dotyczyła również procesu „więzienia” procesu bez rootowania? z wymienionymi bardziej aktywnymi lub wstępnymi podejściami do rozwiązania tego zadania.
imz - Ivan Zachharyaschev

Odpowiedzi:

12

W systemie Linux wywołanie systemowe chroot (2) może być wykonane tylko przez uprzywilejowany proces. Możliwości potrzebne procesowi to CAP_SYS_CHROOT.

Powód, dla którego nie możesz chrootować jako użytkownik, jest dość prosty. Załóżmy, że masz program setuid, taki jak sudo, który sprawdza / etc / sudoers, czy możesz coś zrobić. Teraz włóż go do chroot chroot z własnymi / etc / sudoers. Nagle masz natychmiastową eskalację uprawnień.

Możliwe jest zaprojektowanie programu, aby sam się chrootował i uruchamiał jako proces setuid, ale ogólnie uważa się to za zły projekt. Dodatkowe bezpieczeństwo chroota nie motywuje problemów bezpieczeństwa z setuidem.

pehrs
źródło
3
Dzięki nowym możliwościom przestrzeni nazw w systemie Linux może być możliwe utworzenie (nieudostępnianie) nowej przestrzeni nazw „użytkownika”, w której byłby „osadzony” użytkownik root, i wykonanie chroottego.
imz - Ivan Zakharyaschev
1
@ imz - IvanZakharyaschev Masz całkowitą rację i mam nadzieję, że nie przeszkadza ci, że mogłem napisać to jako łatwą do sprawdzenia odpowiedź.
hvd
@hvd Świetnie! Musi być bardzo przydatny, ponieważ pokazuje, jak używać nowych nieznanych funkcji Linuksa za pomocą konkretnych poleceń.
imz - Ivan Zakharyaschev
6

@ imz - IvanZakharyaschev komentuje odpowiedź pehrsa, że ​​może to być możliwe dzięki wprowadzeniu przestrzeni nazw, ale nie zostało to przetestowane i opublikowane jako odpowiedź. Tak, to naprawdę umożliwia użytkownikom innym niż root korzystanie z chroot.

Biorąc pod uwagę statycznie połączony dashi statycznie połączony busyboxoraz działającą bashpowłokę działającą jako użytkownik inny niż root:

$ 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

Identyfikator użytkownika root w tej przestrzeni nazw jest mapowany do innego niż root ID użytkownika zewnątrz tej przestrzeni nazw, i vice versa, dlatego pliki systemowe przedstawia posiadane przez bieżącego użytkownika jako własność ID użytkownika 0. regularny ls -al root, bez unshare, czy pokaż je jako własność bieżącego użytkownika.


Uwaga: dobrze wiadomo, że procesy, które są zdolne do użycia chroot, są zdolne do wyrwania się z chroot. Ponieważ unshare -rprzyznałby chrootuprawnienia zwykłemu użytkownikowi, byłoby to zagrożeniem bezpieczeństwa, gdyby było to dozwolone w chrootśrodowisku. Rzeczywiście jest to niedozwolone i kończy się niepowodzeniem w przypadku:

unshare: unshare failed: Operacja niedozwolona

który pasuje do dokumentacji unshare (2) :

EPERM (od Linuksa 3.9)

CLONE_NEWUSER został określony w flagach, a program wywołujący znajduje się w środowisku chroot (tzn. Katalog główny dzwoniącego nie pasuje do katalogu głównego przestrzeni nazw montowania, w której się znajduje).

hvd
źródło
Uruchomienie pivot_root w przestrzeni nazw montowania ma podobny efekt jak chroot, ale pozwala uniknąć konfliktu z przestrzeniami nazw użytkowników.
Timothy Baldwin
1
Można uciec z chroot lub zamontować przestrzeń nazw, schodząc do / proc, jeśli jest to proces poza tym samym UID w tym samym lub potomnym PID i przestrzeniach użytkownika.
Timothy Baldwin
2

Teraz chcesz patrzeć na LXC (Linux Containers) zamiast na chroot / BSD. Jest gdzieś pomiędzy chrootem a maszyną wirtualną, co daje dużą kontrolę bezpieczeństwa i ogólną konfigurowalność. Uważam, że wszystko, czego potrzebujesz, aby uruchomić go jako użytkownik, to być członkiem grupy, która jest właścicielem niezbędnych plików / urządzeń, ale mogą również dotyczyć możliwości / uprawnień systemowych. Tak czy inaczej, powinno to być bardzo wykonalne, ponieważ LXC jest dość nowy, długo po dodaniu SELinux itp. Do jądra Linux.

Pamiętaj również, że możesz po prostu pisać skrypty jako root, ale dać użytkownikom bezpieczne uprawnienia do uruchamiania tych skryptów (bez hasła, jeśli chcesz, ale upewnij się, że skrypt jest bezpieczny) przy użyciu sudo.

Lee B.
źródło
1

Połączenie fakeroot / fakechroot daje symulację chroot do prostych potrzeb, takich jak tworzenie archiwów tar, w których pliki wydają się być własnością root. Strona man Fakechroot to http://linux.die.net/man/1/fakechroot .

Nie otrzymujesz jednak żadnych nowych uprawnień, ale jeśli posiadasz katalog (np. Fałszywe dystrybucje) przed wywołaniem

fakechroot fakeroot chroot ~/fake-distro some-command

teraz szuka jakiegoś polecenia, jakbyś był rootem i posiadał wszystko w fałszywej dystrybucji.

sylvainulg
źródło
To fajny pomysł, ale wydaje się nieprzewidywalnie obsługiwać dowiązania symboliczne. Mój ~/fake-distroużywa busyboksa, do którego prowadzi dowiązanie symboliczne ls, mvi innych popularnych narzędzi /bin/busybox. Jeśli wyraźnie dzwonię /bin/busybox mv ..., wszystko działa, ale jeśli dzwonię /bin/mv ..., dostaję sh: /bin/mv: not found. Ustawienie export FAKECHROOT_EXCLUDE_PATH=/przed uruchomieniem fakechroot naprawia ten objaw, ale potem psuje się na innych dowiązaniach symbolicznych (np /usr/bin/vim -> /usr/bin/vim.vim.).
Ponkadoodle,
może FAKECHROOT_EXCLUDE_PATH = /: / usr pomógłby wtedy?
sylvainulg,
1

Wydaje się, że dzięki przestrzeniom nazw użytkowników można w rzeczywistości chrootować bez rootowania. Oto przykładowy program, który pokazuje, że jest to możliwe. Dopiero zacząłem badać, jak działają przestrzenie nazw systemu Linux, więc nie jestem całkowicie pewien, czy ten kod jest najlepszą praktyką, czy nie.

Zapisz jako user_chroot.cc. Kompiluj z g++ -o user_chroot user_chroot.cc. Zastosowanie jest ./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;
    }
}

Przetestowałem to na minimalnych rootfsach generowanych przy pomocy multistrap (wykonywanych jako non-root). Niektóre pliki systemowe, takie jak /etc/passwdi /etc/groupszostały skopiowane z rootfów hosta do rootfów guest.

Cheshirekow
źródło
Nie Failed to unshare user namespacedziała dla mnie na Linuksie 4.12.10 (Arch Linux).
Ponkadoodle,
@wallacoloo może zmodyfikować printf () na perror () i zobaczyć, jaki był rzeczywisty błąd. sprawdź man7.org/linux/man-pages/man2/unshare.2.html, aby dowiedzieć się, jakie kody błędów mogą wynikać z nieudanego unsharepołączenia. Możesz także wypróbować tę wersję Pythona, która może mieć lepsze komunikaty o błędach: github.com/cheshirekow/uchroot
cheshirekow
1
Właściwie @wallacoloo to brzmi jak arch wyłącza nieuprzywilejowane przestrzenie nazw użytkowników w jego kompilacji jądra: lists.archlinux.org/pipermail/arch-general/2017- lutego /…
cheshirekow
0

Nie. Jeśli dobrze pamiętam, to chroot robi coś na poziomie jądra, co temu zapobiega. Nie pamiętam, co to było. Zbadałem to, gdy zadzierałem z narzędziem Catalyst Build Gentoo (a chroot w Gentoo jest taki sam jak chroot w Ubuntu). Choć byłoby to możliwe bez hasła ... takie rzeczy są pozostawione sferze potencjalnych luk w zabezpieczeniach i upewnienia się, że wiesz, co robisz.

ksenoterracid
źródło