루트가 아닌 사용자가 Ubuntu에서 chroot 프로세스를 실행할 수 있습니까?
루트가 아닌 사용자가 Ubuntu에서 chroot 프로세스를 실행할 수 있습니까?
답변:
Linux에서 chroot (2) 시스템 호출은 권한있는 프로세스에 의해서만 수행 될 수 있습니다. 프로세스에 필요한 기능은 CAP_SYS_CHROOT입니다.
사용자로서 chroot 할 수없는 이유는 매우 간단합니다. sudo와 같은 setuid 프로그램이 있다고 가정하면 / etc / sudoers를 검사하여 무언가를 할 수 있는지 확인하십시오. 이제 자신의 / etc / sudoers와 함께 chroot chroot에 넣습니다. 갑자기 즉시 권한 상승이 있습니다.
chroot 자체로 프로그램을 디자인하고 setuid 프로세스로 실행할 수 있지만 일반적으로 잘못된 디자인으로 간주됩니다. chroot의 추가 보안은 setuid의 보안 문제를 유발하지 않습니다.
chroot
.
@ imz--IvanZakharyaschev는 네임 스페이스를 도입하여 가능할 수 있다는 pehrs의 답변에 대해 언급하지만, 테스트 및 답변으로 게시되지 않았습니다. 그렇습니다. 루트 사용자가 아닌 사용자도 chroot를 사용할 수 있습니다.
정적으로 링크 dash
되고 정적으로 링크 되고 루트가 아닌 busybox
것으로 실행중인 bash
쉘이 있습니다.
$ 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
네임 스페이스의 루트 사용자 ID는 해당 네임 스페이스의 루트가 아닌 사용자 ID를 외부로 매핑하고, 사용자 ID가 0 정기 소유로 현재 사용자가 소유 한 시스템 프로그램 파일을 왜 반대 부사장, ls -al root
하지 않고는 unshare
,하지 현재 사용자가 소유 한 것으로 표시합니다.
참고 :을 사용할 수있는 프로세스 chroot
는을 (를) 중단 할 수 있는 것으로 잘 알려져 chroot
있습니다. 일반 사용자 unshare -r
에게 chroot
권한을 부여 하므로 chroot
환경 내에서 허용되는 경우 보안 위험이 있습니다. 실제로 허용되지 않으며 다음과 같이 실패합니다.
공유 해제 : 공유 해제 실패 : 작업이 허용되지 않습니다
unshare (2) 문서 와 일치합니다 :
EPERM (Linux 3.9부터)
CLONE_NEWUSER 가 플래그 로 지정되었고 호출자가 chroot 환경에 있습니다 (즉, 호출자의 루트 디렉토리가있는 마운트 네임 스페이스의 루트 디렉토리와 일치하지 않습니다).
요즘 chroot / BSD jail 대신 LXC (Linux Containers)를보고 싶을 것입니다. chroot와 가상 머신 사이에있어 많은 보안 제어 및 일반 구성 기능을 제공합니다. 사용자로서 필요한 모든 파일 / 장치를 소유 한 그룹의 구성원이어야한다고 생각하지만 기능 / 시스템 권한도 관련 될 수 있습니다. 어느 쪽이든, SELinux 등이 Linux 커널에 추가 된 지 얼마되지 않아 LXC가 최신 버전이므로 매우 가능해야합니다.
또한 스크립트를 루트로 작성할 수 있지만 sudo를 사용하여 원하는 경우 암호없이 스크립트를 실행할 수있는 보안 권한을 사용자에게 부여 할 수 있습니다 (암호는 필요하지만 스크립트는 안전한지 확인하십시오).
fakeroot / fakechroot의 조합은 루트가 파일을 소유 한 것처럼 보이는 tar 아카이브를 생성하는 것과 같은 간단한 요구에 대한 비슷한 chroot를 제공합니다. Fakechroot 맨 페이지는 http://linux.die.net/man/1/fakechroot 입니다.
새로운 권한은 없지만 호출하기 전에 디렉토리 (예 : 가짜 디스트로)를 소유 한 경우
fakechroot fakeroot chroot ~/fake-distro some-command
그것은 이제 당신이 root와 같은 명령을 찾고 fake-distro 내의 모든 것을 소유합니다.
~/fake-distro
용도에 비지 박스, 심볼릭 링크 ls
, mv
그리고 다른 일반적인 유틸리티 /bin/busybox
. 명시 적으로 전화 /bin/busybox mv ...
하면 문제가 발생하지만 전화 /bin/mv ...
하면을 얻습니다 sh: /bin/mv: not found
. export FAKECHROOT_EXCLUDE_PATH=/
fakechroot를 실행 하기 전에 설정하면 해당 증상이 해결되지만 다른 심볼릭 링크 (예 :)에서는 끊어집니다 /usr/bin/vim -> /usr/bin/vim.vim
.
사용자 네임 스페이스를 사용하면 실제로 루트없이 chroot하는 것이 가능합니다. 다음은 가능함을 보여주는 예제 프로그램입니다. 나는 리눅스 네임 스페이스가 어떻게 작동하는지 탐구하기 시작했을 뿐이 므로이 코드가 모범 사례인지 확실하지 않습니다.
다른 이름으로 저장하십시오 user_chroot.cc
. 로 컴파일하십시오 g++ -o user_chroot user_chroot.cc
. 사용법은 ./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;
}
}
멀티 스트랩 (루트가 아닌 것으로 실행)으로 생성 된 최소 rootfs에서 이것을 테스트했습니다. 일부 시스템 파일을 좋아 /etc/passwd
하고 /etc/groups
게스트 rootfs에 호스트 rootfs에서 복사되었습니다.
Failed to unshare user namespace
Linux 4.12.10 (Arch Linux) 에서 나를 위해 실패 합니다.
unshare
. : 당신이 더 나은 오류 메시지가있을 수 있습니다 파이썬 버전을 시도 할 수 있습니다 github.com/cheshirekow/uchroot
아니요. 올바르게 기억하면 chroot가 수행하는 커널 수준의 일이있어이를 막을 수 있습니다. 그게 뭔지 기억 나지 않습니다. 젠투의 Catalyst Build 도구를 망칠 때 다시 조사했습니다 (그리고 젠투의 chroot는 우분투의 chroot와 동일합니다). 비밀스러운 일없이 일어날 수는 있지만, 그런 일은 잠재적 인 보안 취약점의 영역에 맡겨져 있으며 자신이 무엇을하고 있는지를 확인해야합니다.