从内部探测chroot监狱

时间:2008-09-16 18:04:42

标签: linux unix posix bsd chroot

如何在没有root权限的情况下检测到chroot jail?假设标准的BSD或Linux系统。我想出的最好的方法是查看“/”的inode值并考虑它是否相当低,但我想要一种更准确的检测方法。

[edit 20080916 142430 EST]仅仅查看文件系统是不够的,因为复制诸如/ boot和/ dev之类的东西来欺骗被监禁的用户并不困难。

[edit 20080916 142950 EST]对于Linux系统,在/ proc中检查意外值是合理的,但是那些首先不支持/ proc的系统呢?

8 个答案:

答案 0 :(得分:14)

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

答案 1 :(得分:5)

如果您不在chroot中,/的inode将始终为2.您可以使用

检查
stat -c %i /

ls -id /

Interresting,但让我们尝试找到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)。

答案 2 :(得分:4)

在具有root权限的Linux上,测试init进程的根目录是否是您的根目录。虽然/proc/1/root始终是/的符号链接,但它会导致“主”根目录(假设init进程不是chrooted,但几乎没有完成)。如果没有安装/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 / ]

这比looking at /proc/1/exe更精确,因为如果自上次启动后init已升级,或者如果chroot位于主根文件系统init上,那么在chroot之外可能会有所不同很难相关。

如果您没有root权限,可以查看/proc/1/mountinfo/proc/$$/mountinfo(简要记录在filesystems/proc.txt in the Linux kernel documentation中)。此文件是世界可读的,并且包含有关文件系统进程视图中每个安装点的大量信息。该文件中的路径受影响读取器进程的chroot限制(如果有)。如果读取/proc/1/mountinfo的进程被chroot到与全局根不同的文件系统中(假设pid 1的根是全局根),则/中不会出现/proc/1/mountinfo的条目。如果读取/proc/1/mountinfo的进程被chroot到全局根文件系统上的目录,则/中的/proc/1/mountinfo条目将出现在$4中,但具有不同的装入ID。顺便提一下,根字段([ "$(awk '$5=="/" {print $1}' </proc/1/mountinfo)" != "$(awk '$5=="/" {print $1}' </proc/$$/mountinfo)" ] )表示chroot在其主文件系统中的位置。同样,这是Linux特有的。

{{1}}

答案 3 :(得分:3)

防止这样的事情是重点。如果你的代码应该在chroot中运行,那么在启动时设置一个标志。如果你是黑客,黑客:检查已知位置的几个常见事物,计算/ etc中的文件,/ dev中的文件。

答案 4 :(得分:3)

在BSD系统上(使用uname -a检查),proc应始终存在。检查/ proc / 1 / exe的dev / inode对(使用该路径上的stat,它不会通过文本跟踪符号链接而是通过底层钩子)匹配/ sbin / init。

检查inode#2的根也是一个很好的。

在大多数其他系统上,root用户可以通过尝试fchdir root-breaking技巧找到更快的速度。如果它到了你在chroot监狱的任何地方。

答案 5 :(得分:1)

我想这取决于你为什么会在chroot,以及是否有任何努力伪装它。

我检查/ proc,这些文件是自动生成的系统信息文件。内核将在根文件系统中填充它们,但它们可能不存在于chroot文件系统中。

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

同样地,检查/ sys。

答案 6 :(得分:0)

如果您使用schroot进入chroot,那么您可以检查$ debian_chroot的值。

答案 7 :(得分:0)

我想在FreeBSD上运行jail的相同信息(因为Ansible似乎没有检测到这种情况)。

在FreeBSD 11的FreeNAS发行版中,/proc未安装在主机上,但它位于jail中。这对于常规的FreeBSD是否也是如此,我不确定,但procfs: Gone But Not Forgotten似乎暗示它是。无论哪种方式,你可能都不想尝试安装它只是为了检测监狱状态,因此我不确定它是否可以被用作在监狱内的可靠预测器。

我还排除在/上使用stat当然在FreeNAS上所有jail都有自己的文件系统(即a ZFS dataset),因此主机上的/节点和监狱都有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将永远是主机上的内核,并且jail中不会有pid。