Czy użytkownik inny niż root może uruchomić proces chroot na Ubuntu?
Czy użytkownik inny niż root może uruchomić proces chroot na Ubuntu?
Odpowiedzi:
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.
chroot
tego.
@ 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 dash
i statycznie połączony busybox
oraz działającą bash
powł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 -r
przyznałby chroot
uprawnienia 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).
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.
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.
~/fake-distro
używa busyboksa, do którego prowadzi dowiązanie symboliczne ls
, mv
i 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
.).
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/passwd
i /etc/groups
zostały skopiowane z rootfów hosta do rootfów guest.
Failed to unshare user namespace
działa dla mnie na Linuksie 4.12.10 (Arch Linux).
unshare
połączenia. Możesz także wypróbować tę wersję Pythona, która może mieć lepsze komunikaty o błędach: github.com/cheshirekow/uchroot
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.