There is a chroot environment in
/var/myroot, and an attacker has obtained arbitrary machine code execution in a process running as root (EUID 0) in the chroot. But the processes under control of the attacker don't have all capabilities enabled (just filesystem capabilities). The attacker wants to escape the chroot, and append a line to
/etc/passwd outside the chroot. How can he do it?
The following security measures have been set up:
- To prevent the chdir("..") chroot escape technique, the chroot environment was entered using pivot_root(2) rather than chroot(2). See in jchroot.c how it can be done.
- When the first process in the chroot was started, it didn't have any file descriptors open pointing outside the chroot.
- Each process in the chroot has at most
CAP_SETUIDcapabilities and is not able to gain other ones. In short, the attacker is able to make arbitrary filesystem reads and writes, bypassing permission checks etc., but he is not able to send arbitrary signals to processes (
CAP_KILL) or send arbitrary packets on the network (
CAP_NET_RAW) or reboot the system (
CAP_SYS_BOOT) or modify arbitrary bytes in memory (
unshare(CLONE_NEWUSER)was not called, the UID 0 of the chroot process is the same as UID 0 outside the chroot.
unshare(CLONE_NEWPID)was called, so the attacker doesn't see processes running outside the chroot.
unshare(CLONE_NEWNS)was called when setting up the chroot, and the following filesystems are visible:
/var/chrootis visible as
/, remounted with
MS_NODEVis used so that the attacker can't write to
MS_NOSUIDis used so that the attacker can't gain new capabilities from file capabilities.)
- A proc filesystem is visible as
/proc, with the following paths removed (by putting an empty file there using a bind-mount):
/proc/scsi, and the following paths made read-only:
- A sysfs filesystem is not mounted.
- A devpts filesystem is not mounted.
- A tmpfs filesystem is mounted as
MS_NODEV, prepopulated with a few devices.
- No other filesystems are visible from the chroot.
- Block device nodes are not available in the chroot (and
CAP_MKNODis not available, so the attacker is not able to create them).
- Only the following character device nodes are available:
/dev/pts/ptmx) and a
/dev/pts/X, the terminal which was used outside the chroot.
- If the attacker calls
ioctl(..., TIOCSTI, ...)(simulate typed input) on
/dev/pts/X, and exits the chroot, probably an interactive shell outside the chroot will read those simulated bytes, so simulating this can be useful:
sudo sh -c 'echo pwned::0:0:pwned:/:/bin/bash >>/etc/passwd'. To prevent this from succeeding, the parent process which created the processes in the chroot will flush all terminal input before returning to the shell.
FYI My use case is the following: there is a Debian system in
/var/myroot (possibly created by debootstrap), and I'd like to be able to install untrusted packages there without exposing the host system to attacks by install scripts in malicious packages. Unfortunately
sudo chroot /var/myroot apt-get install MALICIOUS-PACKAGE is not secure enough, because e.g. the install script of the package can create the block device node
/dev/sda1, find the
/etc/passwd file there and modify it, thus potentially escaping from the chroot. I'm now exploring what other options are secure enough, and a hardened chroot as described above is one of the candidates. (In this question I'm not looking for other candidates.) In this question I'd like to understand how secure it is.
FYI There is a command-line tool chw00t to escape from chroot. About its techniques:
- -0 does not work here because pivot_root(2) was used.
- -1 does not work because there are no file descriptors pointing to outside the chroot available.
- -2 may work, I need to check if it works with pivot_root(2).
- -3 does not work because unshare(CLONE_NEWPID) was called.
- -4 does not work because block devices are not available.
- -5 may work, I need to check if it works with pivot_root(2).
- -6 does not work because unshare(CLONE_NEWPID) was called.
- -7 does not work because there are no file descriptors pointing to outside the chroot available.