在chroot环境中检测监狱的方法

22

如何在没有 root 权限的情况下检测是否处于 chroot 环境中?假设是标准的 BSD 或 Linux 系统。我想到的最好方法是查看“/”的 inode 值,并考虑它是否合理地较低,但我希望有一种更准确的检测方法。

[编辑 20080916 142430 EST] 仅仅查看文件系统不足以判断,因为很容易复制像 /boot 和 /dev 这样的文件夹来欺骗被禁闭的用户。

[编辑 20080916 142950 EST] 对于 Linux 系统,检查 /proc 中意外值是合理的,但是对于根本不支持 /proc 的系统呢?


3
另请参阅如何判断自己是否在chroot环境中运行? - Gilles 'SO- stop being evil'
1
虽然不完全可移植(而且只作为suid工作),但Debian系统默认安装ischroot。参见:https://manpages.debian.org/jessie/debianutils/ischroot.1.en.html - thom_nic
8个回答

13

如果 / 是 ext2/ext3/ext4 文件系统的根目录,则其对应的 inode 始终为 2,但您可能会被 chroot 在一个完整的文件系统中。如果只是 chroot(而不是其他虚拟化),您可以运行 mount 并将挂载的文件系统与您看到的文件系统进行比较。验证每个挂载点是否具有 inode 2。


8
出于好奇,inode 1 是什么? - Topaz
6
不良块(历史/遗留问题) - user10392
6
在Linux中,/sys和/proc都是inode == 1。devtmpfs是inode == 3。这是个很酷的技巧,但只在“真正”的文件系统上可靠。 - SpamapS
9
并非所有的文件系统都如此。例如,对于XFS文件系统而言,根目录对应的inode编号为128。 - caf
2
换句话说,root_inode=$(stat -c %i /); if [ $root_inode -ne 2 -a $root_inode -ne 128 ]; ... - l0b0
显示剩余3条评论

6
在具有root权限的Linux上,测试init进程的根目录是否为您的根目录。虽然/proc/1/root始终是指向/的符号链接,但跟随它会导致“主”根目录(假设init进程未chroot,但这几乎从不发生)。如果没有挂载/proc,则可以确定您处于chroot环境中。
[ "$(stat -c %d:%i /)" != "$(stat -c %d:%i /proc/1/root/.)" ]
# With ash/bash/ksh/zsh
! [ -x /proc/1/root/. ] || [ /proc/1/root/. -ef / ]

这比查看/proc/1/exe更精确,因为如果init自上次引导以来已经升级,或者chroot在主根文件系统上并且init在其中硬链接,则可能与chroot外的情况不同。
如果您没有root权限,可以查看/proc/1/mountinfo/proc/$$/mountinfo(在Linux内核文档的filesystems/proc.txt中有简要说明)。该文件是可被任何人读取的,并包含有关进程在文件系统中每个挂载点的大量信息。该文件中的路径受到读取进程所受影响的chroot的限制。如果读取/proc/1/mountinfo的进程被chroot到与全局根目录不同的文件系统中(假设pid 1的根目录是全局根目录),则/的条目不会出现在/proc/1/mountinfo中。如果读取/proc/1/mountinfo的进程被chroot到全局根文件系统上的某个目录,则/的条目将出现在/proc/1/mountinfo中,但具有不同的挂载ID。顺便提一下,根字段($4)指示chroot在其主文件系统中的位置。这仅适用于Linux。
[ "$(awk '$5=="/" {print $1}' </proc/1/mountinfo)" != "$(awk '$5=="/" {print $1}' </proc/$$/mountinfo)" ]

这大致就是 ischroot 的功能:https://sources.debian.org/src/debianutils/5.7-0.3/ischroot.c - Jérôme Pouiller

5
如果您不在chroot环境中且根文件系统为ext2/ext3/ext4,则/的inode始终为2。您可以使用以下命令来检查:
stat -c %i /

或者

ls -id /

很有趣,但让我们尝试找到chroot目录的路径。询问stat /位于哪个设备上:

stat -c %04D /

设备的第一个字节表示设备的主要版本,最后一个字节表示次要版本。例如,0802表示主要版本为8,次要版本为1。如果您在/dev中进行检查,您会看到该设备是/dev/sda2。如果您是root用户,您可以直接在chroot中创建相应的设备:

mknode /tmp/root_dev b 8 1

现在,让我们找到与我们的chroot相关联的inode。 debugfs允许使用inode号列出文件的内容。例如,ls -id /返回了923960:

sudo debugfs /tmp/root_dev -R 'ls <923960>'
 923960  (12) .       915821  (32) ..     5636100  (12) var   
5636319  (12) lib    5636322  (12) usr    5636345  (12) tmp   
5636346  (12) sys    5636347  (12) sbin   5636348  (12) run   
5636349  (12) root   5636350  (12) proc   5636351  (12) mnt   
5636352  (12) home   5636353  (12) dev    5636354  (12) boot   
5636355  (12) bin    5636356  (12) etc    5638152  (16) selinux   
5769366  (12) srv    5769367  (12) opt    5769375  (3832) media 

有趣的信息是 .. 目录项的 inode 编号: 915821。我可以查看它的内容:

sudo debugfs /tmp/root_dev -R 'ls <915821>'
915821  (12) .              2  (12) ..    923960  (20) debian-jail   
923961  (4052) other-jail  

目录名为debian-jail的inode为923960。因此我chroot目录的最后一个组成部分是debian-jail。现在让我们看一下父目录(inode 2):

sudo debugfs /tmp/root_dev -R 'ls <2>'
      2  (12) .           2  (12) ..          11  (20) lost+found    1046529  (12) home   
 130817  (12) etc    784897  (16) media     3603  (20) initrd.img   
 261633  (12) var    654081  (12) usr     392449  (12) sys            392450  (12) lib   
 784898  (12) root   915715  (12) sbin   1046530  (12) tmp   
1046531  (12) bin    784899  (12) dev     392451  (12) mnt   
 915716  (12) run        12  (12) proc   1046532  (12) boot               13  (16) lib64   
 784945  (12) srv    915821  (12) opt       3604  (3796) vmlinuz 

名为opt的目录具有inode 915821,inode 2是文件系统的根。所以我的chroot目录是/opt/debian-jail。当然,/dev/sda1可能已经挂载在另一个文件系统上。您需要检查一下(使用lsof或直接从/proc中获取信息)。


这不可靠的另一个原因是例如btrfs,其中文件层次结构的真正“/”可能仍然不是文件系统的根目录(而是它的子卷),然后具有其他inode号码。 - calestyo

4
在BSD系统上(使用uname -a命令检查),proc应该始终存在。检查/proc/1/exe的dev/inode对(使用stat命令在该路径上进行检查,它不会按照文本而是按照底层钩子跟随符号链接)是否与/sbin/init匹配。
检查根目录inode #2也是一个好方法。
在大多数其他系统上,root用户可以通过尝试fchdir root-breaking trick来更快地找到答案。如果它进入任何地方,则表示您处于chroot jail中。

+1 .. /proc/1/root 或 /proc/1/exe 的设备+节点是 Debian 和 Ubuntu 中几个程序用于确定它们是否在 chroot 中运行的方式。 - SpamapS
如果 /sbin/init 在 chroot 环境中被硬链接,则它将具有与正在运行的 init 相同的 dev/inode:误报。如果自系统引导以来升级了 /sbin/init,则它将具有不同的 dev/inode,即使在真正的根文件系统上也是如此:误报。 - caf
这里的假阴性要求根inode不是2。而假阳性则非常罕见。 - Joshua

4

防止这样的事情发生才是重点。如果你的代码应该在chroot中运行,请在启动时设置一个标志。如果你正在进行黑客攻击,请检查已知位置中的几个常见事物,在/etc中计算文件数量,或者在/dev中找到某些东西。


2

我希望能获取在FreeBSD上运行的jail的相同信息(因为Ansible似乎无法检测到这种情况)。

在FreeBSD 11的FreeNAS发行版中,/proc未挂载在主机上,但在jail中挂载。我不确定在常规的FreeBSD上是否也是如此,但procfs: Gone But Not Forgotten似乎表明是这样的。无论哪种方式,您可能都不想尝试挂载它来检测jail状态,因此我不确定它是否可用作可靠的jail预测器。

我还排除了在/上使用stat的方法,因为在FreeNAS上,所有jails都有自己的文件系统(即ZFS数据集),因此主机和jail中的/节点都具有inode 4。我认为这在FreeBSD 11中普遍存在。

因此,我采取的方法是在pid 0上使用procstat

[root@host ~]# procstat 0
  PID  PPID  PGID   SID  TSID THR LOGIN    WCHAN     EMUL          COMM        
    0     0     0     0     0 1234 -        swapin    -             kernel      
[root@host ~]# echo $?
0
[root@host ~]# jexec guest tcsh
root@guest:/ # procstat 0
procstat: sysctl(kern.proc): No such process
procstat: procstat_getprocs()
root@guest:/ # echo $?
1

我假设这里的pid 0始终是主机上的内核,而容器内部不会有一个pid 0。

2

我猜这取决于你为什么要进入chroot环境,以及是否有任何努力去掩盖它。

我建议检查/proc目录,这些文件是自动生成的系统信息文件。内核会在根文件系统中填充这些文件,但在chroot文件系统中可能不存在。

如果根文件系统中的/proc已经绑定到chroot中的/proc,则该信息与chroot环境之间可能存在一些差异。例如,请检查/proc/mounts文件。

同样地,请检查/sys目录。


虽然绑定/proc很容易,但是其中的数据差异会很难掩盖。答案已被接受。 - Topaz
抱歉,刚才说错了 - 那么对于那些一开始就没有/proc和相关系统的非Linux系统呢? - Topaz
1
问题假设使用标准的Linux或BSD系统。据我所知,两者都有/proc目录。 - SpoonMeiser

0

如果您使用schroot进入了chroot环境,则可以检查$debian_chroot的值。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接