เป็นไปได้หรือไม่ที่ผู้ใช้ที่ไม่ใช่รูทใช้กระบวนการ chroot บน Ubuntu?
เป็นไปได้หรือไม่ที่ผู้ใช้ที่ไม่ใช่รูทใช้กระบวนการ chroot บน Ubuntu?
คำตอบ:
บน Linux การเรียกระบบchroot (2)สามารถทำได้โดยกระบวนการที่ได้รับการยกเว้นเท่านั้น ความสามารถที่กระบวนการต้องการคือ CAP_SYS_CHROOT
เหตุผลที่คุณไม่สามารถ chroot เนื่องจากผู้ใช้นั้นค่อนข้างเรียบง่าย สมมติว่าคุณมีโปรแกรม setuid เช่น sudo ที่ตรวจสอบ / etc / sudoers หากคุณได้รับอนุญาตให้ทำอะไรบางอย่าง ตอนนี้ใส่ไว้ใน chroot chroot กับ / etc / sudoers ของคุณเอง ทันใดนั้นคุณมีการยกระดับสิทธิ์ทันที
เป็นไปได้ที่จะออกแบบโปรแกรมเพื่อ chroot ตัวเองและรันมันเป็นกระบวนการ setuid แต่โดยทั่วไปถือว่าเป็นการออกแบบที่ไม่ดี ความปลอดภัยเพิ่มเติมของ chroot ไม่ได้กระตุ้นให้เกิดปัญหาด้านความปลอดภัยกับ setuid
chroot
ภายหลัง
@ imz - ความเห็นของ IvanZakharyaschev เกี่ยวกับคำตอบของ pehrs ว่าอาจเป็นไปได้ด้วยการเปิดตัว namespaces แต่สิ่งนี้ยังไม่ได้รับการทดสอบและโพสต์เป็นคำตอบ ใช่มันทำให้ผู้ใช้ที่ไม่ใช่รูทสามารถใช้ 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 ผู้ใช้รากใน namespace ที่ถูกแมปไปที่ไม่ใช่รากนอก ID ผู้ใช้ของ namespace นั้นและในทางกลับกันซึ่งเป็นเหตุผลที่ไฟล์ระบบที่แสดงให้เห็นว่าเป็นเจ้าของโดยผู้ใช้ปัจจุบันเป็นเจ้าของโดยผู้ใช้ ID 0. ปกติls -al root
โดยไม่ต้องunshare
ไม่ แสดงให้พวกเขาเป็นเจ้าของโดยผู้ใช้ปัจจุบัน
หมายเหตุ: มันเป็นที่รู้จักกันดีว่ากระบวนการที่มีความสามารถในการใช้งานมีความสามารถในการทำลายออกของchroot
chroot
เนื่องจากunshare -r
จะให้chroot
สิทธิ์แก่ผู้ใช้ทั่วไปจึงเป็นความเสี่ยงด้านความปลอดภัยหากได้รับอนุญาตภายในchroot
สภาพแวดล้อม อันที่จริงมันไม่ได้รับอนุญาตและล้มเหลวด้วย:
ยกเลิกการแชร์: ยกเลิกการแชร์ไม่สำเร็จ: ไม่อนุญาตให้ดำเนินการ
ซึ่งตรงกับเอกสารunshare (2) :
EPERM (ตั้งแต่ Linux 3.9)
CLONE_NEWUSERถูกระบุในแฟล็กและผู้เรียกอยู่ในสภาพแวดล้อม chroot (เช่นไดเร็กทอรีรูทของผู้โทรไม่ตรงกับรูทไดเร็กทอรีของเมาต์เนมสเปซที่มันอยู่)
วันนี้คุณต้องการดู LXC (Linux Containers) แทน chroot / BSD jail มันอยู่ที่ไหนสักแห่งระหว่าง chroot และเครื่องเสมือนที่ให้การควบคุมความปลอดภัยจำนวนมากและการกำหนดค่าทั่วไป ฉันเชื่อว่าสิ่งที่คุณต้องใช้เพื่อดำเนินการในฐานะผู้ใช้คือการเป็นสมาชิกของกลุ่มที่เป็นเจ้าของไฟล์ / อุปกรณ์ที่จำเป็น แต่อาจมีความสามารถ / ระบบการอนุญาตที่เกี่ยวข้อง ไม่ว่าจะด้วยวิธีใดก็ควรเป็นไปได้มากเนื่องจาก LXC นั้นค่อนข้างเร็วหลังจาก SELinux เป็นต้นถูกเพิ่มเข้าไปในเคอร์เนล Linux
นอกจากนี้โปรดทราบว่าคุณสามารถเขียนสคริปต์เป็น root แต่ให้สิทธิ์ผู้ใช้ที่ปลอดภัยในการเรียกใช้สคริปต์เหล่านั้น (โดยไม่ต้องใช้รหัสผ่านหากคุณต้องการ แต่ให้แน่ใจว่าสคริปต์นั้นปลอดภัย) โดยใช้ sudo
การรวมกันของ fakeroot / fakechroot ให้เสมือนจริงของ chroot สำหรับความต้องการง่ายๆเช่นการสร้างคลังเก็บ tar ที่ไฟล์ดูเหมือนว่าจะเป็นเจ้าของโดยราก Fakechroot manpage เป็นhttp://linux.die.net/man/1/fakechroot
คุณไม่ได้รับอนุญาตใหม่ แต่ถ้าคุณเป็นเจ้าของไดเรกทอรี (เช่นปลอม distro) ก่อนที่จะเรียกใช้
fakechroot fakeroot chroot ~/fake-distro some-command
ตอนนี้ให้มองหาคำสั่งบางอย่างเช่นคุณหยั่งรากและเป็นเจ้าของทุกสิ่งภายในโรงกลั่นน้ำมันปลอม
~/fake-distro
ใช้ busybox ซึ่ง symlinks ls
, mv
และระบบสาธารณูปโภคอื่น ๆ /bin/busybox
ทั่วไปที่จะ ถ้าผมชัดเจนโทร/bin/busybox mv ...
, สิ่งที่ทำงาน แต่ถ้าผมเรียกฉันได้รับ/bin/mv ...
sh: /bin/mv: not found
การตั้งค่าexport FAKECHROOT_EXCLUDE_PATH=/
ก่อนใช้งานการปลอมแปลงรากเทียมจะแก้ไขอาการที่เกิดขึ้น แต่หลังจากนั้นจะหยุดลงบน symlink อื่น ๆ (เช่น/usr/bin/vim -> /usr/bin/vim.vim
)
ดูเหมือนว่าด้วย user-namespaces ในความเป็นจริงเป็นไปได้ที่จะ 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 น้อยที่สุดที่สร้างขึ้นด้วย multistrap (ดำเนินการในฐานะที่ไม่ใช่ราก) ไฟล์ระบบบางไฟล์เช่น/etc/passwd
และ/etc/groups
ถูกคัดลอกจากโฮสต์ rootfs ลงใน guest rootfs
Failed to unshare user namespace
สำหรับฉันที่ linux 4.12.10 (Arch Linux)
unshare
โทรที่ไม่สำเร็จ คุณสามารถลองใช้งานไพ ธ อนรุ่นนี้ซึ่งอาจมีข้อผิดพลาดในการส่งข้อความที่ดีกว่า: github.com/cheshirekow/uchroot
ไม่ถ้าฉันจำได้อย่างถูกต้องมีบางสิ่งในระดับเคอร์เนลที่ chroot ทำเพื่อป้องกัน ฉันจำไม่ได้ว่ามันคืออะไร ฉันตรวจสอบมันกลับมาเมื่อทำ messing ด้วยเครื่องมือ Catalyst Build ของ Gentoo (และ chroot บน gentoo นั้นเหมือนกับ chroot บน Ubuntu) แม้ว่ามันจะเป็นไปได้ที่จะทำให้มันเกิดขึ้นโดยไม่ต้องใช้รหัสผ่าน ... แต่สิ่งต่าง ๆ เหล่านี้อยู่ในขอบเขตของความเสี่ยงด้านความปลอดภัยที่อาจเกิดขึ้นและทำให้แน่ใจว่าคุณรู้ว่าคุณกำลังทำอะไรอยู่